Commit graph CultLib/docs
Author SHA1 Message Date
Meta Vens
979fa42fb2 Record variant fork 1: stable element ids everywhere
Some checks failed
CultMesh portability and performance / ubuntu-latest one-command multiplayer onboarding (push) Has been cancelled
CultMesh portability and performance / windows-latest one-command multiplayer onboarding (push) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (push) Has been cancelled
CultMesh portability and performance / windows-latest reactive semantics and leases (push) Has been cancelled
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 13:02:11 +02:00
Meta Vens
1cf44e630a Record variant forks 2 and 6: resolve at load, same concrete type
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 12:57:08 +02:00
Meta Vens
c901d58824 Record the operator's rulings on variant forks 1, 3, 4, 5 and 7
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 12:52:48 +02:00
Meta Vens
8d1bb025d4 Write the CultCache document variants target
Operator rulings: variants are a CultCache feature, stored as a delta from a
base and resolved by the cache. Ends, invariants and open forks for the
Imagination pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 12:43:26 +02:00
Meta Vens
367c9bc2b8 Record the pass that beat the bands with a clamp
No constant sits in both bands, which is true and is not the rule. A wait that
caps itself at a second passes every scenario, and capping a wait so shutdown
gets noticed is the most ordinary way that line will ever be written. An offset
and a scale survive beside it.

A fresh Windows clone also cannot run the documented Linux path at all, because
nothing tells git to leave shell scripts alone and the container dies on a
carriage return in the interpreter line. The mount fix works; this sat behind
it.

The equivalence holds, but on two premises nobody had written down, and
narrowing both wakes survives while being equivalent to nothing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 02:36:37 +02:00
Meta Vens
1845301f91 Record the batch that made the timeout observable
The blind spot was not where the hold sat. No scenario ever let a timeout
finish a poll, because both ended their waits with a close, so the duration
governed nothing anyone could see. A scenario that polls an idle runtime and
measures elapsed against what it asked kills all three constants, and it asks
twice at values whose bands do not overlap, because one value cannot tell a
bridge honouring the host from one waiting on that same number of its own.

The probe that reached the two-phase poll through a closed port is committed,
the wake finally has the entry the table had been claiming, and a surviving
mutant is argued equivalent and handed to Soul rather than swapped for an
easier one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 02:12:12 +02:00
Meta Vens
122c2172d9 Rule the reference check onto read now and write later
A reference whose target contradicts its declaration is noticed on read in this
cut and refused by name. Writing the same check into the put path is intended
rather than optional: the declaration already names the target and the writer
already holds the record, so it is cheap, and leaving it to consumers means
every tool that writes records reimplements it and a tool that forgets looks
exactly like one that did not until something refuses.

The consumer story rests on less than it sounds. There is no Studio repository
and no project by that name; the tooling that enforces this today is one
console project in one game. That makes now the cheapest moment to move the
rule to its owner.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 01:44:09 +02:00
Meta Vens
2df124e269 Name what the generator needs before it can exist
A generator runs against published schemas, and the published schema entry is
flat: the cache walks the base types to collect members and then throws the
hierarchy away. Fed that, a generator emits one flat class per leaf with the
inherited members copied into each, which is the opposite of building the
hierarchy up for you.

So the catalog carrying each leaf's base chain is a prerequisite of that
campaign rather than a nicety for naming families, and families fall out of it
once it exists. The campaign itself waits until this cut settles the shape it
would be generating against. No generator exists in the repository today.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 01:38:24 +02:00
Meta Vens
34df099e8c Rule the cross product, and park families for the right reason
A caller needing exact pairs asks once per schema. The limit is stated rather
than answered with a third addressing list.

Naming a family is parked, but not because there is nothing to name. In one
process a family is an assignability check; over the wire there is no type
system, and nothing publishes the hierarchy where a caller can see it. The fix
is a catalog entry naming each leaf's base chain, which is small work that
moves the catalog's shape, so it belongs in a cut already touching it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 01:30:45 +02:00
Meta Vens
6e4b9e7eb4 Rule numbers onto decimal strings
Floats are fragile, and every value in this vocabulary is already a string, so
decimal strings keep the wire to one value encoding rather than adding a
second. The recommendation this reverses had that backwards.

What it costs is a comparison rule, and that is where the danger sits: compared
as text, ten is less than nine. The cut owes a canonical decimal form and a
numeric comparison, both pinned, and it no longer owes anyone a sentence about
where exactness runs out.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 01:23:44 +02:00
Meta Vens
fa6c000e7f Record the pass where the verdict splits
A stranger can now rerun both targets from the committed container and the
README, which was the batch's point and holds. The rules are another matter.
The scenario holds its callers after the wait whose duration is the rule, so
a hard-coded two seconds walks through the whole matrix while the committed
entry only ever died because one constant was smaller than another.

The gap recorded as unreachable is reachable in fifteen lines against a closed
port, and the mutant crashes a plain optimised build on contact. Second gap
falsified today. The next batch fixes the cause once instead of adding another
entry at another constant.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 01:19:02 +02:00
Meta Vens
47618428a3 Close three questions the map still lists as open
The operator ruled ordinals, the two deletions and the leaf titles earlier
today, in the other campaign's map. This one still carried them as open, and
a stale live question is exactly what a later agent reads as a decision still
to make.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 01:13:41 +02:00
Meta Vens
ee91062cee Finish the selection map, and price it honestly
The cache already declares and persists what type each member is, so numbers
cost no migration. What they do cost is a public way to read a declared value
at all, because the evaluator today cannot reach one from outside the cache,
which is why the existing snapshot loop reflects. That is a hundred and fifty
lines, not sixty, and the ledger moves the wrong way to say so.

Three claims inherited from the earlier pass were wrong and were cut rather
than designed around. A fifth selector engine turned up in Rust. And the
cache's index maps keep one key per value, so an evaluator that reached for
them would answer a query about a whole family with a single row.

Watching a selection is mapped as its own cut, where nine overloads that are
a query language in disguise collapse into one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 01:13:08 +02:00
Meta Vens
211b5e320f Point the Linux recipe at the container that exists
The map carried a one-line invocation that installed no JavaScript runtime,
so it could not run the mutation runner, and said nothing about disabling
randomisation or relaxing seccomp. That is how the Linux path came to be red
for everyone except the agent that had found the flags by hand. The recipe now
lives with the image and the bridge README, and the map points at them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 00:48:50 +02:00
Meta Vens
c2c07605d8 Map the selection cut for CultNet's database organ
Three selector engines evaluate the same two allowlists today, two of them
carrying identical copies of the same reflection, and projection is a delegate
no production code ever constructs. The map replaces all of it with one
selection a caller can state: any-of over the aliases the cache already
declares, a projection it asks for, an order, a cursor, and one hop along a
declared reference.

The audit is reported as measured rather than as hoped. About 326 of 21,720
lines collapse in CultMesh, and the repository grows by about 370, because the
Rust runtime gains a capability it never had.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 00:36:44 +02:00
Meta Vens
51fb449b56 Record the second fix batch and the harness that was never there
The lifetime fix holds under a thread sanitizer and the assertion kills the
deleted wait on both targets. The harness defending all of it does not hold.
Every native kill this cut had reported came from scratchpads that no longer
exist, the committed Linux path dies before its scenario starts and hides the
reason, and the scenario stays green when calls are not counted at all or
when nothing ever parks.

Two rules are defended by nothing committed. They are recorded as undefended
rather than given a number that would look better.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 00:02:05 +02:00
Meta Vens
27ae3cb292 Record Soul's second pass, and rule the surviving mutation killable
The cut does not close. The lifetime model was right in shape and wrong by
one line: the last call notifies after it has released the lock, so the
runtime can be destroyed in between and the wake lands on freed memory. A
sanitizer found it on the unmutated bridge.

The mutation that survived by construction is ruled killable rather than
accepted. Under a sanitizer with pollers blocked mid-copy it fails four times
in forty-eight, so a dev-only assertion makes it fail every time instead. Two
further mutations are honest only on the sanitizer target and the table must
say so, because a mutation whose kill depends on the target is not killed
until it runs there.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 22:58:15 +02:00
Meta Vens
e1ce4915b6 Record the Cut 3 fix batch
The bridge keeps an object alive across the call that names it, closes
each handle exactly once, and quiesces before it frees. The contract is a
header hosts and tests are checked against. Return codes are negative on
every platform, one completion per frame, and every connection's end is
observable. One mutation survived by construction and is handed to Soul
to rule on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 22:24:51 +02:00
Meta Vens
7badce1e4e Record Soul's Cut 3 pass
The bridge's lifetimes are wrong: a lookup hands the host a pointer the
worker can free before the next call. Release crashes on both platforms
under an ordinary stream teardown. Three ABI gaps ride with it, and the
return-code contract inverts between Windows and POSIX. One digest in
this map was the zip's, not the DLL's. All in a fix batch before Cut 4.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 21:34:24 +02:00
Meta Vens
27446e7761 Rule Q9: pin the OpenSSL MsQuic on Windows
One credential type on both platforms, the provider role works, the ABI
is unchanged. The tree pays four megabytes more and the Unity plugin's
copy diverges until its rebuild. The map's claim that PKCS12 was one type
for both providers is withdrawn.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 21:29:57 +02:00
Meta Vens
aa22b6141a Record the Cut 2 fixes and Cut 3's landing, and raise Q9
The bridge is a runtime-neutral two-role event queue, built and smoked
on both platforms with the Linux artifact named as development-loop only.
Two hangs the old shape never exercised are pinned. One fork stops the
Windows provider: the pinned Schannel flavour does not implement the
PKCS12 credential the spec assumed was one type everywhere, while the
same bridge passes beside the OpenSSL flavour. Recommended: pin OpenSSL
on Windows and pay the tree size.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 21:07:55 +02:00
Meta Vens
343dffc1de Record Soul's Cut 2 pass and correct one attribution
Byte parity held both ways under Soul's own frames. Three small things
did not: a mutant declared equivalent was not, the payload copy is a view
for a Node buffer, and the frame parity has no CI executor. The breakage
of the aggregate scripts dates from the scoped rename, not the version
bump this map first named.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 19:58:50 +02:00
Meta Vens
fef767d34a Record Cut 2's landing
The frame codec exists with parity proven both ways from its first
commit, and its test found a real divergence before any consumer could:
the JavaScript decoder deletes a leading byte-order mark the .NET decoder
keeps. Two housekeeping rulings taken: the aggregate TypeScript scripts
have been broken by a rename for two days and get their one-word fix, and
the mutation runner is renamed for what it now covers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 19:24:11 +02:00
Meta Vens
565ce79a4a Close Cut 1 and start Cut 2
Three Soul passes and three fix batches leave one verifier whose rules
match the C# reference as executed, parity pinned both ways and run in
CI on both operating systems. Three residuals ride with Cut 2. Two
statements this map made about its own batch were overstated and are
corrected: the NUL byte never caused a rewrite, and CI was not green
throughout.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 18:21:52 +02:00
Meta Vens
74fee16003 Record the Cut 1 edge-alignment batch
TypeScript now cleans a route the way the C# constructors do, reads
whitespace with C#'s alphabet, refuses the endpoint spellings the URL
parser would otherwise repair, and names the two signature refusals as
C# names them. Every probe reruns with zero reachable disagreements. Two
scars kept for the postmortem: a sidecar that reverted fixes it was meant
to protect, and a NUL byte that made git read source as binary.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 17:51:25 +02:00
Meta Vens
b7bb483989 Record Soul's second Cut 1 pass
The cut closes on its invariants. What is left is the gap between the C#
rules as written and as executed: the route is cleaned before the
transcript on one side and transcribed raw on the other, whitespace and
loopback are decided by different alphabets at the edges, and the browser
guard is enforced by name only. All in a final Hands batch before Cut 4
makes a TypeScript signer real.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 17:02:03 +02:00
Meta Vens
04087c6ab6 Record the browser session alignment and widen the name grep
The browser's local-development short-circuit reads "unsigned" through the
shared predicate, so the two TypeScript sides cannot disagree with each
other or with C#. The negative grep now names the two functions the fix
batch added. The generated contracts file's line-ending churn is recorded
where unassigned findings live.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 16:45:00 +02:00
Meta Vens
e3f56c183f Record the Cut 1 fix batch
Both parity directions are now pinned in the repo and run in CI, the
public verifier copies its bytes, and the four edge rules match the C#
reference, with the loopback set probed rather than assumed. One scar: the
runner's multi-line anchors had never matched on a CRLF checkout, so two
earlier kill claims rested on an LF-on-disk state. One browser-side
divergence remains and is in Hands.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 16:37:04 +02:00
Meta Vens
c00bed8575 Record Soul's Cut 1 pass
The verifier is sound in both directions, the second one by probe. What
can go wrong silently is the verification story: a mutant left compiled
in an ignored directory, a C# vector check with no CI owner, a public
function that reads a pooled buffer wrong, and four edge rules that drift
from the reference. One map claim about error texts is withdrawn.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 16:19:46 +02:00
Meta Vens
737e13286b Record Cut 1's landing
One route verifier in cultnet-ts, the browser copy deleted, a C#-written
vector file, and a mutation runner with a control. Soul is on it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 16:01:46 +02:00
Meta Vens
1c12136872 Rule Q8: the native binaries are committed
The deploy tarball is a git archive, so committed files are the only ones
that reach Yggdrasil without a second mechanism, and the Windows pair is
already committed for Unity. Four binaries, about eight megabytes, with a
manifest and digests beside them. No operator question is open on this map.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 15:57:33 +02:00
Meta Vens
4a2fdafa61 Remap Cut 6 under C: binaries in the tree, a release workflow, no registry
The deploy tarball is a git archive of two package directories, so only
committed files reach Yggdrasil and cultmesh-ts does not ride at all
today. Under C the binding resolves binaries from an environment variable
or the package's own native directory, a workflow builds the Linux artifact
in a debian:13 container and attaches it to a release with a manifest and
digests, and the operator smoke ships its own archive. Registry publication
is parked with its seam named. One question remains: whether the four
binaries are committed or fetched at deploy time.

The corrected npm premise is recorded in the operator's words: reachable,
publication deferred by choice.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 15:28:31 +02:00
Meta Vens
8d8ad568aa Re-rule Q5 to C: no registry, because npmjs is unreachable here
Ruling A assumed a publish job whose token is minted by logging in to
npmjs.com, and the operator's subnet is blocked there. That is also why the
existing cultcache-ts publish job has never run. Consumers keep file: paths;
the binaries ship in the CultLib tree the deploy path carries; the Actions
build attaches the Linux artifact to a release. Cut 6 and the lines of Cuts
4 and 7 that assumed a registry are flagged for remapping.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 15:12:08 +02:00
Meta Vens
3c29fc934d Record the Q5, Q6 and Q7 rulings in the QUIC cut map
All three recommendations were taken: unscoped cultnet-ts and cultmesh-ts
with only the native platform packages scoped; the Linux artifact built by
GitHub Actions in a debian:13 container and smoked on Yggdrasil; the lookup
source port plus a static source now, with the Node Odin rendezvous parked.

The status header now says no operator question is open and cut 1 has not
started, so a reader of the header alone knows where the campaign stands.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 13:35:11 +02:00
Meta Vens
bf9f6f7874 Map the TypeScript QUIC realtime plane migration
Seven cuts against main at f2cd2eb4, with the largest liability priced first
rather than discovered later. The native binding was the open question: a probe
loaded the committed msquic.dll through koffi under Node 24, drove a handshake
on MsQuic's own threads and closed cleanly, with no addon build and no toolchain
at load time. It is one cut, not the campaign.

The consumer audit found no package at zero external consumers and every
external consumer on a file: path rather than the registry, which is why
registry naming is an operator question rather than an assumption.

Two corrections against the target are recorded in the map rather than absorbed
silently: a cited transport filename that does not exist under that name, and a
registry path the target assumes for cultmesh-ts that has never existed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 13:16:56 +02:00
Meta Vens
f2cd2eb464 Add the TypeScript QUIC realtime plane migration target
Eureka target for giving cultmesh-ts a QUIC realtime provider and consumer,
byte-compatible with GameCult.Mesh.Quic and the Unity native MsQuic connector.
First consumer: the StreamPixels service publishing to its Unity overlay.

Operator rulings 2026-09-16: overlay character, subathon window and scene
intents travel as QUIC state frames and the costume catalog as an HTTPS
content artifact; shared TypeScript route verification moves to a
browser-safe module; Windows x64 and Linux x64 only; datagrams out of scope.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 20:02:33 +02:00
Meta Vens
ae194d5eb2 Release CultLib Unity 1.0.57 with deterministic plugin assemblies
Some checks failed
Publish packages / cultcache-py to PyPI (push) Has been cancelled
Publish packages / cultmesh-py to PyPI (push) Has been cancelled
Publish packages / cultnet-py to PyPI (push) Has been cancelled
Publish packages / @gamecult/cultcache-ts to npm (push) Has been cancelled
Bumps org.gamecult.cultlib to 1.0.57 and rebuilds its managed plugins from
main, so the Unity package carries the store-routing CultCache (one home
store per type, AddBackingStore(CacheBackingStore, Type[]), atomic commit)
instead of the Sep 3 assemblies. Install docs point at the new tag.

The build script now publishes without Source Link or the source revision,
with CI path mapping and cleared Release intermediates. The previous DLLs
named the commit and the worktree they were built in, so committed plugins
could never match a fresh build of the commit that holds them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 15:18:42 +02:00
Meta Vens
b26c98f185 Note that CultManagedDocument is parked with SoA; state the page load rule
The parked/cultcache-soa tag message says the managed document was deleted
separately. parked-features.md now supersedes that; the tag is unchanged.
The directory store gains its design statement and a comment that only
manifest-named pages are loaded.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 17:17:14 +02:00
Meta Vens
1982d73e44 Name the managed document in the parked SoA entry
CultManagedDocument<T> and its two Document<T> openers came in with the SoA
storage (5428870) and are preserved at the same parked/cultcache-soa tag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 16:41:55 +02:00
Meta Vens
d904960610 Park the CultCache SoA table at parked/cultcache-soa
The SoA table was built for ECS-style structure-of-arrays columns over
cached documents and has no consumer outside tests. It is tagged before
removal; docs/parked-features.md names the tag, span, and restore path, and
the runtime parity scope says the table is parked rather than wrong.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 16:21:25 +02:00
Meta Vens
486fe560af Correct stale store-routing, SoA, and generator docs
The README and the Rust README described mirrors as C# behavior; the parity
scope claimed the C# SoA table; the generator README described DatabaseEntry
formatters that no longer exist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 16:01:32 +02:00
Meta Vens
95493862bd Split the Python runtime into cultcache-py, cultnet-py, cultmesh-py
One distribution named cultcache-py carried three libraries. Rust and
TypeScript layer them as cultcache < cultnet < cultmesh; Python now does
the same, one package per layer, module names unchanged so every
`from cultmesh_py import ...` keeps working.

Two imports ran against that layering and are resolved by moving code to
where the dependency direction says it lives, not by adding a shim:

- cultnet_py.interop_peer imported the Verse/peer catalog, authority
  lease, stream, and simulation-fact contracts from cultmesh_py. They are
  wire contracts a bare peer has to speak without owning a node, which is
  why cultnet-rs and cultnet-ts keep them in the net layer. They now live
  in cultnet_py.cultmesh_contracts; cultmesh_py re-exports them.
- cultcache_py.benchmark imported cultnet_py. It measures framed CultNet
  parse beside cache paths, so it and compare_csharp move to cultnet_py.
  verify checks all three packages and moves to cultmesh_py.

The single 6,693-line test module is split by what each test touches: a
test using any cultmesh_py name lands in cultmesh-py, else cultnet_py in
cultnet-py, else cultcache-py. Each suite runs with only its layer and the
layers below on the path, so a test that reaches up fails to import
rather than quietly binding the packages back together. 11 / 53 / 78 =
the same 142.

Workflows install all three; the publish job is one matrix over the
three packages keyed by tag prefix. The TS test harnesses put all three
src directories on PYTHONPATH. cultcache-py bumps to 0.2.0 because it no
longer contains cultnet_py or cultmesh_py; the new packages start at
0.1.0. Nothing was ever published, so no PyPI consumer moves.

  cultcache-py  11 tests, path: cultcache-py/src
  cultnet-py    53 tests, path: + cultnet-py/src
  cultmesh-py   78 tests, path: + cultmesh-py/src
  python -m cultmesh_py.verify -> ok, all five checks
  cultnet_py.interop_peer imports with cultmesh_py absent

Not run here: the cultnet-ts interop ring and cultcache-ts store matrix
need dotnet/kotlin peers; their PYTHONPATH change is four lines.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 13:10:47 +02:00
Meta Vens
4111fbb468 Write down that a stored record's encoding is part of its contract
Three byte-exact re-encode guards exist across three separate Idunn
stores -- the runtime projection, the deployment brake, and the trust
bindings -- each decoding a record, re-encoding it, and refusing on any
byte difference. Idunn's control store does the same for its own
transactions. Three independent instances is a house pattern, and it
means changing how any persisted CultCache record serializes is never a
flag flip.

Records the measured behaviour of #[cultcache(key = N, bytes)] rather
than the assumed one: reading stays compatible both ways, so the cost
lands on reproduction and therefore on those guards, not on
compatibility. A field with no live producer is free; a field with
persisted records needs its store rewritten in the same change.

Also records that Option<Vec<u8>> cannot take the attribute today, and
that a shape-validated field nobody produces may be a fossil rather than
an omission -- the estate has at least one other case of a live consumer
outliving its producer.

This was learned by nearly deploying an attribute flip that would have
made Idunn refuse the projection store Odin reads.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 01:18:45 +02:00
Meta Vens
5dbc0c29f5 Bound the RUDP receive path and refuse hostile sequences
Clears the cultnet half of the retained debt. The two unported commits from the
retiring GameCult/cultnet-rs lineage were not portable as patches: this lineage
had reworked the same receive path with sequence domains and ACK horizons, and
applying them raised nine conflicts that would have reverted that work. Most of
what they added already existed here by another route -- received-sequence
history, fragment-set count and reassembly bytes are all bounded already. So
the gaps were taken rather than the patches.

Three were real. The per-channel maps grew without limit, and a peer picks its
own channel ids, so ordered and sequenced channel tracking is now capped at 64
each. The out-of-order hold buffer grew without limit, and a peer picks its own
send order, so it is capped at 1024 frames and 4 MB; sizes are computed from the
buffer rather than tracked in counters, which cannot drift.

The fourth was the sharpest. remember_received ran before the duplicate
early-return, so a single forged packet far past the current highest advanced
the receive state beyond every sequence still in flight and starved the
session. Such a packet is now refused without being remembered.

Reliable sequence exhaustion aborted the process through expect(). The capacity
gate that already guards the send window now also refuses when the sequence
space cannot cover the request, and allocation saturates rather than panicking
so no future path can reintroduce the abort.

Five tests cover the bounds and both refusals. cultnet-rs passes 103,
cultcache-rs 48, cultmesh-rs 7, and the TypeScript-Rust RUDP interop lanes pass
5 of 5 with the hardened peer, so legitimate traffic is unchanged.

The parity ledger now records what this actually leaves owed: these are
refusals, not wire-format changes, so the interop lanes stay green whether or
not the other four runtimes match. The gap will not announce itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 00:57:07 +02:00
Meta Vens
62ac7e3483 Record the unported RUDP hardening as owed work
Exact acknowledgement receipts landed; bounded session memory and hostile
sequence rollover rejection did not. Until they do, this runtime accepts
sequence and reassembly input the retiring lineage rejects, so its repository
cannot be deleted yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 23:14:45 +02:00
Meta Vens
67cbb4ea36 Give the Rust CultMesh runtime a home
The only Rust CultMesh implementation in existence was 1,363 lines inside
Ghostlight's vendor directory. It was in no library repo and no standalone
repo, so it had never been checked against the browser, Kotlin, and
TypeScript CultMesh bodies it must interoperate with.

It is not a duplicate of the facade in cultnet-rs. That one is the small
surface the parity table claims for Rust: peer cards, authority leases,
endpoint parsing. This is the stream and session layer -- node, document
sets, RUDP document publication, stream descriptors, negotiation, stream
catalog, and shared-memory frame rings -- which the same table lists under
Rust's "Not claimed". A consumer grew the unclaimed surface because there was
nowhere else to put it.

Its path dependencies already matched this layout and it builds against
CultLib's cultnet-rs unchanged, so it does not depend on the forked RUDP
extras. Seven runtime-local tests pass, and CI now runs them.

The parity table gains no claim from this. The Rust row says plainly that no
interop lane exercises the stream surface, and expansion work records that
runtime-local tests are not a parity claim. Landing code is not evidence.

packages/cultmesh-rs needed an explicit .gitignore re-include; the NuGet
packages rule hides every language package until one is added by name.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 23:09:45 +02:00
Meta Vens
75c180782a Acknowledge retransmits across RUDP horizons 2026-08-23 19:15:22 +02:00
Meta Vens
a2e3d3fa35 Bind reliable windows to the RUDP ACK horizon 2026-08-23 18:54:18 +02:00
Meta Vens
f4dabfefb0 Bound RUDP reliable transmission windows 2026-08-23 18:35:49 +02:00
Meta Vens
d4d24385d1 Prove clean .NET Eve package onboarding 2026-08-18 06:33:40 +02:00