carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

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.go Server.handleConfirm: renders the expired message only. Its TakeConfirmation, EnsureUser, GrantToken and CreateSession calls are gone.
  • stepup.go Store.TakePendingAction: calls takePendingActionByHash.
  • store.go Store.CreateSession: calls CreateSessionMethod with MethodKeymail.

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

  1. Accept the ten changed and eighteen new units as accepted legacy under the console's identity, with seal 1221062f…1d00?
  2. Retire handleConfirm, TakePendingAction and CreateSession by H3 removal? If ruled, the marker becomes census-ruling-email-signin in every row and the seal is recomputed.