Soul s2 found 'success() || c' and plain or quoted if: values continued on a
following line passing the pin. Any status function now refuses, and stepCondition
reports an if: whose value continues (block scalar or a deeper-indented next line)
as multi-line, which the pin refuses. Soul's four probe forms are asserted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The persistence contract's rule 3 now says the store refuses, under its lock, a
write or removal at a key whose durable record is under an undeclared id, for
the store's own write API and for CultMesh single-file writes, which declare
through the catalog entry they write. The sentence that a declaring type stores
the record under its own id is corrected: Declares is registry-wide, so the
record lands under the writing type's id. The late-registration test is renamed
to match.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A record another writer moved to an undeclared id after the load, a staged
removal of one, and one that appeared at a written key are refused at the apply
and reloaded read-only. A direct store Push, Delete and CommitBatch of a
read-only record are refused and never relabel it. Removing a foreign record is
refused typed. A CultMesh write over a record its entry does not declare is
refused, and one whose entry lists the id lands under its own id.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove and a committed batch removal of a key the cache does not hold ask every
store whether it carries a foreign record there (RefuseUndeclared); one that
does refuses with the typed schema conflict instead of Remove returning false
and Commit returning Committed over a record the store still carries.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
A Publish if: calling always(), cancelled() or failure() runs after the suite failed, the
continue-on-error bypass by another name; a block-scalar if: was compared by its indicator, so
'>-' equalled '>-' whatever followed. Both are now refused. The third refusal no longer calls
sound conditions narrower: it names the three accepted shapes, and the code comment and
docs/semver-policy.md list the sound forms textual matching refuses and why.
(Soul findings cut-3-gate.s1.status-function-bypass, block-scalar-if-compared-as-text,
pin-refusal-cost-undocumented.)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unchanged CultMath source built on another SDK or host gives other bytes (Linux sdk:10.0:
db2a11cc against tracked 6781bf20), so the refusal no longer sends the operator to release a
CultMath with no change (Soul finding cut-3-gate.s1.toolchain-drift-named-as-source-change).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Directory.Build.props puts CultMath's obj at obj\packages\cultmath\src\CultMath, which the
obj\src-only clean left in place, so an old-mtime CultMath source change could reuse a stale
CultMath.dll and pass the byte gate (Soul finding cut-3-gate.s1.cultmath-obj-not-cleared).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The held-only mutant of RefuseUndeclared survived the suite, because the
apply-time refusal still caught the write at flush. This pins the staging
half for foreign records in both store kinds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The persistence contract's relabel paragraph is replaced by ownership by
declaration: a record read through the catalog's schema name or a persisted
entry's list is read-only, and declaring its id claims it. CultForeignRecord
says no type can read it; the write APIs and MintElementIds name the refusal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The relabel tests become refusals: ARecordReadByNameIsReadOnly (name branch)
and AnOlderVersionCannotWriteANewerRecordItReadsThroughTheNewerEntry (a
persisted entry's list). New: every write path refuses before staging,
declaring the id claims the record, a type registered after load claims it,
MintElementIds is refused by a read-only record, the undeclared dropped-slot
case, and a variant of a read-only base lands. The copy test also checks the
write beside the read-only record landed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eyes pass for variants❓read-only-record-signal. ORMs, embedded
stores, serializers, file systems and object stores; signal shape and
time-of-check pitfalls for each, with evidence pointers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
The suite step's if: is absent, equal to Publish's, or a leading conjunct of
a Publish condition that has no ||. A disabled or narrowed suite step fails
the pin. Closes asura:follow_up:suite-step-condition-pin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The declared org.gamecult.cultmath dependency must equal the CultMath package
version (-ne, not -gt), and every CultMath.dll a managed publish produced must
equal the DLL that package tracks. The type-name check and its helper,
scripts/check-cultmath-types.cs, are gone: the byte gate subsumes them.
$managedPublishes is the single owner of publish-root identity for the clean
step, the publish loop, $publishedByName, the byte gate and --api-refs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The release check measures each package against its predecessor tag instead of
trusting caller-declared flags. First releases are proved by a managed assembly,
the suite runs in CI and the Unity scripts before publish, and the Caching Unity
prefix is its own tag family. Verdict asura:verdict:cut-semver-measured.s7 holds;
one Low finding (suite-step-condition-unpinned) is deferred.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The store chooses carried catalog slices by the entry object the read
produced. Keyed by schema id instead, a type whose id is unchanged but
whose entry changed (a compatible id added) would have the file's old
entry written over its own. The test stages a WsItem over a file whose
ItemId entry carries an unread slot and asserts the writer's encoding
lands, in both store kinds.
Closes variants:finding:cut-c2a-content-version.s3.catalog-writer-entry-unpinned.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
publish-packages.yml runs the suite in both jobs, after .NET setup on a full-depth
checkout and before any check or publish step; the three Unity release scripts run
it before the checker. A test reads each file and fails when the step is removed,
moved, or made non-fatal. The Caching Unity pin now needs a prefix declared once
whose exact tags hold the package's own manifest at the tag's version. No NUL byte
in the checker is a test. The policy records that releases run from a full clone.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
MarchTile reports a body start where the gated bound over the rest of the
grid is a positive point and appends the rest unprobed; MarchLod takes one
closed-form Beer-Lambert step there. AnalyticBodyMatchesFineMarch pins it
against the ungated field and the fixed-step product, and pins that no
(a)-(d) tile reports a body. VoidField takes a focal length; LOD-far
(Rh 4000, S 50, f 467) joins the enclosure test, which now asserts it
sampled weights in (0, 1) and at 0. The void grid ends at Rc + 6/K. The
doc derives the one shipped void (198, 50) and records the [w(z1), 1]
deviation. (c) is held to 0.90 of its probe-free ceiling.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The radius gains (|c|_1 + radius) 2^-20 in C# and both HLSL copies; the
doc's strictness claim leaves. TileBallEnclosesEveryRaySegment measures in
double over the r2 domain and seven extreme families with outward corner
flows, pins the radius two-sided, and counts misses per family. The noise
ball enclosure tests draw radii to 1e3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolves Soul's five findings on cut-interval-ops.h2 and carries the rulings
operator-wells-contract-vs-ceiling and operator-analytic-wall-body. glsl-lowering
r2 and site-ground r3 now depend on interval-ops r3; the site-ground spec names
the one shipped void with (Rc, e) derived from (Rh, S) and the body-start word.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pins that a carried catalog entry keeps the store's slice, in the single-file and the directory store.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The C# peer gains edit-in-place (payload and override through the public snapshot
API; collection and nested object through the held document), and the four-peer
test has Rust and Python read each edit.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
Also defines the PE fixture before the tests that use it, so a filtered run no
longer reaches it before initialization.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The previous commit does not build: the widening helper read a byte string with an overload the test project cannot bind.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
Monorepo snapshot tags track every package's directory, so tracking a file
proved nothing about a package's own releases. A package with an assemblies
directory is a first release only when no tag under any prefix tracks a managed
assembly there (decided by PE bytes, once per blob). Assembly-less packages are
a first release when no tag of their own prefix exists; their prefix is pinned
by the suite test tying each declared prefix to a workflow trigger or an
existing tag, which now fails on a typo for every assembly-less package.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
The changelog-heading guard missed 12 of 17 heading shapes and a first changelog
entry. It and its parsing are deleted. A release with no same-prefix baseline is
a first release only when no tag in the repository, under any prefix, tracks a
file under the package's folder (declared assemblies dir, else the changelog's
directory); otherwise it refuses naming the tag. A tag whose tree cannot be read
refuses. Tests pin the mistyped prefix for CultMath 0.3.1, cultlib 1.0.61 and a
Python package, a genuine first release, the moved-folder choice, and an
unreadable ancestry and tree.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The foreign-record header test expected a marked header to drop while a record was copied
forward, which the header rule no longer does. A directory store loads a record from its
page, not the manifest, so its skew test makes both writers hold the record ahead instead of
editing the manifest.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
Ported from Soul's s2 probes: P5 skewed clock (equal storedAt re-mint, mint from the durable one),
D (directory store re-mint, as a store-kind parameter on the later-storedAt test), E (a disappeared
base refuses a variant write), P3 (foreign refusal whose reload fails carries the cause). New: a
foreign record a refusal reloaded is not seen as moved, and a writer that finds the file gone has
read nothing. ExpectOnAVariant is restored to pin that Expect tests only the stored delta: a stale
base reaches the write conflict, not a mismatch. Per-commit build not verified.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
The previous release is chosen by version order among same-prefix tags strictly older than the version, and must be an ancestor of HEAD, so a later backport on another branch never moves a rebuild's predecessor. A release with no previous tag is refused when the changelog already lists an earlier version, so a mistyped prefix cannot make an unmeasured first release. The declaration is validated as a whole: two packages sharing a prefix, or an entry without a string tagPrefix and changelog, refuse.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>