Deletes CultNetDocumentRecord, the DocumentPut and SnapshotResponse variants,
parse_cultnet_message, require_typed, round_trip_typed, the eight replication
functions and the two catalog schemas (parked at tag
parked/cultnet-rs-dynamic-document-lane). decode_cultnet_message_from_slice is
the one decode; raw v1 rows, identity credentials and the signed-record readers
decode through cultcache_rs::decode_payload. Adds tests/decode_door.rs. 0.2.0.
Not yet compiled at this commit (verification runs on Yggdrasil).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Operator ruling, 2026-09-30: "FEC: Please own the math."
reed-solomon-erasure 6.0.0 pulled lru 0.7.8 (RUSTSEC-2026-0253, unsound) and
instant (RUSTSEC-2024-0384, unmaintained) into every cultnet-rs consumer.
media_fec.rs now implements the construction its docs already state, read
against the crate's source rather than its names: GF(2^8) reduced by 0x11D
with 2 as generator, the n x k Vandermonde matrix over the evaluation points
0..n-1 with 0^0 = 1, E = V * inverse(top k rows), parity = rows k..k+m of E,
and recovery through the inverse of E's rows for the first k present shards,
which is the row choice the crate made.
About 130 lines: const log/exp tables, a Gauss-Jordan inverse, the encoding
rows, and one combine loop. It allocates only the block's shards and three
k x k matrices, so the decoder's bound is still set by the wire validators
(<= 256 shards of <= 64 KiB). The shard functions no longer return errors
that only the crate's own checks could raise; every caller already bounds k,
m and the shard length.
The generator test is deleted with the crate; the fixture keeps its output and
names the commit that ran it. New: a seeded property test over 300 random
(k <= 48, m <= 24) geometries, any e <= m erasures recover exactly and m + 1
are refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cultnet_impair is a deterministic bidirectional UDP proxy for pressure
testing real CultNet RUDP sessions with seeded loss, burst, duplicate,
reorder, jitter and stall schedules. It is ported from the Odin donor
(80adfd3) as an example, not library surface. The decision policy (Profile,
Scheduler, seeded RNG) is split from the sockets into policy.rs, which the
proxy and the tests both compile, so a schedule has one owner. The ten
donor profiles live in tests/impairment/.
tests/impairment_policy.rs keeps the donor's six deterministic policy tests
(the burst test now pins the exact drops rather than a count) and adds
profile loading and rejection. tests/media_fec_loss.rs sends protected video
frames through those schedules with no sockets and asserts the guarantee: a
block recovers exactly when at most m of its records were lost, recovered
chunks equal what was sent, and a burst that the send order spreads under m
per block loses no frame. The recovered-frame ratios are printed, not
asserted; tests/impairment/loss-matrix.txt is that output.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The codec owns the erasure math for both ends: protect_video_frame and
protect_audio_block on the producer, recover_video_block and
recover_audio_block on the consumer. Each block is systematic Reed-Solomon
over GF(2^8) (reed-solomon-erasure 6, default features), named on every
parity record by the scheme id rs-gf256-v1. Any <= m erasures recover
exactly; more report BeyondRepair. Video frames split into ceil(n/16)
near-equal blocks with m = max(2, ceil(k/4)); audio is 4+2. A frame's
records come back in send order, rotating one record from each block so a
burst lands as one loss per block.
Deleted first: gamecult.media_video_parity_shard.v2 and its XOR-stripe
validator, and the reliable "audio" channel (profile entry, send-options
arm, constant, tests). Audio now rides "media" with parity.
Added: gamecult.media_video_parity_shard.v3 (block geometry, scheme id,
shard length), gamecult.media_audio_parity_shard.v1, the AudioParity wire
variant with validation, and the parity record key now names the block.
Every shard is bounded at MEDIA_FEC_MAX_SHARD_PAYLOAD_BYTES (720) so its
wrapped record fits MEDIA_FEC_MAX_WIRE_BYTES (1431), measured with
identifiers of up to 32 bytes.
Tests pin: exhaustive recovery for every shipped (k, m) and 4+2, m+1
refusal, known-answer parity bytes for both paths, the datagram bound on
every record kind, send order, deadline carriage and decoder validation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The standalone GameCult/cultnet-rs holds six modules CultLib never received:
runtime_authority_contracts, service_identity, provider_health_contracts,
idunn_deployment_brake, idunn_lifecycle_brake, and snapshot_query. They own
Idunn Expected incarnations, dual-proved runtime activation, process write
leases, service-signed presence health, and Odin topology correlation -- the
wire contracts every GameCult daemon must agree on.
They belong here because wire parity conformance lives here and nothing
outside it is checked for cross-runtime agreement. Held as source to be
copied, this contract already forked: Ghostlight vendors it at e542225 while
its own authority map names f4ab237, and the two disagree on whether Present
may coexist with a disagreement. One copy makes them exclusive; the other
separates presence from readiness and gates through into_undisputed_present.
A single owner under the parity harness is the fix; re-vendoring is not.
None of the six touch RUDP, so they land without disturbing the protocol
core. rudp.rs remains genuinely forked -- 140 hunks between the lineages,
with reliable windows and ACK horizons on this side and bounded session
memory, exact acknowledgement receipts, and hostile rollover rejection on the
other. That reconciliation needs the cross-runtime interop harness and is not
attempted here.
Adds ed25519-dalek, zeroize, and the Windows Foundation/Cryptography features
the credential paths require. 96 tests pass. The two rudp_server_hub failures
are pre-existing on this base and reproduce at 230ace6 untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>