Accounts for deeper questions

Everyone gets prepared answers; a deeper question needs an account: a sign-in, a second factor and a short form, and a conversation is kept only if its visitor asks.

Status
Accepted 8 November 2026
The record
0023-accounts-for-deeper-questions.md

Context

The site has been open from the start (ADR 0004), and anyone could ask the assistant a question of their own, behind a proof of work and a daily budget, with nothing kept of what was asked (ADR 0019, ADR 0021). The owner wants three things that design cannot give: to know who asks the questions that matter (the person, their company, the role), to spend the model on those questions rather than on anyone's, and to give the people who ask them their conversation back. Recruiters' patience is the cost: every step before an answer loses some of them, so the site has to stay open, and each step has to buy something.

Decision

  • Prepared answers for everyone. The assistant's examples grow into the questions recruiters ask, each with an answer written in advance that passes the same gate as a model's, in a test. A question typed without an account is matched to a prepared one by its words and by the record's terms and hiring topics; a question about pay or private life is refused by rule as before; anything else is met with an invitation to sign in. No model is called for a visitor without an account, and what went unmatched is counted by topic, never by its words, so that the owner knows what to prepare next. The anonymous conversation, its proof of work and its three endpoints are gone.
  • An account, for a deeper question. Google's sign-in, the client the admin already has (ADR 0016): the owner, by the allow-list, reaches the admin as before; anyone else with an address Google has verified gets a visitor's account at their first sign-in. No passwords, so nothing to leak, reset or confirm by email.
  • A second factor. A time-based one-time code from an authenticator app (RFC 6238: SHA-1, six digits, thirty seconds, one step either way, no code accepted twice), with ten single-use recovery codes, asked at every sign-in and then not again in that session. Required before the form, the history and deep questions, by a switch that is on. The secret is sealed with AES-256-GCM under a key from Secret Manager; recovery codes are kept as keyed hashes; five wrong codes lock the factor for fifteen minutes.
  • The short form. The visitor's LinkedIn profile, the company's site and the posting's link, each over https; for a search that is not posted, the role's title instead of the link. The form says the owner sees what is in it.
  • Deep questions. A ready account (signed in, the factor given, the form filled in) asks the guide as it was: the same model, tools, gate and daily budget, conversations held in memory as before; thirty questions a day an account.
  • The history, by choice. At the start of a signed-in visit the guide offers to keep the conversation in the account. Kept, each question and its answer as shown, prepared or deep, is stored, listed on the visitor's page, downloadable as a PDF made on the server, and deletable one by one, all at once, or with the account.
  • The owner sees accounts, not conversations. The admin lists who signed in, their form and how many questions they asked; a conversation reaches the owner only when its visitor sends it with an introduction.
  • One session cookie. __Host-session (it was __Host-admin, and is no longer the admin's alone): in the one instance's memory, eight hours, Secure, HttpOnly, SameSite=Lax. A visitor who never signs in gets no cookie: asking who is signed in, as the guide does whenever it opens, is answered for nobody with no content, no session made for it, and nothing a browser logs as an error.
  • Retention. An account whose setup never finished is deleted after seven days; any account, with everything in it, 180 days after it was last used, by the sweep at start that introductions have.
  • The greeting. The text greeting stays. A recorded greeting, the owner's own voice, has a place beside it with its transcript, and plays when the visitor presses it, never by itself. A signed-in visitor is greeted by name and offered the history.

Consequences

  • ADR 0004 stands for the site: every page, the lab and the prepared answers stay open; one feature, the deep question, sits behind an account.
  • ADR 0007's one exception, the session cookie, now covers signed-in visitors as well as the owner; the privacy page says what an account keeps, for how long, and how to take it away.
  • ADR 0016: anyone may complete Google's sign-in now; the admin's endpoints still let the owner alone in.
  • ADR 0019: nothing is kept of an anonymous visitor's question, as before; an account holder's conversation is kept in their account if they ask for it, and nowhere else.
  • No model is called without an account, so the budget and the anonymous proof of work no longer meet strangers.
  • A recruiter signs in, sets up an authenticator and fills in the form before the first deep question: three steps. If that loses too many, app.accounts.second-factor-required=false makes the factor an offer rather than a door.
  • A PDF needs PDFBox, about four megabytes in the image, loaded only when one is made; its font, Liberation Sans, covers Latin and Cyrillic, and anything else in a question is printed as a question mark.
  • Deploying it needs the accounts' key in Secret Manager and the Google client the admin already needs.