--- type: rule summary: Never implement anything that diverges from NextGraph — ask "does the target do this?" first, and only then how badly a caller would be misled --- # No divergence from NextGraph **Rule:** Never implement anything that diverges from NextGraph. At every choice — a published signature as much as an internal mechanism — the **first** question is *does the target do this?* Verified in `nextgraph-rs`, or stated by its author. If the target does it differently, we do it their way, whatever that costs. Only where the target answers nothing at all do we invent, and then deliberately, documented, and named as a bet. "Known" is narrow: read at the source, or stated by its author. Never inferred from what an npm package happens to expose, and **never inferred from an absent implementation** — *"the engine does not do X"* says nothing about whether the target will. **A definition is a fact; its being unwired is an absence.** The two arrive together and the absence is the louder one, which is how it wins arguments it should lose. A type the target has declared but nothing constructs yet is the *strongest* thing to align on — implementing it is not inventing, it is realising a shape the target wrote down. Read the declaration and let the silence around it say nothing. That distinction has its own place in the taxonomy below, because collapsing it into "invention" makes us believe we are further from the target than we are — and then a later reader, seeing "our own idea", feels free to change it. **The second question measures gravity, not permission:** *would an application coding against this have to unlearn it?* Use it to rank what to fix first, and to judge an unavoidable divergence. Never use it to authorise one. **Why the order matters — it is the failure this rule was rewritten for.** `readUnion` folded every triple of a document into one bag keyed by the document, so two entities written under two subjects came back merged and one written under another subject came back relabelled, silently. Asked the second question first, the answer was ambiguous: *one entity per document* is good placement practice anyway, so what exactly would a caller unlearn? The reasoning stalled there for hours. Asked the first question, it took one look: level 1 returns real subjects, and level 3's ORM carries `@id` **and** `@graph` on every object and generates the former when omitted — several objects per graph is the designed case. Divergence, done, no debate about perception. Earlier instances, all of the same shape: *"every document has a native inbox"*, written from general reasoning, false, and already an implementation; and a per-document inbox pointed at its owner's inbox to absorb a measured cost, emulating a many-to-one relation the target cannot express. **The pressure to deviate never announces itself as one.** It arrives as a cost, a latency, an ergonomic wrinkle — all real, all legitimate. That disguise is what makes it dangerous. When shape and cost conflict: keep the shape and attack the cost elsewhere (the lever is usually *who* pays and *when*). If the cost is genuinely unsolvable, say so rather than bending the model quietly. **How to apply.** The tells, each of which has produced a real hole here: - **A recommendation enforced by the code.** Ours may guide placement; it may not make the other arrangement invisible. A read path that silently normalises what it did not expect is the signature. - **A symbol that makes the caller handle what the target will never hand it** — a document's key, an inbox address, a store id, its own identity. - **A named exception stops being one the moment it is published.** A door documented as *"only this internal caller uses it"* is a door any application can open; the note is not a mechanism. Move it out of the published surface instead. - **A symbol kept because it was already there is not a decision.** At every surface change, re-ask whether an application still needs each neighbouring symbol. When a divergence is genuinely unavoidable it must be **deliberate, documented and invisible to the caller**. What is forbidden is the silent one, adopted because it was convenient. ## Every symbol says where it comes from Answering *does the target do this?* once, in conversation, does not survive the week. So each symbol carries its own provenance, beside the code rather than in a document that drifts: the **level** that answers (1 the engine, 2 the binding, 3 the ORM), the upstream `path:symbol` it aligns on, and one of five kinds. | kind | meaning | |---|---| | `passthrough` | upstream's own symbol, same name and shape | | `aligned` | our name or ergonomics, upstream's semantics and model | | `declared-not-wired` | upstream **defines** the shape; nothing constructs it yet; we implement it | | `invention` | nothing at any level answers — a deliberate, documented bet | | `divergent` | upstream does this, and we do it differently | A test requires the annotation on every published symbol; it cannot check that the citation is *true*, and that is fine — a citation is refutable by a reader in seconds, prose is not. The classification also applies to unpublished code that **claims to resemble the target**: the mistake this section exists for was made on an internal function, and being unexported protected nobody. **Why this exists.** A maintainer read that `AddLinkV0` is defined upstream but constructed nowhere, and reported our implementation of it as our own invention — reasoning from the absence while quoting, in the same session, the rule against exactly that. The correct reading was `declared-not-wired`, which is the best alignment available. Prose said otherwise elsewhere too: `docs/api-contract.md` claimed `docs.*` was a 1:1 passthrough while two of its signatures diverged, and stated a member count that was simply wrong. Both errors are the same one — a claim about the target that nothing forced anyone to check.