Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

0036: Copied reference relocation

Context

RFC 9880 Section 4.4 copies a referenced definition and applies the composition patch through JSON Merge Patch. It does not say what name references inside the copy mean afterwards. Sections 4.3 and 4.4.1 also leave open whether a name reference selects an element of the document as written or of its resolved model. Reusable Objects commonly require their own declarations through absolute pointers such as #/sdfObject/alarm/sdfProperty/status, so reusing one through sdfRef copies a pointer to the source’s coordinates.

Decision

Esdieff adopts this RFC interpretation as copied-reference-relocation/1, following ADR 0002: Recorded standards baseline.

A copied reference keeps the document and namespace mappings of the definition that authored it. When its target, read in that context, is the copied definition or lies beneath it by decoded JSON Pointer tokens, it is an internal copied reference. It relocates to the corresponding position in the importing definition. This applies to same-document and CURIE forms alike and at every copy boundary, including a target’s root chain and nested copies. Other copied references keep their original target. Relocation starts from the target the reference has in its authoring context, so a copied reference whose target is missing there stays missing in every copy, even when the importer declares something at the corresponding position.

A reference written in a composition patch belongs to the importing author and uses that author’s context, even when its text equals the inherited one. Only the sdfRef member or sdfRequired array actually written in the patch counts. Patching sibling qualities leaves a copied reference copied.

Every name reference selects the element at its pointer in the target document’s resolved model. An importer can therefore reference and require declarations that exist only through a copy. A relocated target that a patch deleted is missing, as for any other reference, under ADR 0006: Scoped reference failures and ADR 0020: Owned effective views and nearest origins. Nothing falls back to the source definition. Cycles created by relocation or by composing a pointer’s path are scoped failures.

Composing a pointer’s path is an exception to the explicit frames of ADR 0020: Owned effective views and nearest origins. A lookup composes a definition on its path, and that composition can need another lookup through another composed definition, so nested path compositions recurse. Each nested composition is reused for the rest of the operation, and the nesting stops at a fixed bound of 32 levels, or at the reference depth when that is lower. Exceeding the bound leaves the affected result undetermined with operation.limit, following ADR 0009: Bounded processing and reporting. The bound is a supported stack limit rather than an allowance, and raising the reference depth does not raise it. Recursion keeps lookup on the existing composition steps, while explicit frames would need a resumable lookup inside every expansion. Ordinary models nest only a few levels, and 256 levels of recursion can exhaust a 2 MiB thread stack.

Copied sdfRequired pointers relocate by coordinate. A relocated pointer selects the declaration at that coordinate in the resolved model, with its own Declaration contribution under ADR 0026: Required declaration relationships and source evidence. A deleted declaration leaves the relationship missing, and a reinserted one is selected as a new contribution. Referenceable names and true entries keep their carrier-relative meaning. Boolean and short-name sdfRef keep no processing meaning.

baseline.interpretations lists the identifier whenever a result relied on this interpretation. That is when requested work relocated a copied reference, read a copied CURIE reference with its authoring document’s namespace mappings, or found that a name reference target in the resolved model differs from the document as written, including a target that composition removed. Reports that did none of these omit it.

Considered Options

Binding a copied reference to its source target keeps the source’s constraints and ignores the importer’s refinement of the very data its copy uses. Reading inherited pointers literally in the importing document selects unrelated lookalike definitions, or nothing. Requiring authors to restate every inherited reference breaks reuse of ordinary models that require their own declarations by pointer. Keeping copied references undetermined left that common reuse incomplete, and an opt-in switch would keep that default while doubling the tested behaviour. String prefix matching would treat a sibling such as BaseExtra as inside Base. Limiting resolved-model lookup to sdfRequired or to same-document pointers would let two spellings of one global name disagree. Classifying a reference by the map that holds it would let an unrelated sibling patch silently rebind it. Relocating by pointer structure alone, even when the source lacks the target, would make one copied reference broken in its source yet valid in each importer that happens to declare the missing element. Recording the identifier only for relocation and composed-only targets left passing results that read a copied CURIE in its authoring context, and missing targets that composition removed, without naming the reading they rely on.