MaestroFor agentsDesign systemSource

Naming

Keys are the API. Every saved view, every route, every reference from a document and every future query names your keys as text. A key is the one part of a game's design that other people's work is written against.

The conventions this bundle recommends

These are bundle conventions, not server rules. The server accepts more than this; consistency is what you are buying.

What the row-key rule excludes, and why it earns its place

A key that addresses a row admits letters, digits, underscores and hyphens, starting with a letter or a digit. What it leaves out is deliberate:

Digits may lead. 1999_season and 500_miles are ordinary keys, and no game should have to rename its content to satisfy an identifier convention.

What can be renamed, and what cannot

An entity's own key is permanent. There is no rename for a row: the address an upsert writes against is the address the row was created with, and the only way to change it is to create a second row and move everything that pointed at the first — which costs one write per edge, per attachment and per stored position, and loses the row's history.

An entity type's key and a relation type's key can be changed. types.rename and relation_types.rename take the key the type has now, and the type keeps its id, its history, its content and every edge of it. This is worth knowing precisely, because the workaround the old surface forced — declare a new type, move every row, delete the old one — is now both unnecessary and destructive.

What a type rename costs is one thing and it is small: a saved view that named the old key goes stale. It keeps running, it draws the same picture — a view records ids, and an id does not move — and it reports the position in its own stored query document where the old spelling still sits. Repairing it is one save from a document you already hold. Nothing rewrites a stored query behind its author, deliberately.

A rename that changes only capitalisation is refused, because the folding index makes the two spellings one address: it would change nothing while announcing a change no reader could observe.

So the useful habit is not a ban on renaming. It is:

Derive an entity's key from something that will not change, and treat a type rename as a small, visible cost rather than an impossible one.

A thing is one row for as long as it is the same thing

When what a thing is changes, update the row. Do not make a second one. A command from an old build that is reimplemented as a skill is the same thing in the game's history: it keeps its key, its edges, its attachments and its place in every saved view, and its fields are rewritten to say what it is now. What it used to be goes in a comment — comments.add on the row, saying it was a command until the rewrite — and not into a history field growing inside the row, which would leave every view drawing a value that is half a changelog. A second row says the game has two things where it has one, and every analysis then counts it twice. modelling/deciding.md argues the division.

The name is the part that moves. A row's name is editable and its key is not, so when the thing's natural name changes you change the name and leave the key alone: entities.upsert writes the new name against the same address, and nothing that pointed at the row has to be touched. A key that no longer looks like the name is not a defect; it is the record of what the thing was called when it was created, and it is the reason every link to it still works.

Two rows are right only when the game ends up with two things a player can meet. A spell that is split into a weak and a strong version is two rows; a spell that is rebalanced, renamed and reimplemented is one.

A key derived from a display name is the classic version of getting this backwards. Titles get rewritten — that is what titles are for — and the key the_dark_portal_part_1 outlives the quest that was renamed to something else in week three, at which point every reader has to know the old title to find the row.