Contract: element ids, the v3 header and its rules
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
f4f8e3ed93
commit
e85b201bd2
2 changed files with 43 additions and 8 deletions
|
|
@ -15,6 +15,9 @@ Cross-runtime parity has three layers:
|
|||
without translation folklore.
|
||||
Every store reader refuses, by name, a header or record slot it does not
|
||||
understand (vectors: `tests/vectors/document-variants-c0`).
|
||||
Element ids: a store that can hold them declares `cultcache.store.v3`; TypeScript,
|
||||
Python and Rust read it and keep the header, and readers older than ids refuse it
|
||||
(vectors: `tests/vectors/document-variants-c2a`).
|
||||
Document variants: C# resolves them (`cultcache.store.v2`); every other runtime,
|
||||
CultMesh single-file reads, the directory store and CultNet refuse a variant by name
|
||||
(vector written by C#: `tests/vectors/document-variants-c1`).
|
||||
|
|
|
|||
|
|
@ -212,10 +212,17 @@ Example:
|
|||
The payload is the domain object only. It does not repeat the key, schema id,
|
||||
or stored timestamp.
|
||||
|
||||
Under `cultcache.store.v1` a record has exactly these four slots. A reader refuses any
|
||||
`cultcache.store.*` header it does not know and any record with more slots than its
|
||||
header allows, naming the version or the record's key and schema id. It never skips a
|
||||
slot it does not understand.
|
||||
Under `cultcache.store.v1` and `cultcache.store.v3` a record has exactly these four slots.
|
||||
A reader refuses any `cultcache.store.*` header it does not know and any record with more
|
||||
slots than its header allows, naming the version or the record's key and schema id. It
|
||||
never skips a slot it does not understand.
|
||||
|
||||
The headers are `v1` (no variant, no element ids), `v2` (holds a variant) and `v3` (can
|
||||
hold element ids, variants or not). A single-file store declares `v3` when any record it
|
||||
holds is of a type that reaches an object list, and a file already declared `v3` stays
|
||||
`v3` when a writer merges onto it. A directory store's manifest says
|
||||
`cultcache.store.v5.directory-content-addressed-pages` under the same rule, and
|
||||
`v4` otherwise.
|
||||
|
||||
## Variant Records
|
||||
|
||||
|
|
@ -236,17 +243,42 @@ fifth slot:
|
|||
`elementId` is `""` unless the step enters an object-list element. `value` is the
|
||||
member's own MessagePack encoding, inline. A top-level Set has one step and `id` `""`;
|
||||
a reader that resolves only that shape refuses the others, naming the variant.
|
||||
- A store holding at least one variant declares `cultcache.store.v2`; a store holding
|
||||
none declares `cultcache.store.v1` and is byte-identical to what a runtime without
|
||||
variants writes. A `v1` header over a variant record is refused.
|
||||
- A store holding at least one variant declares `cultcache.store.v2` (`v3` when it can
|
||||
hold element ids); a store holding none declares `cultcache.store.v1` (or `v3`) and is
|
||||
byte-identical to what a runtime without variants writes. A `v1` header over a variant
|
||||
record is refused.
|
||||
- A variant's resolved document is derived in memory when the cache admits the record
|
||||
or any record on its base chain, and is never written back. A plain write at a
|
||||
variant's key is refused; `Flatten` replaces a variant with a plain record holding its
|
||||
resolved document.
|
||||
- The C# runtime resolves variants. Every other runtime refuses a `v2` store by name.
|
||||
- The C# runtime resolves variants. Every other runtime refuses a `v2` store by name, and
|
||||
refuses a variant record inside a `v3` store by its record key.
|
||||
CultMesh single-file reads, the directory store and CultNet refuse a variant record by
|
||||
name until each has its own cut.
|
||||
|
||||
## Element Ids
|
||||
|
||||
Every object that sits in a list, array or dictionary value of a registered document
|
||||
type, union subtypes included, carries an id: one string member with an integer `[Key]`
|
||||
and `[CultElementId]`. The id identifies the element inside its list, so an override can
|
||||
name it (a path step is `[slot, elementId]`) and a base edit that reorders or inserts
|
||||
elements retargets nothing.
|
||||
|
||||
- A random id is 12 lowercase hex characters. A derived id
|
||||
(`[CultElementId(nameof(Source))]`, for content-addressed elements) is the
|
||||
invariant-culture text of its source member, which must be non-empty; it needs no
|
||||
other format. An id is unique within its list.
|
||||
- A write mints random ids for unset elements, including inside variant override
|
||||
values, and refuses a duplicate, a malformed random id or an empty derived source. A
|
||||
load refuses the same things, naming the record, the list and the id. A record
|
||||
written before ids existed loads, and its ids are minted from SHA-256 of the record
|
||||
key and the element's path, so every reader mints the same ids; they reach disk with
|
||||
the record's next write, or `CultCache.MintElementIds()`.
|
||||
- A store that can hold ids declares the `v3` header (above), so a reader older than ids
|
||||
refuses it instead of skipping the id slot and rewriting the elements without ids.
|
||||
TypeScript, Python and Rust read `v3` and keep a `v3` header they found when they
|
||||
rewrite a store; they do not decide when a document carries ids.
|
||||
|
||||
## Canonical Semantic Schema Hash
|
||||
|
||||
`schemaId` should be derived from a canonical semantic schema hash.
|
||||
|
|
|
|||
Loading…
Reference in a new issue