Contracts: the id walk follows declared types; keyed structs, every map interface and AllowPrivate named

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-15 01:24:35 +02:00
commit 8bbe56f555
2 changed files with 13 additions and 5 deletions

View file

@ -408,8 +408,9 @@ fifth slot:
## 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]`
Every object that sits in a list, array or dictionary value (`IDictionary<,>` or
`IReadOnlyDictionary<,>`) of a registered document type, or of a keyed struct a document
holds, 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.
@ -432,7 +433,13 @@ elements retargets nothing.
store; they carry ids and do not decide when a document carries them.
- An object list's elements are written by their `[Key]` layout, because the id is a
keyed member of the element. A list whose element type is not keyed
(`[MessagePackObject]` or `[Union]`) is a value list and is replaced whole. For an
(`[MessagePackObject]` or `[Union]`) is a value list and is replaced whole; so is a list
of keyed structs, since a struct is a value and never an element, but an object list
inside a keyed struct is walked like any other. The walk follows declared member types:
a member declared `object` is untyped on disk, and a subclass's extra members under a
non-union base-typed member are not written, so neither is walked. A non-public `[Key]`
member on the way to an object list is refused at registration, because MessagePack
writes it only under `AllowPrivate` and the element-id walk reads public members. For an
object list, C# refuses at registration a concrete element type that is not keyed and
`[MessagePackFormatter]` on any type, collection type or member on the way to the list or on the id
member, and refuses at the first encode or decode of the document a formatter

View file

@ -299,8 +299,9 @@ exclusive open of the same lock file exclude each other is not established.
the walk passes (`List<T>`, `T[]`, a collection class, a dictionary on the way).
Those are written by their `[Key]` layout so each element's id reaches disk, and the
codec refuses the document on first encode or decode, naming the resolver and the
type. A resolver that returns MessagePack's standard formatter for a type does not
claim it. A value list (`List<float2>`, a list of a non-keyed class) is not on the
type. The formatter `StandardResolver` or `StandardResolverAllowPrivate` hands out for a
type does not claim it (registration refuses a non-public `[Key]` member on the way to
an object list, so the private-member formatter writes every id). A value list (`List<float2>`, a list of a non-keyed class) is not on the
path, so a resolver may claim it.
- Deserialization runs under untrusted-data security. `CultRecordRef<T>` is a
permitted dictionary key, compared by its key string.