Why: A hit intent should start the bound workflow, and a command that shares the same id still has to win.
Evidence: go test ./internal/intentgate/ ./internal/runmgr/ ./internal/server/ passed. Recognize keeps slots and the missing-slot question. StartWorkflowRun copies the definition and selects the workflow runner even when mock is on.
Impact: Ordinary turns are unchanged. The workflow runner body is still a stub until the executor lands.
Refs: feature/agent-harness-p4
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: the user ruled out self-registration (2026-09-30): accounts are
created only by admins who set an initial password; first login (and
first login after any admin reset) must force a password change.
Evidence:
- migration v10 auth_accounts (users password/must_change/is_admin +
sessions table; upgrade test walks v1<->v10 both directions).
- argon2id hash/verify with PHC encoding; store tests cover hash
roundtrip, duplicate-owner conflict, must-change lifecycle, session
keep/except semantics.
- e2e TestAdminAccountFlow: static login page reachable without auth,
wrong password 401, login sets HttpOnly cookie + mustChangePassword,
admin creates user (409 on duplicate), non-admin create 403, forced
change clears flag and old password dies, admin reset revokes sessions
and re-arms forced change, API-key channel untouched, 5-fail backoff
429, logout kills session. Full go test ./... green.
Impact: middleware now accepts Bearer key OR session cookie and exempts
static + /api/auth/login (also fixes the latent case where the login
page itself could 401). Embedded no-auth mode unchanged.
Refs: proposal 2026-09-30-ui-redesign-and-auth.md section 5 (admin-issued
variant, user decision 2026-09-30)