docs(auth): the fourth reading, and the rules as they stand (ADR 0017)

ADR 0017 records what the fourth reading found and what was done, and
states who changes what of an account with which proofs, as a table the
full reading can check against; the module README and Learn's AGENTS.md
follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-21 11:47:04 +02:00
commit 858fffdce3
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -180,12 +180,17 @@ Built on the three parts above, on the register (members forward every step thro
of each kind per account, with when it takes effect).
- **Setting a password** (`password.set`): the device sends salt, costs (`argon2id13`,
3–16 passes, 64 MiB–1 GiB), verifier (1 < v < N, as long as N), public keys (32 bytes
each) and both wrappings (24-byte nonce, 112 bytes). It needs an address: the
caller's, or the one a mailed code proves, which becomes theirs as email sign-in makes
it (anonymous → `identified`, same ID). It signs in once an authenticator is
confirmed; until then a new setup replaces it, never once one was, even while a reset
leaves the account without one (a new password comes through the recovery phrase or
the account's reset alone).
each) and both wrappings (24-byte nonce, 112 bytes). It needs an address, and a
session alone sets none (ADR 0017's fourth reading): an account with an address proves
it anew by a code mailed to it for this (`firstPassword`); an anonymous person by a
mailed code (`signUp`) for the address they add, which becomes theirs as email sign-in
makes it (anonymous → `identified`, same ID); an account that signs in with GitHub
alone does that within 10 minutes of a GitHub sign-in on the session asking
(`gitHubSignInFreshFor`, the session row's method and creation time, a member telling
the register; else `signInAgain`, before any code is used). It signs in once an
authenticator is confirmed; until then a new setup replaces it, never once one was,
even while a reset leaves the account without one (a new password comes through the
recovery phrase or the account's reset alone).
- **Codes by mail** (`emailCode.sendCode`, without a session) only prove an address: for
a password's setup, a sign-up, a setup never finished, the resets and deleting an
account without a working second factor. Each is asked for a purpose
@ -241,9 +246,10 @@ Built on the three parts above, on the register (members forward every step thro
account's waits, nor waiting for them: whoever knows the password holds no signed-in
owner out of changing it, and a new password forgets those waits.
- **Authenticators:** a secret made on the register, shown once as an `otpauth://` URI
(issuer: the account domain); confirmed by a code from it; while the account has a
confirmed one, another counts only with the owner's proof too, so a session alone adds
no second factor; confirming one confirmed already is refused as unknown (its code is
(issuer: the account domain); confirmed by a code from it and the owner's proof, so a
session alone adds no second factor: while the account has a confirmed one, the
password and a code from it; the first (none confirmed, after a reset carried out
too) the password alone (`proveOwnersPassword`, the fourth reading); confirming one confirmed already is refused as unknown (its code is
never checked for a session); the first confirmed brings ten recovery codes; at most
10 per account; the last confirmed one stays; removing a confirmed one, or new recovery
codes, takes the owner's proof, removing one never confirmed nothing. Each step's code
@ -259,8 +265,10 @@ Built on the three parts above, on the register (members forward every step thro
password clear it.
- **Resets:** a lost authenticator: SRP's proof plus a mailed code or the recovery
phrase's signature asks for it; it takes effect 72 hours later, a mail tells the
address at once, and signing in with a code calls it off; then the password alone
signs in until a new authenticator is confirmed. A lost password with the phrase: a
address at once, and signing in with a code calls it off; the sign-in that carries it
out ends every session of the account in every service (its own session comes after
that moment), and then the password alone signs in until a new authenticator is
confirmed. A lost password with the phrase: a
signature over a nonce (`keyProofMessage`) by the phrase's own proof key (Ed25519,
derived from the phrase alone, its public half kept as `recoveryProofKey`; never the
account's signing key, which every signed-in device keeps) and a code set a new