Split what a person is from how they sign in and how they are seen #55
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "land/identity-face"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
identity: split what a person is from how they sign in and how they are seen
Actor.loginwas doing two jobs. It was the account name a password ischecked against, and it was the handle the world knows someone by. Those
are different facts with different lifetimes and different audiences, and
holding them in one unique field means a second login source cannot be
added without breaking the first.
Three units now, where there was one and a half.
Actorcarries what ensign decides about a person: an opaquesub, akind, and whether they are barred.
Profilecarries what the world maysee — a handle and a name — and is veiled, so it has no generic routes and
cannot be listed.
Sourcecarries one way of signing in: a kind and thehandle within that kind, unique per kind, many to one at the Actor.
Passroots at the Source rather than the Actor, because a password belongs to
the password login and not to the person.
The subject is opaque and minted once. It was the Actor's row id, which
meant rebuilding an estate silently reassigned people to each other's
downstream records, and meant a directory could be walked by counting.
Neither is true of a value drawn from the CSPRNG.
Two ceremonies replace what the generic projection used to answer:
GET /api/profile/{sub}needs no credential and returns a handle and aname. Teams are not in it — group membership is not public.
GET /api/handle/{handle}needs an operator or the sudo token andreturns the actor behind an exact handle.
Both take a key and return a row. Neither takes a predicate and neither
lists, so there is no enumeration face to close.
The service seat stops pretending. It was an Actor with a login it never
used; it is now an Actor with no
Sourceat all, so being unable to signin is a fact of its shape rather than a convention.
Found on the way:
repasspassed an actor id where a source id was nowexpected, and both are
i64, so it compiled and would have refused everypassword change. The custom routes also could not see the sudo face at
all — keel's
admitaccepts sudo, operator, or anon, but a handleroutside the generic projection only receives the operator, so
crownwasturned away holding the highest credential there is. It now asks
core.seal, which is the same judgement keel makes.identity: split what a person is from how they sign in and how they are seen `Actor.login` was doing two jobs. It was the account name a password is checked against, and it was the handle the world knows someone by. Those are different facts with different lifetimes and different audiences, and holding them in one unique field means a second login source cannot be added without breaking the first. Three units now, where there was one and a half. `Actor` carries what ensign decides about a person: an opaque `sub`, a kind, and whether they are barred. `Profile` carries what the world may see — a handle and a name — and is veiled, so it has no generic routes and cannot be listed. `Source` carries one way of signing in: a kind and the handle within that kind, unique per kind, many to one at the Actor. `Pass` roots at the Source rather than the Actor, because a password belongs to the password login and not to the person. The subject is opaque and minted once. It was the Actor's row id, which meant rebuilding an estate silently reassigned people to each other's downstream records, and meant a directory could be walked by counting. Neither is true of a value drawn from the CSPRNG. Two ceremonies replace what the generic projection used to answer: - `GET /api/profile/{sub}` needs no credential and returns a handle and a name. Teams are not in it — group membership is not public. - `GET /api/handle/{handle}` needs an operator or the sudo token and returns the actor behind an exact handle. Both take a key and return a row. Neither takes a predicate and neither lists, so there is no enumeration face to close. The service seat stops pretending. It was an Actor with a login it never used; it is now an Actor with no `Source` at all, so being unable to sign in is a fact of its shape rather than a convention. Found on the way: `repass` passed an actor id where a source id was now expected, and both are `i64`, so it compiled and would have refused every password change. The custom routes also could not see the sudo face at all — keel's `admit` accepts sudo, operator, or anon, but a handler outside the generic projection only receives the operator, so `crown` was turned away holding the highest credential there is. It now asks `core.seal`, which is the same judgement keel makes. Land-Source: identity-face@edae43013197323b5d371dbfae44a649b565cd56