Repository navigation
Description
A Like parsed from valid standalone JSON-LD can make an OrderedCollectionPage invalid when it is embedded in the page. The page's default toJsonLd() output retains the item's context but adds a parent context with protected terms that the item redefines. Parsing the resulting page fails with protected term redefinition.
This surfaced while serving saved activities in fedify-dev/drfed#177. It also occurs with ordinary Fedify vocabulary objects, without a custom toJsonLd() override or a database. In an outbox, one such item prevents a JSON-LD client from parsing the whole page, including its other activities.
Reproduction
Tested on Node.js 26.12.1, Linux x86_64, with the published @fedify/vocab 2.4.3 package. In an empty directory, run:
npm install @fedify/vocab@2.4.3Save this as repro.mjs and run node repro.mjs:
import { Like, OrderedCollectionPage } from "@fedify/vocab";
const AS = "https://www.w3.org/ns/activitystreams";
for (const [name, context] of [
["control", AS],
["custom proof", [AS, { proof: "https://example.org/proof" }]],
]) {
const like = await Like.fromJsonLd({
"@context": context,
id: "https://example.com/likes/1",
type: "Like",
object: "https://example.net/notes/1",
});
const page = await new OrderedCollectionPage({
id: new URL("https://example.com/outbox?page=1"),
items: [like],
}).toJsonLd();
try {
await OrderedCollectionPage.fromJsonLd(page);
console.log(`${name}: OK`);
} catch (error) {
console.log(`${name}: ${error.details?.code ?? error.message}`);
}
}Actual output:
control: OK
custom proof: protected term redefinition
Both standalone inputs pass Like.fromJsonLd(), and both page serializations complete. Only parsing the page containing the custom context fails. The proof property need not appear in the item; the context definition alone triggers the error.
Expected behavior
Both pages should remain valid JSON-LD and be readable through OrderedCollectionPage.fromJsonLd(). Embedding a parsed item should preserve its meaning without introducing a conflicting inherited context. A regression test should parse the serialized page, since checking the returned JSON or an HTTP status alone does not catch this.
Context composition and #1356
The default serialization path in packages/vocab-tools/src/codec.ts embeds each item's default toJsonLd() output and assigns the page's default context. That parent context includes https://w3id.org/security/data-integrity/v1, which protects proof. The cached child document retains its different definition of proof, so the combined document violates the protected-term rules in JSON-LD 1.1.
#1356 fixes a related cache problem: inherited parent contexts were being added to an embedded child's cached source, affecting proof verification. Its later decoder change avoids reparsing the child separately. Those changes preserve a child extracted from an existing document; this case instead combines an independent child with a new parent context.
The failure was also reproduced against #1356 at 935df52. Its existing embedded objects keep their cached JSON-LD as received regression test passes, while the reproduction above still fails. This report concerns context composition during serialization, not the raw-property read API.
Drafted and reproduced with assistance from Codex; prose reviewed with Claude Code.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Effort
Activity
Parse outbox pages in a test for fedify#1394
Isolate cached JSON-LD child contexts