Stable identity
Jadpo knows a declaration or field by the name it was born with, so a rename never looks like something removed and something added. The identity registry holds one line for each thing that has been renamed since, mapping its name now to its born name, and nothing else: a line for every declaration would grow with every new action. Children follow their parent, so renaming a domain or an entity is one line.
Three things write the registry: jadpo rename, the jadpo domain
commands, and promoting a function or type declared in a domain to
shared/.
// Generated by Jadpo from renames and moves; update it with `jadpo rename`, `jadpo domain` or `jadpo fmt --layout`, never by hand.record identities 1entity Todo -> Taskfield Todo.priority -> importancesubscriber send_reminder -> notify_owner
- One registry for data and code. Stored rows name code: outbox events, delivery records and schedule state in the system tables refer to events, subscribers and schedules. Renaming a subscriber must not orphan its pending deliveries, any more than renaming a field may lose its column.
- Physical names never change. The table stays
todoand the columnpriority. Migration snapshots hold the whole schema with physical names, so a rename made by hand shows as a removal and an addition, andjadpo migrate newrefuses it, pointing you tojadpo rename(Tooling). - Inside a callable, branches and fault sites are numbered afresh in each build. Only declarations and fields need to be recognised across builds.
jadpo incident, path keys and the review all compare through this registry, so a rename reads as "renamed", never as "removed and added".
Keys
A key is the kind and the born name, in the registry's own form:
action complete_todo, field Todo.title,
function rounding.half_even (a library keeps its name in shared/).
Names are unique across the project and across kinds
(Names are unique),
so the domain is a field of the node, not part of the key.
The exception is a function or type declared in a domain, whose name
needs to be unique only within its domain. Its key carries the domain,
whether it is public or not: type billing.Address,
function billing.format_address. Its fields and variants follow it:
field billing.Address.street.
Adding public, or a route starting to return the type, never changes a
key. Promoting one to shared/ does. So when a type moves to
shared/types/, the edits layout.promotion_required asks for add its
registry line, type billing.Address -> Address, which
jadpo fmt --layout writes. The key stays type billing.Address, and the
move reads as a move, not as a removal and an addition. That is why the
registry's header names jadpo fmt --layout beside jadpo rename and
jadpo domain.
A field's, variant's or rule's line gives only its own new name
(field Todo.priority -> importance), read back through its owner's
line. Every other line gives the whole name now. The registry is
database/identities.jadpo_record. Jadpo reads it once jadpo rename
writes it; until then every born name is the name now.
A test's key is the file it sits beside and its sentence, with no path:
test create_todo "rejects a blank title". Moving its domain keeps the
key. Two tests with one sentence anywhere in the project are
semantic.duplicate_declaration.
Changing what a key holds is a new manifest format.
Markdown for agents: /docs/stable-identity.md.Built from Jadpo main at a707efb.