The reader owns the verdict; the writer replaces an arrived record by key alone so it cannot emit a store the reader refuses. Store-file tests no longer pin one key under two types.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
0.14.1 and 0.14.2 were never tagged; cultcache-ts-v0.14.0 is the last release. The
Unreleased exports (SchemaConflictError, schemaIdentityOf, the document payload codec)
are in no tagged release, which is what failed the declared-ranges check. Package and
lockfile go to 0.15.0 and every consumer range (cultnet-ts, cultmesh-ts, cultmesh-browser)
moves to ^0.15.0, since a 0.x caret does not admit a new minor.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The package root imports node:fs, node:path and koffi through the single-file
store, so esbuild platform=browser fails on it. src/browser.ts is the root
surface minus that store; src/index.ts re-exports it and adds the store, so
the Node entry is unchanged. Exposed as ./browser and as the 'browser' export
condition on the root.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Both blocks now come from a snippet region in their test, and a second test
fails when docs/start/README.md stops showing it, as the Rust and Python
blocks already do. The TS block differs only in the package import specifier.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A language x package matrix (each cell a tested snippet or "not yet"), a C# first-call test and a TypeScript first-call test that the docs link, and a pointer from the top of README.md.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Hand mutant T4 (lead >= 0x90) survived; the empty-array case now carries a newer stamp after it.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The Unity list no longer calls MarkFlushSucceeded removed and places HeaderFor and the CacheBackingStore members where apicompat finds them. cultnet-rs gains a CHANGELOG. The store-composition contract moves DecodeDocument to the codec and states that a call's registry serves that call only. Docs only.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The stamp functions (Rust refuse_unread_format, TS refuseUnreadFormat) are the single owner of the stamp rule, accept v1 and v3, and are called only from the one reader every whole-store write runs under the lock. The fix's header peek (TS refuseUnreadStoreBytes, peekHeader) is deleted. Its tests that v3 is refused and that a stampless file is healed are dropped; the reversal is a Breaking line in the Rust and TS CHANGELOGs. The 0xff-after-stamp test now runs over v1 and v3.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Owns finding c2a-public-breaks-not-in-changelog. Leaf changelogs gain v3 read and write and element ids carried; cultcache-rs gets its first changelog (the whole-store writer fix is not on main, so no 0.3.1 section).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
refuseUnreadFormat is shared by isV1Snapshot and the writer's header peek; message text unchanged. Builds.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Both new tests fail at this commit; it builds. Vector copied byte-identical from C2a (blob 9fc9b64f).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
Fixes variants:finding:cut-ts-store-write.s2.changelog-csharp-any-write-overclaim:
a C# conditional commit on a clean store lands onto the current file; other
C# writes can still overwrite concurrent TypeScript records.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
push and delete no longer lose records across concurrent TypeScript and Rust writers. A full
pushAll and any C# write still replace the whole store.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The default StoreFileOps were never observed. One test now wraps fs/promises.open and each handle's
sync and close, and records the store's bytes at every call: the staged file is synced and closed
while the store still holds its old bytes, and on Unix the directory is synced and closed after the
store changed. A second test puts a directory at <store>.lock and requires the lock to fail within
3 s with the lock path named, under the default 30 s wait bound.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A share-none open (what the C# lock and readers need) must succeed after the replace
and after a waiter gave up.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both directions: a TypeScript write waits on a C# or Rust holder; a C# or Rust writer
waits on a TypeScript holder; the lock wait bound names the lock path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#enqueue takes withStoreWriteLock; the legacy heal moves out of pullAll's read into a
queued, locked operation that re-reads; push and delete read through #readDisk so they
never enqueue from inside the locked queue (a self-deadlock). Builds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
commitStoreFile stages a unique temp, fsyncs it, replaces the store and fsyncs the
directory on Unix. Windows replaces POSIX-semantics first with a write-through
MoveFileExW fallback and a 25x20 ms retry on 5/32/33 (koffi, loaded lazily). The
cross-process lock functions land in the same file but are wired in a later commit.
package-lock.json also carries pre-existing version drift from regeneration.
Builds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One browser-safe module owns the manifest and chunk-ref shapes, their MessagePack form (positional ten-array, metadata as
ordered entries, duplicate keys and unsafe integers refused, payload depth through cultcache-ts's own checkPayloadDepth),
normalizeHash/parseSha256Hex, both record-key grammars (StableToken per UTF-16 unit), WebCrypto sha256Hex and packContent.
cultcache-ts/document re-exports checkPayloadDepth. scripts/write-cultmesh-content-vectors.mjs writes the TypeScript
manifest vectors for the C# reference to judge.
Builds. Co-Authored-By below.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main's two payload-depth tests staged a record with no catalog entry and
asserted that the inspector and the single-file store infer its schema from
the payload's first element. C2a refuses a record whose schema id the catalog
lacks (merge-r1-precedence, exact binding), so the guess door is gone. The
inspector test keeps the bound check with a catalog entry that names the
schema; the store inference test goes with the door.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
C2a's writer, catalog and soft-push tests handed raw Uint8Array payloads to
the store. Main made the envelope payload an opaque DocumentPayload, so they
wrap with documentPayloadFromBytes and read back with documentPayloadBytes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>