From 115bc0a249b7e137c43bab963ab11f4f637fe754 Mon Sep 17 00:00:00 2001 From: Libby Date: Wed, 11 Nov 2026 23:58:11 +0000 Subject: [PATCH] CHANGELOG (org.gamecult.cultlib, Unreleased): extra slots are read-only (Breaking); IsWritable, CultUnreadSlots (Added) Behavioural break per docs/semver-policy.md (tightens the soft-drift classification; writes that succeeded now refuse). ApiCompat against cultlib-unity-v3.0.0 measures no signature break. Co-Authored-By: Claude Opus 5.5 --- unity/org.gamecult.cultlib/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/unity/org.gamecult.cultlib/CHANGELOG.md b/unity/org.gamecult.cultlib/CHANGELOG.md index 225bb3ae..c2fc2a1f 100644 --- a/unity/org.gamecult.cultlib/CHANGELOG.md +++ b/unity/org.gamecult.cultlib/CHANGELOG.md @@ -7,6 +7,12 @@ All notable changes to this package are documented in this file. ### Breaking - A single-file store holding two records under one key is unreadable: the reader refuses it with `CultStoreUnreadableException` naming the key (keys compare by ordinal code units, no case folding or normalisation), so a cache, `ReadStoreSnapshot` and a flush refuse the file and leave it as it is. Before, the later record silently replaced the earlier. A directory store reads its manifest through the same reader and refuses a duplicate key the same way. Repair the duplicate with the runtime that wrote it before reading the store here. +- A record whose payload carries a slot past the slots its reading type declares, at any depth (the record, a nested object, a list element, a union arm or a unit arm), is loaded read-only: it is served, and every staged write or removal of its key (`Upsert`, `UpsertVariant`, `Remove`, a batch, and `Flatten` of a variant) is refused with `CultSchemaConflictException` before anything is staged, and the store keeps the record byte for byte. Before, the extra slots were skipped on read and dropped on the next write. Declaring an id compatible consents only to depth-0 slots the schema comparison reports ignored under that id; any other extra slot keeps the record read-only whatever is declared, including under the reader's own id. A variant overriding a slot its type does not have is read-only too (it used to be shed on flush). Write such a record from the build that declares those slots. Missing trailing slots still default and stay writable. + +### Added + +- `CultCache.IsWritable(CultRecordKey)`: whether a write or removal of the key would be let through, answered by the same predicate the write uses (false for a foreign record, undeclared drift that drops slots, or unread slots; true for a key no store holds). Live and advisory: the write still decides. +- `CultUnreadSlots` (`TypeName`, `SlotCount`, `DeclaredCount`, `Occurrences`, `Explained`), `CultStoredDocument.UnreadSlots`, and `CultSchemaConflictException.UnreadSlots` with its constructor overload: what a load found past the reader's slots, holding no slot value. The refusal message names the type and both counts, never a value. ## [3.0.0] - 2026-11-11