Skip to main content
Declared with capabilities.materialize = true. All three functions are required, and registration refuses the capability without any of them. This is what migration and cross-server deployment run on.

PrepareMaterialize

Phase 1. Answers every question that can be answered without writing. Is this record mine? Is the target usable? Is the model installed? It is called for previews, so it runs often and must be cheap.
accepted
Optionally with orientation, preview and warnings.
refused
Requires code ("unsupported" or "invalid") and a non-empty reason. A bare { ok = false } is a contract failure, not a refusal.
Phase 1 never writes, and never throws. A thrown error is a contract violation, not a refusal. Blueprints contains it, names you and fails the operation, but you are at fault.
It must also not mutate the source record it was given. That record is a defensive copy and is read-only.

preview

An optional tagged union describing what to draw as a ghost:
Returning nothing is fine. An adapter that offers no preview gets a point marker, silently. Most domains have nothing to draw and that is not a mistake. kind is required when you do return one. Omitting it is not treated as “model with no model”: an adapter that forgot the field and an adapter whose domain has no model need different answers. Numbers are clamped rather than trusted: radius to 1 to 512, skin to 0 to 255, coordinates to the world half-extent, and a model path is validated. A value outside those is corrected silently. A malformed descriptor (a bad model path, mins above maxs, an unknown kind) is downgraded to a point marker with a warning naming your adapter, never refused: a cosmetic mistake must not block a migration.
An adapter never sends a function, a material, a colour or a render callback to a client. A public SDK that let a third party run code in every admin’s client would be a different product with a different threat model.Colour stays the client’s status vocabulary (ready, skipped, unsupported, invalid), which the admin relies on to judge the operation.

warnings

Shown to the admin and does not block. Use it for anything cosmetic or recoverable; use { ok = false, code, reason } for anything that will not work.

Materialize

Phase 2. Creates exactly one object, or none.
Return a NEW identity, never the source’s.The rebuilt object is a different object from the one the Version describes. Reusing the id would make a migration’s target indistinguishable from its source, and a restore would then reconcile one against the other.
identity is required, and its source and scope must come from the declared vocabularies. Returning just ok and localId is a contract failure.

transform may be nil

If your records carry no transform, neither does the argument. An adapter for a positionless domain that indexes transform.pos errors on every real create, so guard it:

ReleaseMaterialized

Undoes exactly one materialization from the running operation. It is not a general delete.
Without it, an all-or-nothing group materialization becomes a lie the moment a later member fails. That is why registration refuses materialize without it.
It must leave the world exactly as it was found, by object count. An adapter that creates one thing and releases something else is the failure this function exists to prevent.
Note it takes no ctx argument, unlike the other two.

Where this is used

Post-restore verification asks PrepareProperties for an adapter that declares properties, and PrepareMaterialize otherwise. If you declare both, return your orientation from both.