Blog · release
Latch 0.9.0
Hosted mode: one instance, many profiles, each in its own database. LATCH_HOSTED=1
turns the solo install into something a handful of people you know can sign in to — a beta
round without asking testers to install anything. Off by default; the single-player install
is byte-for-byte what it was.
- A profile is a directory, never a column.
profiles/<id>/latch.db+media/, resolved per request from the session cookie through a contextvar the game code never sees. There is noWHERE profile_id = ?anywhere because there is noprofile_idanywhere — isolation is a property of the filesystem, and the two-profile test asserts it through the HTTP layer with two cookie jars, never by calling the store. - The path and timezone accessors are functions now (
config.db_path(),media_dir(),tz(),tz_name()) — the constants stay as the single-player values and the fallback. 🔴 Timezone is per profile, chosen at sign-up: a day, a streak and the Handler's evening check roll over on the player's clock, not the server's. /login,/register(invite codes only — no open sign-up),/logout,/account(display name, timezone, password, sign out everywhere, delete — the whole directory). Sessions: random token,HttpOnly+SameSite=Lax, stored hashed, 30 days sliding; a password change revokes every other device; eight misses lock the handle ten minutes.- Admin is a CLI,
python -m latch.hosted(invite · invites · list · disable · enable · passwd · delete · prepare) — not a second login system. - 🔴 The JSON API is a flat 503 in hosted mode, before any route runs: one global bearer token cannot belong to one of many profiles.
- Every profile is migrated and seeded at boot; the tick loop sweeps every enabled profile in its own context, so overdue training is stamped at the deadline for a pup who has not signed in all week.
/healthzno longer needs a database: on a hosted instance it reportsprofilesinstead of a clock, and still answers with no cookie.docs/hosted.md— including, in the player's own words, what the host can see.LATCH_HOSTED_NOTICE— the host's own sentence on the register and sign-in pages (who runs it, how long it lasts, what happens to the data).- 🔴 scrypt: OpenSSL's default
maxmemis exactly the working set of the textbook parameters, sohashlib.scrypt(n=2**15, r=8)fails with memory limit exceeded unlessmaxmemis passed — on the verify side too, or a stored hash becomes a lockout.