CultMesh TS: a node's returned documents belong to its cache

Soul F8 (M6, M7 survived): node.get, getRequired and put return the
object the cache holds, as C# and Python do (Rust copies). That is the
behaviour that ships.

- The README says the returned object belongs to the cache and must not be
  mutated, and shows the put-a-new-value pattern.
- A test pins it: two reads return the same object, put resolves to that
  object, and the caller's own value is never the one held.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-30 19:49:57 +02:00
commit 852ea0fe1a
2 changed files with 32 additions and 0 deletions

View file

@ -108,6 +108,20 @@ reactive.update(draft => {
});
```
`node.get`, `node.getRequired` and the value `node.put` resolves to return the
object the node's cache holds, not a copy: two reads of one record return the
same object. That object belongs to the cache and must not be mutated. Mutating
it changes what later reads see without writing anything to the store. To
change a document, build a new value (or use a writer) and put it:
```ts
const held = station.getRequired(stationStockDocument, "station:starbridge:stock");
await station.put(stationStockDocument, "station:starbridge:stock", {
...held,
availableMissiles: held.availableMissiles - 4,
});
```
State pointers are the same kind of managed surface for UI and tools. They can
advertise source documents, inherit a Verse route when bound, and resolve
through that Verse without caller-side context plumbing:

View file

@ -3074,6 +3074,24 @@ test("CultMesh TS reads remote RUDP snapshots through document handles", async (
}
});
// What ships (F8): a node's reads and puts return the object its cache holds, not a copy, and the README says that object
// belongs to the cache. The caller's own value is never the one held.
test("CultMesh TS node reads and puts return the cache's own object", async () => {
const node = await CultMesh.startNode(
join(await mkdtemp(join(tmpdir(), "cultmesh-ts-held-object-")), "node.ccmp"),
{ documents: [noteDocument] },
);
const written = { noteId: "note:held", body: "held" };
const put = await node.put(noteDocument, "note:held", written);
assert.notEqual(put, written);
assert.deepEqual(put, written);
assert.equal(node.get(noteDocument, "note:held"), put);
assert.equal(node.getRequired(noteDocument, "note:held"), put);
assert.equal(node.get(noteDocument, "note:held"), node.get(noteDocument, "note:held"));
written.body = "changed by the caller";
assert.equal(node.getRequired(noteDocument, "note:held").body, "held");
});
test("CultMesh TS syncs remote RUDP snapshots into a local node", async () => {
const connectionId = 0x1020304a;
const source = await CultMesh.startNode(