carlos / platform Public
Census: console email sign-in
Status: APPROVED by Paul (census owner), 2026-10-24, recorded on #280 with main at 65ca4aca. The rows keep rev3=PROPOSED-email-signin: under the #369 process nothing is flipped, and later overlays re-froze units at these dispositions, so a flip would move their fingerprints.
Branch email-signin, cut from main at 4d6f0e6c. Design: docs/superpowers/specs/2026-10-21-console-email-signin-design.md.
What changed
The front page has one address box. An address with a Keymail mailbox goes to Keymail's sign-in as before. Any other address gets an emailed link and a six-digit code. A session that signed in by email re-confirms risky actions by email instead of a passkey. The old Apps-inbox confirmation link is retired: its route stays, but only says the link has expired.
None of this runs as root. Every unit below runs in the console (cmd/console serve under console.service, user carlos-console). The root carlos binary links neither internal/console nor internal/mail, and TestRootBinaryLinksNoConsoleOrMail (internal/provision/root_binary_deps_test.go) pins that with go list -deps. No root read is added.
Root-read census (TestPlan14RootReadCensus)
Overlay internal/provision/testdata/plan14-root-reads-email-signin.tsv, loaded last, after plan14-root-reads-claim-merge-main-4.tsv. Without it the test reports 47 discrepancies; with it, none.
Changed units, re-frozen at main's disposition
Each keeps main's basis, with this branch's identity and change appended (the run-lifecycle-logs-325 form).
| unit | change | sites | |---|---|---| | cmd/console/main.go serve | passes CARLOS_CONSOLE_NAME to NewServer as Config.ConsoleName | same three /data literals, same offsets | | server.go NewServer | sets consoleNameCfg and the challengeSem send bound; registers the four /auth/email routes | the logs/data route pattern, moved | | authcli.go Server.handleCLIApprovePage | signed out, renders the front page with next back to /auth/cli instead of redirecting | adds r.URL.Query() (a URL, not a file); old site moves | | server.go Server.handleCallback | session minting moves into finishSignin; reads the next cookie | r.URL.Query(), unchanged | | store.go Store.PurgeExpired | also deletes expired email_challenges rows | one more SQLite Exec on CONSOLE_DB | | store.go Store.migrate | adds sessions.method (default keymail) and calls migrateEmailSignin | SQLite DDL; old site moves | | templates check, home, layout, team | approved copy, the address and code forms, CSS for email inputs | embedded UI input |
New units, accepted legacy at their siblings' class
All J4 root-input, the class of the console's other store methods, URL-query handlers and templates.
| unit | what it reads | |---|---| | emailsignin_store.go: Store.HoldEmailChallenge, LiveEmailChallenge, PeekEmailLink, TakeEmailCode, TakeEmailLink, insertEmailChallenge, migrateEmailSignin, deleteBound | SQLite on the console's own email_challenges table | | store.go Store.SessionInfo | one QueryRow on sessions, as SessionAddress | | store.go Store.PendingInviteAddress | one QueryRow on invites, without consuming it, as PendingInviteFor | | store.go Store.CreateSessionMethod | CreateSession's INSERT, moved, plus the method column | | stepup.go Store.takePendingActionByHash | TakePendingAction's body and both sites, moved unchanged, keyed by hash | | store.go newStore | two crypto/rand.Read calls: an in-memory 32-byte HMAC key for codes and an 8-byte epoch label, never written down; as Keymail.sealEnvelope | | server.go Server.handleHome, Server.handleSignin; emailsignin.go Server.handleEmailLinkPage | r.URL.Query() of the request URL (next, t), not a file; as handleCallback | | templates email_link.html, stepup_email.html | embedded UI input, as their sibling templates |
Retired units
Each is still declared and reads nothing now, so it is retired by an H3 removal. The loader accepts an H3 removal only with a census-ruling- basis, so the rows read census-ruling-email-signin (PROPOSED, awaiting the census owner on #280): .... That is the form console-invite-delivery used for Keymail.SendApp before its ruling. A removal is not in the seal.
server.goServer.handleConfirm: renders the expired message only. ItsTakeConfirmation,EnsureUser,GrantTokenandCreateSessioncalls are gone.stepup.goStore.TakePendingAction: callstakePendingActionByHash.store.goStore.CreateSession: callsCreateSessionMethodwithMethodKeymail.
Envelopes and seal
cmd/console, internal/console and internal/console/templates are re-pinned. The scan finds no other read-site change in them. Twenty-eight frozen declarations are added, so the seal moves from securelisten-337's 33a8ff46…c430 to b25dfda5a68d2183af759b42398f79bb471749d46e68d267545647d1a2e6046b.
Record-write census (TestPlan9B8RecordWriteCensus)
internal/console/server.go:NewServer is re-digested to 9a49c1fc…8169. The effective entry is the replacement in scanDemandWriteCensusInventory (scan_demand_census_test.go), which overrides the plan9B8CensusInventory row, so that is the entry changed. Its kinds are still lit:instances. The diff adds two struct fields and four route registrations. No record write is added or moved.
Questions for the census owner
- Accept the ten changed and eighteen new units as accepted legacy under the console's identity, with seal
1221062f…1d00? - Retire
handleConfirm,TakePendingActionandCreateSessionby H3 removal? If ruled, the marker becomescensus-ruling-email-signinin every row and the seal is recomputed.