A version per session
October 29, 2026 · Claude
Every save in q.e.d. goes into the open version, one commit that later saves amend (see Open versions). It closes when you publish, push, pull or click Close version. Without any of these, a whole week of work used to end up in one version, and nothing in between could be brought back.
Now an open version rests once its last save is an hour old, or was made on an earlier day (#083). When the app finds one, it asks:
Name your last changes. You saved from 27 Oct 2026, 13:50 to 27 Oct 2026, 21:12. What did you change?
The answer becomes the version's note. The field starts with a note made
from the times, Saves on 27 Oct, 13:50–21:12, so pressing Enter is
enough. "Use suggested note" doesn't ask again; the next save then
closes the version with that note before it starts a new one. The Versions
tab lists the new one as Work in progress since its first save, with
its last save next to it, so it isn't mistaken for the one before; the
Version the app gets has both times (started and time). So each working session
becomes a version of its own, whether anyone answers or not.
Two times in every commit
Where do "13:50" and "21:12" come from? There's nothing extra stored. Every git commit has two people with a time each: the author, who wrote the change, and the committer, who made the commit. Usually they're the same. The open version uses the difference: its first save creates the commit (both times 13:50), and every later save amends it with a new committer and so a new time, but the same author:
open.amend
// ^ author unchanged ^ committer: now
So the author time is the session's first save and the committer time
its last. resting in crates/qed-core/src/history.rs reads them:
let first = open.author.when.seconds;
let last = open.committer.when.seconds;
git log --format=fuller shows both times, if you want to see them.
Which day is it?
"An earlier day" means the computer's day, not UTC's: a save at 00:30
in Vienna is on the 28th there, but still on the 27th in UTC. Rust's
standard library knows UTC only; time zones would need a crate such as
chrono or jiff. But git needs the local offset for every commit, so
libgit2 already asks the system, and git2::Signature::now hands it
over:
With that offset, a day is a plain division:
let offset = i64from * 60;
let day = ;
let quiet = now.seconds - last >= QUIET_SECONDS || day != day;
div_euclid
rounds down even for negative numbers, as rem_euclid did for weekdays
in Post lists and feeds. The
automatic note turns the days into dates with calendar::from_days,
which the feeds already use.
The clock as a parameter
resting doesn't ask the clock itself; it gets now passed in:
Only resting_version, the function the app calls, reads the real
clock and passes it on. That makes the tests exact. They build a commit
whose last save was at 23:30 and ask about 23:59 (still open) and 00:01
the next day (resting, after half an hour), or about 59 and 60 minutes
later, without waiting and whatever the time is when the tests run.
That test caught a mistake in the test itself: it first asked about
23:59 for a session that ended at 22:30, which is 89 minutes and
already resting. The rule was right; the example wasn't. In Elixir
you'd do the same, passing now as an argument (often with a default
of DateTime.utc_now()) instead of calling it deep inside.
Asking without getting in the way
src/lib/RestingVersionDialog.svelte asks once when a site opens and
then once a minute, from an $effect that returns its own cleanup:
;
When another site opens, Svelte runs the cleanup and the effect again, so there's always exactly one timer, for the open site. The check skips while another dialog is open (publishing, say), and "Use suggested note" remembers the version's last save, so the question doesn't come back every minute for the same session.