Map: claimant-one-owner r2 body facts (one description of the written type decides ownership)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
fc74cf6f41
commit
be12d75a01
1 changed files with 88 additions and 0 deletions
|
|
@ -351,3 +351,91 @@ settled cache's gate. Results:
|
|||
cache `a`. That is true before, during and after an attach, so it is not the window's
|
||||
two-fact problem. Closing it changes public API (a store's writes taken only from its
|
||||
cache), so it is a follow-up and an operator question for Self, not part of this cut.
|
||||
|
||||
## Body facts: claimant-one-owner r2 (Imagination, 2026-10-27, base fc74cf6f)
|
||||
|
||||
Why a revision: Soul beat the same rule three times (s1 claimant choice, s2 compatible ids, s3 shape). Each time a
|
||||
cacheless write lent a registry let the registry's entry for the written schema id decide ownership beside the entry
|
||||
the caller passed. Two descriptions of one type reached `Owns`; each fix (h2 schema-id compare, h3 subset of compatible
|
||||
ids) compared one more facet of the two and left the rest open. r2 removes the second description from the lookup.
|
||||
|
||||
### Where the two descriptions met (source read, fc74cf6f)
|
||||
|
||||
- `OwnsOnDisk` cacheless arm (`CultCache.cs:4725-4740`): with a lent registry it called
|
||||
`lent.Owns(id, catalog, declared, written)`, whose lookup is the registry's `_indexes` and whose `entryOf` is
|
||||
`descriptor.ToCatalogEntry()` (`:824-825`). The claimant for the written schema id was the registry's descriptor,
|
||||
so `ReadsWhole(persisted, claimantEntry)` (`:848`) judged shape against the registry's entry, and the claimant
|
||||
precedence (`:756-806`) walked the registry's compatible ids. `written` (`:4734-4736`) then compared the two entries
|
||||
by schema id plus a subset of compatible ids.
|
||||
- `WriteDocument` (`:4495-4524`) takes its entry from the registry (`resolvedRegistry.GetRequired<TDocument>().ToCatalogEntry()`),
|
||||
so its two descriptions are always identical. Only `WriteRecord(record, catalogEntry, holdsIds, registry)` (`:4471`) can
|
||||
pass an entry that disagrees with the registry's entry for the same id.
|
||||
- `CopiedHoldIds` (`:4600-4630`) also reads `AttachedRegistry`, to decide the v3 header from copied records. It is a
|
||||
positive-only header decision, not ownership, and out of this cut.
|
||||
|
||||
### Consumer audit (2026-10-27)
|
||||
|
||||
- `WriteRecord` and `WriteDocument` are new in the Unreleased 3.0.0 entry; `main` has neither (`git show main:src/GameCult.Caching/CultCache.cs`).
|
||||
- Per-repo `rg` over every git repo directly under `F:\Projects` for `.WriteRecord(`, `.WriteDocument(`, `WriteSingleFileDocument`
|
||||
(Library, obj, bin, PackageCache excluded): hits only in CultLib and in vendored CultLib copies under Heimdall and StreamPixels
|
||||
(`vendor\CultLib`, older pins without these methods). No consumer outside CultLib calls either method.
|
||||
- Inside CultLib at fc74cf6f: Mesh `WriteSingleFileDocument` calls `WriteDocument(key, document, storedAt, registry)`;
|
||||
Mesh's raw-payload path calls `WriteRecord(..., registry: null)` (`CultMeshSingleFileDocuments.cs:129, 226`). The only
|
||||
`WriteRecord` calls with a registry are tests: `CachelessSingleFileTests.cs:453, 660` (a registry `{IdDeck}` that does
|
||||
not hold the written entry `One` at all, used for the copied-record header), `RestampOnWriteTests.cs:595, 599`, and
|
||||
Soul's probes. Packages: no TS, Python or Rust counterpart takes a registry (cultnet-rs `write_record` is an example helper).
|
||||
- Consequence: the registry's documented role in `WriteRecord` is to describe the other records in the store. A shape
|
||||
that derives the written entry from the registry (or refuses an entry the registry does not hold) breaks
|
||||
`CachelessSingleFileTests.cs:660` and removes that role.
|
||||
|
||||
### Candidate shapes weighed
|
||||
|
||||
| Shape | One description? | Public API | Kills s2/s3 | Cost |
|
||||
|---|---|---|---|---|
|
||||
| A. Lent registry's entry decides; refuse a passed entry that disagrees | yes, after a door check | signature kept; new refusal | yes | an equality check over a redundant parameter; breaks the registry-describes-others use (`:660`) when the registry lacks the written type unless it falls back to the passed entry, which is two descriptions again |
|
||||
| B. Passed entry is the only description of its schema id; the registry supplies other types only | yes, by construction | signature kept; doc only | yes (probed) | one lookup class gains the registry; one registry overload deleted |
|
||||
| C. Overloads: `WriteRecord(record, catalogEntry, holdsIds)` and `WriteRecord(record, registry, holdsIds)` | yes, by type | changes a 3.0.0 signature | yes | loses the registry-describes-others use |
|
||||
| D. Delete `WriteRecord`'s registry parameter | yes | changes a 3.0.0 signature | yes | loses the copied-record header decision for raw writes |
|
||||
|
||||
Picked B. It is the only shape that keeps every documented use of the registry, needs no public signature change,
|
||||
and deletes the comparison instead of extending it. It is ordinary scoping (an inner binding shadows the outer one
|
||||
for its name), applied to schema ids.
|
||||
|
||||
### Probes (Starfire, local filtered runs, 2026-10-27)
|
||||
|
||||
Scratch clone of fc74cf6f at `<scratchpad>/imagination-claimant-r2/clone`, Soul's `SoulClaimantProbe.cs`,
|
||||
`SoulClaimant2Probe.cs`, `SoulClaimant3Probe.cs` copied into `tests/GameCult.Caching.Tests`.
|
||||
|
||||
Base fc74cf6f (`probe-base.log`):
|
||||
- P7 (registry {N lists own, A, B}; passed entry N with the list varied; record k under O, named like N): lent R / no
|
||||
registry C for rows b, b2, e, g, h, k, l, l2; lent C for a, c, d, f, i, j. Confirms `subset-refuses-own-drift`.
|
||||
- P9 (registry {NW: Name, Value, Colour}; passed NW minus Colour): lent C (restamped, Colour lost), no registry R.
|
||||
Confirms `lent-shape-widens-passed-entry`.
|
||||
- P6 (bare X1 entry, registry {X1} listing OX, record under OX): lent R, no registry R, cache C. h3 closed the id axis.
|
||||
- P4: 12 states x 8 registries, violations=0. P1d: a cache {N,L} commits N over L's listed old id (`cache-replaces-other-types-record`).
|
||||
|
||||
Prototype B (scratch commit 349ea3f3 on the clone, not for landing; `probe-protoB2.log`): `CatalogEntryLookup` takes
|
||||
the written entries and an optional registry and drops every registry descriptor whose schema id a written entry has;
|
||||
the registry's `Owns(schemaId, catalog, declared, mayClaim)` overload is deleted; the cacheless arm always asks
|
||||
`CultDocumentRegistry.Owns(id, catalog, declared, new CatalogEntryLookup(writes, AttachedRegistry), entry => entry,
|
||||
claimant => writes has claimant's schema id)`.
|
||||
- P7: lent == no registry on all 14 rows (all C).
|
||||
- P9: lent R, no registry R, wide entry C.
|
||||
- P6: unchanged (R, R, C). P4: identical table to base, violations=0. P1a-f, P2a-d: identical to base.
|
||||
- `RestampOnWriteTests`, `CachelessSingleFileTests` and the probes: 139/139 passed locally.
|
||||
- Yggdrasil, 349ea3f3, `ygg-protoB-full.log`: GameCult.Caching.Tests 1180 passed / 0 failed / 2 skipped;
|
||||
GameCult.Mesh.Tests 342 / 0 / 4.
|
||||
|
||||
Negative greps, each tested at fc74cf6f (each matches there, and none may match after the cut, src and tests):
|
||||
`claimant.CompatibleSchemaIds.All(` (1, the subset), `lent.Owns(` (1), `Func<CultSchemaCatalogEntry, bool> mayClaim) =>`
|
||||
(1, the deleted overload), `CatalogEntryLookup(writes)` (3, one-argument construction). CHANGELOG and docs:
|
||||
`never widens what the passed entry declares` (1), `with no compatible id the passed entry does not list` (1).
|
||||
|
||||
### Not settled by r2
|
||||
|
||||
- `cache-replaces-other-types-record` (s2, PreExisting, cache arm): r2 touches only the cacheless lookup, so it does
|
||||
not settle whether a cache may replace another registered type's record at a shared key.
|
||||
- Whether a registry-less `WriteDocument` should consult `CultDocumentRegistry.Shared` for claimants at all (s1
|
||||
`shared-decides-registryless-write`, closed Fixed by documentation in h2). r2 keeps today's answer.
|
||||
- `variants:finding:cut-restamp-on-write.s2.cacheless-inverts-registry-claimant` is still in force although r1 was
|
||||
mapped to close it; Self should close or re-triage it after r2's Soul pass.
|
||||
|
|
|
|||
Loading…
Reference in a new issue