cultcache-ts: the payload nesting bound (256) in the one document-payload owner, so every TS payload door shares it

checkPayloadDepth is an iterative header walk run by decodeDocumentPayload before the formatter and by
encodeDocumentPayload on the formatter's bytes; the two plain-decode inspection doors call it first. The plain
formatter's encoder depth is set above the limit so the walk decides. Tests: the C# bounds vectors, the walk's
header and scalar rules, the owner, the inspector, the legacy version inference, and the mesh network doors;
test:pack:ts denies decoder-shaped exports by enumerating the packed entries.

Builds and passes untested at this commit (verification runs on Yggdrasil next).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-12 00:01:59 +02:00
commit b69d3057a5
10 changed files with 446 additions and 15 deletions

View file

@ -84,10 +84,19 @@ const mesh = require("cultmesh-ts");
assert.equal(typeof cache.defineDocumentType, "function");
// The document owner is also an entry of its own, which the browser client imports without the Node-only cache.
assert.equal(documentEntry.decodeDocumentPayload, cache.decodeDocumentPayload);
assert.equal("resolveDocumentFormatter" in cache, false);
assert.equal("resolveDocumentFormatter" in documentEntry, false);
assert.equal("codecFormatter" in cache.codecs, false);
assert.equal("codecFormatter" in documentEntry, false);
// No entry exports a decoder or formatter that reads a payload around its schema: by shape, every packed export whose name
// says it decodes, reads a wire or formats is enumerated, and the only one allowed is the schema-checked owner.
const inspection = require("@gamecult/cultcache-ts/inspection");
const decoderShaped = (entry) => Object.keys(entry).filter((name) => /decode|formatter|readwire/i.test(name)).sort();
for (const [entryName, entry] of Object.entries({ root: cache, codecs: cache.codecs, document: documentEntry, inspection })) {
const found = decoderShaped(entry);
const allowed = entryName === "root" || entryName === "document" ? ["decodeDocumentPayload"] : [];
assert.deepEqual(found, allowed, "decoder-shaped exports of the " + entryName + " entry");
}
assert.equal(typeof documentEntry.checkPayloadDepth, "undefined");
assert.equal(documentEntry.MAX_PAYLOAD_DEPTH, 256);
assert.equal(cache.MAX_PAYLOAD_DEPTH, 256);
assert.equal(documentEntry.CultCachePayloadDepthError, cache.CultCachePayloadDepthError);
assert.equal(typeof net.CultNetPeer, "function");
assert.equal(typeof mesh.CultMesh, "function");
assert.equal(typeof mesh.CultMeshProviderSession, "function");