Skip to content

Retract, Rename & Schema Changes

WarmHub never destroys data. You retract things instead of deleting them, you rename things in place, and you evolve shapes over time. Each of these changes ripples outward to the wrefs, assertions, and collections that point at what you changed.

This page covers exactly what happens to those references in each case. It assumes you already know things, wrefs, and assertions.

ChangeNew version?Effect on references
Retract a thingYes — a retract versionNone — references keep pointing at the preserved version
Rename a thingNo — an in-place identity editIdentity-pinned references follow it; a wref using the old name breaks
Revise a shapeYes — a new shape versionNone — existing things are unchanged until their next write
Retract a shapeYes — a retract versionNone — things validated against it still resolve

The throughline: assertions and collections pin the exact version they referenced, so a retraction or a rename can never orphan them. Only a wref that addresses a thing by its name is fragile, and only across a rename.

Retracting a thing marks it inactive. Its name, data, and full version history are preserved, and it is hidden from default queries. Retraction is the only way to make something inactive — there is no hard delete. See Operations — Retract for the operation itself and Things — Active/Inactive Lifecycle for the lifecycle.

What retraction does not do is cascade. Retracting a thing leaves everything that points at it in place:

Reference to the retracted thingWhat happens
Its own wrefHidden from default reads and listings — a plain wh thing view Location/cave returns not-found. Its data and full version history are preserved and stay readable with --include-retracted or a pinned @vN version.
An assertion about itUntouched. The assertion still resolves and still points at the exact target version it was pinned to when created.
A collection that includes itUntouched. The collection keeps its version-pinned member reference, which still resolves to that member version. No dangling reference, no new collection version.
A subscriptionA retract is a write operation, so a subscription whose filter matches retract fires on it. See Subscription Filters.

Because assertions and collections pin the exact version they referenced, a retraction can never orphan them — they keep pointing at a version that still exists.

Renaming changes a thing’s name in place — wh thing rename Location/cave cavern (the new name is bare; the shape stays the same), or client.thing.rename in the SDK. It does not create a new version, a commit, or a history entry, and there is no record of the old name afterward.

That makes the rule simple: references that point by identity follow the rename; references that use the old name break.

Reference to the renamed thingWhat happens
An assertion about itFollows the rename. Assertions link to their target by identity, so reading the assertion — or querying what it is about — resolves to the thing under its new name automatically.
A collection that includes itFollows the rename. Collection members are pinned by identity, so the member resolves to the new name automatically. Nothing dangles.
Its durable idUnaffected. A durable id names a thing by identity, so it survives every rename.
A wref that uses the old nameBreaks. The old name no longer resolves — a lookup returns not-found. There is no redirect from the old name to the new one.
A subscriptionNot re-evaluated. A rename is not a write operation, so it never triggers subscription matching (see below).

Shapes rename the same way: wh shape rename (or client.shape.rename) patches the shape’s name in place, preserves its history, and creates no new version. Things keep validating against it, because they reference their shape by identity.

Subscriptions match write operations as they happen — an add, a revise, or a retract carrying a name, shape, and kind. A rename is not a write operation, so it produces nothing for a subscription to match.

The practical consequence: renaming a thing into or out of a subscription’s name pattern — a glob match like Product/electronics/** — does not notify subscribers. The renamed thing matches that subscription again only the next time it is written (its next revise or retract, under the new name). Until then, the rename is invisible to subscriptions.

Revising a shape replaces its field definitions — it is a full replacement, like any revise. You can add fields (optional or required), remove fields, or rename them.

Existing things are not re-validated when the shape changes. They keep their data and stay valid against the shape version they were written under. The new shape is enforced the next time each thing is written.

Adding a required field is therefore backwards-incompatible in a specific way: existing things stay valid until you next revise one, and that next revise must satisfy the new shape. Shapes — Back-Filling Required Fields covers the two migration strategies: back-fill on next revise, or mass-revise every thing immediately. To avoid the incompatibility entirely, add the field as optional.

Shapes can be retracted, with one restriction: the built-in shapes (Pair, Triple, Set, List, Content) cannot be. Retracting a shape you defined marks the shape inactive. The things validated against it are not deleted or changed, and they still resolve. As with any name, you can add a new shape at the same name afterward — a fresh identity.

One change deliberately does nothing: revising a thing with data identical to its current version. WarmHub returns a no-op and creates no new version, so re-submitting an unchanged revise is always safe. See Operations — Idempotent revise for details.