Part of Stem. This page defines the migration: what is preserved, what is deliberately discarded, how old data is read, how old clients keep working, and in what order the pieces ship. The conversion itself, blob type by blob type, is specified in The runtime model under "The migration box".
Principle
Stem augments the shipping protocol. No existing blob becomes invalid, no existing URL stops resolving, and no document, comment or contact changes identity in a way a reader can observe. The team's chosen method is the one recorded for HM26: migration happens transparently inside the indexer, where old data is signature-validated as it is and then converted into the records the new indexer expects, while new data goes straight through. The original blobs stay in the store, so every signature remains verifiable forever.
What is preserved
Every URL. An HM24 document at path P becomes a node whose id is the SHA-256 CID of the earliest Ref blob published for P and its genesis, placed under the migrated id of its parent path with the last segment of P as its name. That Ref is treated as the node's creating blob, so the id is derived from a signed blob exactly as a Stem id is. Its pretty path is therefore P, unchanged, and hm://<space>/P resolves as before. Versions (?v=) are unchanged because they are head Change CIDs.
Every document's history. Changes are not converted. A document's genesis Change still identifies its Change graph, and every head in the migrated Node's target shares it.
Every comment, attached to the right document. Today comments are keyed to the target's genesis so they follow moves; in Stem they target the node id, which the migration derives from the earliest Ref of the path the comment named (following redirects, as today's genesis keying effectively does). A comment's node id is the SHA-256 CID of the first Comment blob carrying its TSID, and hm://<author>/<tsid> keeps resolving through a TSID lookup the daemon keeps for migrated records.
Every profile and contact. Profiles become the space root's attributes; contacts become contact nodes whose ids are the CIDs of their first blobs.
Who may write. WRITER capabilities become write grants on the migrated node of their path (or on the space root), with the same delegate.
What is public. A space whose owner published public Refs gets a derived read grant to everyone on the space root; a private Ref's node gets access: own and no public grant.
What is discarded
The roadmap records two decisions the migration implements rather than questions it reopens.
Sub-document capability scoping as a product feature. Path-scoped and non-recursive capabilities are discontinued; invitations are to a space's home only, and a writer of a space is a writer of the whole space. The migration keeps an existing path-scoped WRITER as a write grant on that one migrated node, because the grant is harmless and the data exists, but the apps stop issuing anything but whole-space grants, and the roadmap's expectation that such grants are "trashed" in spirit holds: nobody should rely on them.
The no_recursive and is_exact flags. They were never implemented by the daemon and have no counterpart.
Two HM24 fields lose their meaning rather than being discarded: generation and genesisBlob on a Ref. The migration uses them to group the Refs of one path by life (each generation and genesis becomes its own node, sharing the name) and to order each life's Refs into a prev chain (by timestamp, then CID), and then forgets them, because node ids are never reused.
Migrated ids
A migrated node's id is derived the same way a Stem id is: from the CID of a signed blob, here the earliest Ref blob of the path and genesis. There is no reserved namespace and no special creation rule; a migrated node is protected by the ordinary rule that updating an existing node needs write on it. Migrated nodes can be renamed, moved, granted on, tombstoned and redirected like any other node, and a rename changes their pretty path exactly as it would for a new node, which is the point.
A migrated node whose parent path never had a Ref (an "orphan" in the team's discussion) is placed under a derived parent node that the migration creates with a tombstone target and the parent's name, so the child keeps its pretty path and an admin can adopt it by publishing a Node blob for the derived parent with real state.
Old clients during the transition
A Stem daemon accepts HM24 blobs for the length of the transition and converts them on the way in. A client that still publishes Refs, Capabilities, Comments, Profiles and Contacts therefore keeps working against a Stem daemon, with these effects:
A Ref it publishes for path P becomes a Node blob for the node whose pretty path is P, when the daemon can resolve one; if no node has that path, the Ref becomes a creating blob and its own CID is the new node's id. A Ref whose genesis differs from the node's starts a new node sharing the name, as a recreated document does today. Spaces that have adopted Stem clients should not be written to by HM24 clients.
A Capability it publishes becomes a grant as the table in the runtime model says.
A private Ref it publishes yields a node with access: own.
Reading is unaffected: the read APIs return documents, comments and profiles as before, with the node id added to every response.
A Stem client talking to an HM24 daemon does not work; the protocol id changes (see below) so the two never attempt to sync. The SDK and CLI gain Node and Grant emission behind a version switch; the Seed app follows.
Rollout order
Daemon with the migration box and the new protocol id. All derived tables are rebuilt by a reindex at upgrade. Sync between upgraded daemons uses the Stem RPCs; an upgraded daemon does not sync with an HM24 daemon. Sites upgrade first, then desktops, with the gateway's web app serving reads throughout.
Clients emit Stem blobs. The SDK, CLI, agents runtime and app switch to publishing Node, Grant, Revocation, Group and Snapshot blobs. Documents created from now on get ids derived from their creating Node blobs. Grants replace the capability flows in the app; the owner is prompted once per space to issue a sync grant to its declared site.
HM24 emission is disabled. Clients stop producing Refs and Capabilities. The daemon keeps accepting them for stored data and for any straggling client, and keeps converting them, indefinitely: there is no second migration.
Optional re-signing. A device of the owner may re-sign migrated derived records as real Node and Grant blobs so that a Stem-only peer can hold the space without the HM24 originals. This is an open item, below.
The protocol id moves from /hypermedia/0.9.x to /hypermedia/1.0. Exact-match negotiation, which today prevents daemon generations from syncing with each other, is what makes step 1 safe.
Checklist of open migration questions
Open: should the migrated id be the earliest Ref's CID or the genesis Change's CID? Stem's position: the Ref, because a Change has no space or placement.
Open: the exact prev ordering of migrated Refs when two Refs for one path share a generation but differ in genesis, which today coexist as parallel rows and resolve by highest generation. Stem's proposed rule is generation, then timestamp, then CID, which picks the same winner as today for the head.
Open: whether migrated path-scoped WRITER grants should be dropped outright (the roadmap's "trashed") rather than kept as write on one node.
Open: whether derived grants and Snapshots should be re-signed by the owner (step 4) and, if so, whether the app does it silently or asks.
Open: how the two CID hashes for identical bytes (BLAKE2b in the daemon, SHA-256 in the SDK) should be unified when Node heads are compared, since a migrated Ref may name either. Proposed: the migration canonicalises heads to the multihash the store already holds and records the alias.
Open: comments on a migrated document whose path was redirected before migration. Proposed: the migration follows redirects to the final node, as today's genesis keying effectively does.
See also
The runtime model: the migration box table.
Resources and nodes: how ids are derived and why they cannot be forged.
Placement: why pretty paths survive.
Where this is going: the HM26 and permissions decisions this migration implements.
Documents and Permissions: the shipping model being migrated.
Do you like what you are reading? Subscribe to receive updates.
Unsubscribe anytime