Public: anyone can read this; nobody can change it.
No sign-up makes the site admin, not even a forge's first account: only the operator's first-admin code, a claim or a seed makes one #57
Check · Review · Land done · Live — Landed; nothing deploys from this branch, so this is the end of its path.
`AdminOrigin` is `claim`, `first-admin` and `seed`. createUser takes the admin flags only from one of those: they are not in any other origin's input type, and createUser drops them for any other origin at run time. So the signup form, the API, the passkey door, the terminal, the parent forge's sign-in and the platform edge each make a person who is not an admin, even on a forge with no admin at a…
shipped merged
Sign in to join this conversation.
AdminOriginisclaim,first-adminandseed. createUser takes the admin flags only from one of those: they are not in any other origin's input type, and createUser drops them for any other origin at run time. So the signup form, the API, the passkey door, the terminal, the parent forge's sign-in and the platform edge each make a person who is not an admin, even on a forge with no admin at all. A standalone forge's admin comes from the operator's--first-admincode (#41); a spawned child's from its claim link.With no sign-up an admin,
welcomeno longer proves an admin's address by being one, and the edge's first account is not proven by being first: both start unproven and follow the link like anyone else.Test suites whose admin was their first sign-up make it with
test/helpers/admin.ts(seedAdmin, oradminCookiefor a signed-in browser) instead.test/no-signup-admin.test.tsfails on main: the API, passkey, terminal and edge doors each made the first account an admin.Why
Trevor's rule (2026-10-17): a Forge site admin comes only from the operator's first-admin link (#41, merged), a spawned child's claim handover, or the
seedorigin tests use, never from any signup path, even when the forge has no admin. This PR depends on #41, which is already on main: without it a standalone forge would have no way to make its admin.What changed
src/core/users.ts:AdminOrigin = claim | first-admin | seed. Only those origins' inputs carryisAdmin/adminIfFirst(a type error anywhere else), andcreateUserdrops them at run time for every other origin.adminIfFirst.welcomeandensureEdgeUserno longer mark an account proven for being the first/admin, so every sign-up follows the email link.test/helpers/admin.ts(seedAdmin,adminCookie): the 82 suites whose admin was their first sign-up make that same account asseedinstead. The tests that asserted the old rule now assert the new one.test/no-signup-admin.test.ts: on main 18917b93 it fails 4 of 6 (API, passkey door, terminal and edge each made the first account an admin). On this branch it passes 6/6.Beyond
validate, every test file was also run on its own on this head (525 files, CI-shaped env, bun 1.3.14). All are green except contain.test.ts (DNS), crew-interrupted.test.ts and snapshot-destination.test.ts, and those three fail the same way alone on main on this box.Left for a decision
Not changed here: while signup is
closed/invite, a fresh forge still lets in its first account (newAccountsClosed), and the terminal still skips Turnstile for that first account. Both were there so the owner could sign up as the admin. Now all they do is let a stranger make an unproven guest before the operator gets there. Closing them is a small follow-up if Trevor wants it.<!-- pipeline:validation -->
Validation
pipeline/validateonea16896f: baseline in 609s — bun 1.3.14, CI-shaped env (scrubbed vars, runner PATH), exact check.yml shard + forge.json commands.bun install --frozen-lockfileforge.json check.fastcheck.yml gate (1) pull_requestcheck.yml gate (2) pull_requestcheck.yml gate (3) pull_requesttest output (failures, totals)