Commit graph CultLib/src/GameCult.Caching.MessagePack
Author SHA1 Message Date
Meta Vens
c14b2c65d1 Land fixes: stamp judged before the body, deep stores on the grown stack, ported tests refuse by their typed errors
Stamp rule runs on slot 0 before the body is scanned (JudgeStamp). DescribeHeader names a v<N> header that carries a suffix. Rust store_header walks on the grown stack. Drift tests declare Wide's id compatible (ownership by declaration). Mesh write-guard tests expect the typed refusals.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 20:49:43 +02:00
Meta Vens
f2b3569822 Merge main at cultlib-unity-v2.0.0 (42dce361) into C2a: one owner per collision
Identity: C2a's StoredSchemaId/StoredVersion owns; main's PersistedSchemaId, PersistedIdentity and both MarkWritten are deleted. Stamp rule: ReadStore judges the stamp before the body. Flush over damage refuses (merge-r1-precedence). Mesh single-file writes route through SingleFileMessagePackBackingStore. TS: store-file.ts commits, C2a's header handling kept. Rust: C2a's readable_store_format in front of the grown decoder. Build not yet verified at this commit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 20:35:33 +02:00
Meta Vens
ef45e4ed82 org.gamecult.cultlib 2.0.0: the parser's comment and the flush bullet state the exact stamp rule; declare the nil-stamp refusal (Soul s5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 19:03:29 +02:00
Meta Vens
4a14f17270 Public DeserializeSnapshot parses any stamp as in 1.0.61; stores judge the v1/v2 stamp in their own read paths; flush prose states the exact rule; the I/O refusal test asserts no write was reached
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 18:34:15 +02:00
Meta Vens
6adc321a73 Caching: a binary-encoded stamp is refused; directory manifest readers name their stamp rule; the I/O refusal test fails the real read
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 17:33:24 +02:00
Meta Vens
39e8ab5efd Single-file and directory snapshot reads judge the format stamp before parsing the body; a flush heals an empty or truncated file
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 17:30:57 +02:00
Meta Vens
0bf11ddc94 Caching: SingleFileBackingStore.PushAll owns the flush guard; it reads the disk as attach and commit do, ReadFormatVersion is deleted
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 17:00:10 +02:00
Meta Vens
d44188637d Caching: a plain flush and a directory write refuse a store another process stamped newer since attach
Single-file PushAll reads the format stamp under the lock and refuses cultcache.store.v<N> with N > 2;
the directory store throws NotSupportedException for N > 4 from the manifest parse every write already runs.
An unreadable stamp keeps today's behaviour.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 16:43:11 +02:00
Meta Vens
73d438dbcf CultCache: every backing store marks the records it rewrites, through a protected CacheBackingStore.MarkWritten
The directory store's write of a generation marks each page it wrote once the
manifest names it, so a Push+PushAll of a loaded drifted entry no longer leaves
its persisted schema id stale. The single-file store marks through the same
member, and a store outside GameCult.Caching now has a supported way to mark
its own rewrite. The getter's doc names how a store records a rewrite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 21:41:53 +02:00
Meta Vens
3f6dda8b36 CultCache: conditional commit compares the schema id a record is persisted under
The six reads that took Descriptor.SchemaId as a record's durable identity (ConditionsHold, Expect, the store-less commit, both pull filters, JudgeMerge) now read CultStoredDocument.PersistedSchemaId. The store sets it from the record it read, a stamped entry starts at its descriptor's id, and a completed whole-file write (single-file PushAll, whole-view CommitBatchCore) resets it under the hold. A variant and its resolved view share it. An unchanged record loaded under compatible drift now satisfies Expect and ExpectUnchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 21:05:23 +02:00
Meta Vens
1330362235 CultPhasor rename: README, design note and both changelogs
cultmath-unity [Unreleased] and cultlib [Unreleased] carry the Breaking entries; no version bump, no tag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 19:28:25 +02:00
Meta Vens
58baccce78 CultMathJson writes CultPhasor as cosine/sine and still reads cos/sin
Fields takes an optional legacy name per field, matched on read only and mapped to the same index as the current name, so a legacy and a current name in one object are the same property and the duplicate rules decide (refused when AllowDuplicateProperties is false, last wins otherwise). Writing never emits a legacy name. MessagePack bytes are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 19:28:09 +02:00
Meta Vens
d605c70bba CultPhasor.cos/.sin become .cosine/.sine in C# and HLSL (GLSL regenerated next)
SPIRV-Cross renames members matching GLSL builtins, so the source names change. Resolver and JSON writer accessors follow the members; the wire (positional MessagePack, JSON keys) is untouched in this commit. The committed GLSL is stale until its regeneration commit, so CommittedGlslEqualsLowering fails here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 19:25:39 +02:00
Meta Vens
fc3bdc70e8 Caching: MessagePack and JSON shapes for CultSiteCells, pinned
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 18:16:37 +02:00
Meta Vens
19f475ca92 Element ids part 2: one recogniser; shapes the walk does not own are whole values
Delete Hidden, HiddenProblem, UnreadKeyedMembers/UnreadMembers, Settle's
[MessagePackFormatter] refusals and the door's written-as-object branch.
Classify gains Leaf for attribute-formatted, [DataContract] and string-keyed
types; MembersOf honours the most derived AllowPrivate; the door refuses a
null StandardResolver formatter with the throwing path's text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 00:54:37 +02:00
Meta Vens
a5241112de Codec door refuses only a proven family mismatch; source-generated formatters pass
WrittenAsWalked required StandardResolver's formatter to equal one of the walk's own families, which refused every source-generated formatter. WrittenAgainstWalk asks one contrary resolver per walk kind and refuses only on a reference match. DcSeq is refused as a collection written as an object; FormattedRoles passes (registration owns the attribute).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 20:52:13 +02:00
Meta Vens
52d25740ac caching: MessagePack and JSON shapes for SpanPath and SpanStage
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 20:49:31 +02:00
Meta Vens
48d3f667e6 Element ids: a keyed map counts as enumerating objects; family check tests assert the exact refusal
EnumeratesObjects took ElementTypeOf first, which for a dictionary is the
KeyValuePair (a leaf), so a keyed Dictionary subclass never reached the path; the
map's value type is asked first. The unreachable null-standard guard in
WrittenAsWalked is removed. Tests pin the direction and wording of the refusal, the
attribute-formatter collection case and the unwrapped inner exception.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 03:09:39 +02:00
Meta Vens
5157c647af Codec: confirm MessagePack writes every id-path type the way the walk reads it
CultElementIds is the walk's model of a type; MessagePack's StandardResolver owns how
a type is written, and nothing checked that the two agree. ResolverClaim now asks,
for each id-path type, whether StandardResolver's formatter is the object or union
resolver's (a type read by key) or a collection resolver's (a collection), and refuses
the document at first encode or decode when it is not, naming the type. A keyed type
that enumerates objects goes on the path so a keyed List subclass is caught. A type
MessagePack cannot build a formatter for, and a resolver ahead that throws, are typed
refusals; the AllowPrivate catch is pinned (s4: keyed-enumerable-misclassified,
allowprivate-catch-unpinned).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 02:53:28 +02:00
Meta Vens
908d9ac29d Codec: StandardResolverAllowPrivate's formatter for an id-path type is no claim
It writes the [Key] layout plus non-public keyed members, and registration now refuses any of those that
reaches an object list, so no element id can be dropped. The comparison is made lazily, only after an
ahead resolver returned a non-standard formatter, and an exception from it reads as not equal.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 01:23:40 +02:00
Meta Vens
b0cc36bc7e ResolverClaim: a resolver returning MessagePack's standard formatter for an id-path type claims nothing
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 00:26:53 +02:00
Meta Vens
e5736e49f3 CultCache: a write that copies a record it read holding an element id marks the store
The single-file store records, per pull, which plain records decoded holding a non-empty
element id and at what version. A write whose copied record is still at that version
marks the header (v3). The record is positive-only and version-gated, so nothing a load
records can unmark a store. The directory store passes false: only C# writes it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 21:52:36 +02:00
Meta Vens
b091d21f81 CultCache: list elements are written by their [Key] layout; registration and the codec refuse otherwise
Registration: a concrete element type of an object list that is not keyed, and
[MessagePackFormatter] on any type or member on the id path or on the id member, are
refused. The id path is a fixed point over the walk's edges. The codec refuses, once per
document type and on every encode and decode path, a resolver ahead of StandardResolver
that formats a type on that path. UnionArmGuardTests moves StubArm out of the list union.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 21:52:36 +02:00
Meta Vens
427d81feda GameCult.Caching: SpanNoise MessagePack and JSON shapes
MessagePack [field, curvature, fold] beside CultPhasor in CultMathResolver, JSON {field, curvature,
fold} in CultMathJson; round-trip, hex and JSON golden cases beside CultPhasor's.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 20:48:44 +02:00
Meta Vens
0f6edfbfbb Merge remote-tracking branch 'origin/main' into hands/variants-c2a-main 2026-10-14 19:38:48 +02:00
Meta Vens
d47811c323 ExprGraph resolver: nil is nil, decode refuses non-canonical encodings, pin nested shape, nil-name and depth rules
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 07:54:32 +02:00
Meta Vens
defe2b80de Document CultMath.Expr: design.md Expressions section, resolver README
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 06:05:19 +02:00
Meta Vens
dc302a96a7 CultMath.Expr: scalar SSA expression graph, builder with substitution, one validator, evaluator, MessagePack shape
ExprGraph (immutable class, one validator in Create), ExprBuilder (hash-consing, dead-node removal, Substitute), ExprOps (the one op table), ExprEvaluator, ExprBindings, ExprGraphException; CultMathExprResolver appended to the default chain after CultMathResolver.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 06:05:18 +02:00
Meta Vens
c1962181a2 Merge remote-tracking branch 'origin/hands/variants-c2a' into hands/variants-c2a-main 2026-10-14 04:38:07 +02:00
Meta Vens
3b83cb6c08 Merge origin/main into hands/variants-c2a-main (main-into-c2a)
Sixteen conflicted files resolved by the spec's rule: main owns payload
ownership, bounds and the Clock seam; C2a owns persistence semantics and exact
binding. MintStoredAt is internal static (previous, now); the cache and the
store pass their cache's Clock. Package versions are main's. The cultmesh-ts
payload-parse acceptance and its test are deleted under retire-schema-alias;
peer snapshot reads take the schema's own id, else an id the definition lists
as compatible. The held firstRecordAtKey fallback is removed: main's handles
take definitions only, so nothing could reach it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 04:06:41 +02:00
Meta Vens
696a712088 JudgeChecks (directory): drop the CreateDirectory the commit lease already makes; tests for a never-written non-home store and for a check-less batch beside a held lock
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 02:23:14 +02:00
Meta Vens
1893410fe1 Every writable store judges a batch's unheld removals under its own lock; a foreign record's version comes through Foreign
CacheBackingStore.JudgeChecks (default: the view; single-file and directory stores read under their lock) replaces Land's view-only loop over non-home stores. Foreign takes the version the store read; CultForeignRecord.StoredVersion is get-only and set by the ctor, and every assignment after Foreign is deleted. One commit carries both spec commits 1 and 2 (the edits share hunks); unverified until the final job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 02:07:19 +02:00
Meta Vens
3a18f01a83 Caching: a removal of a key the cache does not hold is a check-only key judged under the store's lock; ExpectUnchanged compares foreign records too
Remove and Commit of an unheld key no longer read the store at the call: the key travels as CultCommitRequest.Checks (commit) or a staged check (flush),
and each writable store judges it in RefuseUndeclaredOnDisk with the keys it writes, never removing it. A batch that only checks writes no file.
CultForeignRecord.StoredVersion records the version a store read, and the one ConditionsHold takes the store's foreign records.
Folds spec commits 1 and 2 (their hunks share the same methods). The src projects build; tests/GameCult.Caching.Tests does not at this commit
(CultCommitRequest gained a parameter; the next commit updates the test).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 04:03:41 +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
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
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
43a63b0792 Removing a foreign record is judged against the store as it is, not the last load
A removal of a key the cache does not hold writes nothing, so it never reached
the apply; it was checked against the foreign list of the last load, and a
foreign record that arrived since was reported removed. Each store now reads
its durable state for such a removal (RefuseRemovalOfUndeclared) and refuses
through the apply's own RefuseUndeclaredOnDisk, which reloads and lists the
record. The load-time check (RefuseRemovalOfForeign) is deleted: the durable
read refuses everything it refused, and it could not save that read. A store
kind that cannot read its durable state keeps the view check as its default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:13:32 +02:00
Meta Vens
b636a69f9d A refusal lists what it refused foreign, as a pull lists it
Refuse reloads a refused key as a pull loads it, and now that includes the
store's foreign list: a record another writer moved to an id this cache cannot
read is listed in ForeignRecords after the refusal, so the next write of that
key is refused at staging instead of again at the flush. Both store kinds give
Refuse the durable record's foreign entry (ForeignAt); the variant refusal too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:13:07 +02:00
Meta Vens
067df993a3 Apply refusal: a write over a durable record under an undeclared id is refused at ApplyWriteSet and reloads read-only
ForeignOnDisk and the two RefuseForeign calls in PushAll and CommitBatchCore are
gone. ApplyWriteSet refuses first, over every key it writes or removes, by
Registry.Declares for a cache and by the catalog entry it writes for a cacheless
CultMesh write. Both refusals reload through one DurableAt; the directory store
reloads through LoadPage, the per-record body of LoadRecordPages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:11:23 +02:00
Meta Vens
e9a668769a Ownership by declaration, staging half: a write that would change a record under an id no registered type declares is refused before staging
Declares (registry) is the one answer to whether a cache may write, relabel
or remove a record stored under an id. RefuseUndeclared applies it from
Validate's Claim, which every cache write passes, to what the home store
holds at the key: a foreign record or one held under an undeclared id.
RefuseOverwrite and its two Push calls are deleted.

Red until rewritten: ForeignRecordTests.AWriteOfTheRecordItselfStoresItUnderTheTypesOwnId
and CompatibleSchemaIdTests.AnotherNewerCacheRestoringTheIdAfterAnOlderRewriteStillFailsTheCondition,
which pin the relabel rule 3 forbids.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 12:31:53 +02:00
Meta Vens
2a3773a463 CultCache: the store owns a file's bytes, not the record object
Delete RawBytes from CultPersistedRecord and CultSchemaCatalogEntry, with every
drop-on-assign hook and the catalog's content guard. A decoded record or snapshot
carries no stored bytes, so an in-place edit of its payload or overrides can never
be shadowed by cached bytes, and the public snapshot and record serializers encode
every record from its fields.

SingleFileBackingStore now reads through ReadStore, which returns the snapshot and,
parallel to it, the exact slice the file holds for each catalog entry and record. Its
durable index keeps, by record key, that slice and its SHA-256 (hashed when a
comparison asks), which is the record's version. A write re-encodes every record
the writer staged and copies every other record, and every catalog entry it keeps,
as the slice the file holds. The directory store keeps its manifest's catalog slices
the same way. SerializeSnapshot/DeserializeSnapshot hooks become
SerializeStore/ReadStore plus SerializeCatalogEntry.

A staged but unchanged non-canonical record is now re-encoded canonically and gets
a new version; an untouched one keeps its bytes and version.

Tests: in-place edits through the snapshot API (payload, override) and through a
held document (collection, nested object) are written as edited; an untouched
non-canonical record survives a neighbour's write byte for byte; a staged one is
re-encoded. The cost test counts record hashes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 10:47:30 +02:00
Meta Vens
6001ebf932 CultCache: a single-file version is the hash of the record's exact stored bytes, and a copied record keeps them
A record read from a store file carries the bytes it was read from (CultPersistedRecord.RawBytes, dropped when any field is
assigned) and is written as those bytes, the way a schema catalog entry already is. A version is therefore the SHA-256 of the
slice the file holds, whatever legal encoding its writer chose, not of C#'s re-encoding, and a write that copies a record leaves
its bytes and so its version alone. The contract says exactly that, so the parity cuts port it literally.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 09:48:24 +02:00
Meta Vens
b195525d64 CultCache: a record's version is the SHA-256 of its stored bytes; conditions, pulls, the staleness check and a refusal's reload compare it, never storedAt
Adds CultStoredDocument.StoredVersion, CacheBackingStore.VersionOf and the
SingleFileBackingStore.SerializeRecord hook, and swaps every identity comparison
in the same commit: SameStoredIdentity stays the one comparison, over versions.
Deletes the Identity helper, the (schemaId, storedAt) Expected tuple, the
in-memory fake-record projection and the directory's storedAt arrival.
Breaking public API for 2.0.0: CultCommitRequest.Expected, ConditionsHold and
the abstract SingleFileBackingStore.SerializeRecord.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 08:23:31 +02:00
Meta Vens
25d6cb2951 C# store header: the durable header owns "holds element ids"; StoredHoldsIds and KnownIdFree are deleted
A record's bytes cannot say whether it holds an element id (an id is an ordinary keyed
string), so the per-record fact decoded by whichever type loaded the record was a split
authority: a narrower type unmarked a v3 store over bytes holding ids. HeaderForWrite is now
a pure function of the durable header, the HoldsIds of the records the write encodes, and
whether it copies any record forward: a write that copies keeps a marked header, a write
that encodes every record decides by content. The directory store takes the same rule.

Also pins the three Low test findings deferred from c2a-write-set s3: the reload cause is
observed by type and message, the author's own Expect after a commit, and the directory
store's re-mint branches.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 07:04:48 +02:00
Meta Vens
2e3312635d C# write set: one re-mint for every store kind, and a foreign refusal carries its reload failure
The directory store wrote an earlier storedAt over a later record it replaced, against the contract.
CacheBackingStore.StoredAtOver is now the one re-mint; the single-file apply and the directory
generation write both call it. A foreign refusal passes the reload's cause to
CultSchemaConflictException as its inner exception. Per-commit build not verified.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 06:05:41 +02:00
Meta Vens
a7114a1f9f C# write set: tests for copy-forward, raw catalog carry, header rule and the inverted lay-back rules
New WriteSetTests (single-file and directory stores, flush and commit): another writer's write and
removal survive, a store that appeared after open is kept, an unstaged in-place change is not
written, a copied record keeps the catalog entry the store holds now, an entry's unknown trailing
fields survive byte for byte, conditional and unconditional commits write the same bytes, the
header drops only when every copied record is known id-free, v2 exactly with a variant. Mesh: a
write copies neighbours forward and replaces only its key. The lay-back and whole-view tests and
the flush-restamp tests are rewritten or removed with the rules they pinned.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 03:16:49 +02:00
Meta Vens
aa186513a5 C# stores: every flush, commit and CultMesh single-file write applies a write set to the durable store
SingleFileBackingStore.ApplyWriteSet replaces WholeView and ReplaceDurable: under the lock, from the
durable snapshot read there, it removes staged removals, writes staged upserts and copies every other
record and the catalog entries they reference unchanged. PushAll, CommitBatchCore (conditional and
unconditional, one apply) and CultMesh's write call only it. Catalog entries read from a store keep
their exact bytes and are written verbatim while their decoded fields are unchanged. Derive no longer
lets a registered entry publish an id nothing staged sits under. HeaderForWrite is the one header rule
for the single-file and directory stores. A write is judged against variants another writer left in the
file. Tests of the deleted rules are rewritten in the next commit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 03:05:08 +02:00
Meta Vens
2e12e9eebb Mesh single-file helpers: delete the second reader, the older catalog layout and the lock-free replace
Deletes CultMesh's ReadSingleFileSnapshot, HasOlderCatalogLayout, ReadLegacySchemaCatalogEntry,
WriteFileAtomically and the File.Exists gate, ReadStore's entry-reader delegate, and the three tests
of the older catalog layout. This commit does not build: the Mesh read and write sites still name
the deleted reader; the next commit routes them through the CultCache single-file store.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 01:59:13 +02:00
Meta Vens
425531d88e C#: a dangling link is an I/O error on read; the directory refusal echoes a header only as store version digits; contract names Rust's real type
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 20:49:12 +02:00
Meta Vens
bad511f5ac Merge CultCache R1 (f789c8d1) into C2a: one reader per runtime, R1's failure taxonomy
R1's rules win where both sides decided the same question: a zero-byte file is
not a store (refused as unreadable in every runtime), only nothing at the path is
empty, a dangling link is an I/O error, refusals never echo stored values and echo
a header only as cultcache.store.v<digits>, writes report Rejected, NotReplaced
and ReplacedNotDurable. C2a's rules win on what it added: the v3 element-id
header, variants, whole-file proof, typed unreadable errors in C#, TypeScript and
Python. Rust keeps R1's CultCacheStoreUnreadable{path, kind}; C2a's
StoreUnreadableError is deleted. The readability manifest's zero-byte row is
refuses x4.

Not yet built or tested: verification follows in the next commits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 19:41:35 +02:00