-
v1.0.0-Beta.04
Pre-releasereleased this
2026-09-01 15:36:11 +02:00 | 68 commits to main since this releasePhotographs, real watch files, and updating with people training
Added
-
Photographs have a screen of their own at
/body/photos: a grid of
thumbnails grouped by the month they were taken, newest first, one tap to see
one large, and swiping across it to move through them. Adding is two buttons
of ours — take one, or choose one — rather than the browser's grey "Choose
file / No file chosen", which is a web page announcing itself on a phone.
Comparing is a mode entered from the header, and it appears only when there
are two photographs to compare. -
A third answer to a synchronisation batch:
deferred. It means this server
cannot take the change yet, and a later one may.There were two, and they were answers to different questions. "This identifier
belongs to another account" is never going to become true; "this server has
never heard of that exercise" is a statement about a release, and the sentence
after it is usually the administrator updating the server. Both were answered
with "refused, and will never be accepted", and the client's correct response
to that is to throw the row away. Measured: four recorded sets refused by the
server and discarded by the phone in the same second, existing nowhere
afterwards.Deferred work is held on the device, out of the send queue so it is not
offered every minute, and offered again the first time the phone meets a
server running a different build. The server now tells clients what build it
is, for exactly that purpose. Nobody has to be told their session was waiting. -
The connection detail says how much is held and what it is waiting for, and
signing out counts it. Held training is unsent training, and that button is
the last thing between it and a browser somebody else uses.
Changed
-
The body screen ends in a row that says how many photographs there are and
opens them, instead of carrying the whole thing. It was 865 pixels of form on
a screen somebody opens to read a number. -
An update no longer refuses to run while somebody has a session open. It
reports who is training and carries on.The refusal read well and was backwards. Restarting the server mid-set is not
the failure the rest of this application was designed against — it is the case
the rest of it was designed for: a set is written to the phone's own store
before it appears on screen, a failed request leaves the queue exactly as it
was, and the phone offers it again by itself. From the gym floor a server
being updated and a corridor with no signal are the same event. What the
refusal achieved was letting one person who forgot to close a session block
every update on the server, and it did not even cover the case that matters —
somebody who finished half an hour ago with their phone in a locker and
nothing sent yet.lastgym update --when-idlekeeps the old behaviour for an
administrator who would rather wait, or for a nightly cron.
Fixed
-
A
.fitfile from a real watch imports instead of answering 500.Two things, and neither showed against the files these tests write for
themselves. The reader tooktotal_elapsed_timefor hundredths of a second
where the profile scales it by 1000, so every activity came out ten times as
long as it was — a three-and-a-half hour walk filed as thirty-four hours,
next to its own twelve thousand samples whose last offset said three and a
half. And the watch reports moving time 170 milliseconds longer than elapsed
time, out of those three and a half hours, which the table forbids and SQLite
refused; from outside it was "an error, and nothing happens".A session is now brought inside what the table allows before it is written:
a number out of range by rounding is clamped, and one that cannot mean
anything is dropped.internal/core/activity/testdata/walk.fitis a real
Garmin file, cut down — every definition message as the watch wrote it,
including the six times it redefines a record as sensors come online — with
every position zeroed and every timestamp moved off the day it happened. -
One photograph is shown once. The old screen was a permanent
before-and-after, so with a single photograph both sides chose the same one
and it appeared twice, next to itself — which reads as the upload having gone
wrong. It had not: the file was fine, and its orientation was fine too. -
The sheet closes when a photograph is added, and the screen behind it
redraws. It used to empty the file field and stay open, which reads as
nothing having happened. -
The local database is opened without naming a version, so an older bundle can
no longer refuse to start against a newer database.A progressive web application serves whatever its service worker has, which is
not always the newest build. Opening at a fixed version meant that after a
release which raised it, a tab holding the previous bundle asked for version 1
against a version 2 database — and IndexedDB refuses to go backwards. The
start-up screen showed "LastGYM could not start" over the browser's own
sentence, in English, and the obvious remedy — clearing site data — is the one
action that would have destroyed the queue. Nothing was ever lost, but the
application would not open.There is no version constant any more. What decides an upgrade is whether the
stores this build needs are there, and the only version ever requested is one
higher than what is on disk. An older build meeting a newer database now
simply works: upgrades only ever add stores, so the extra ones sit unused. -
Signing in now does everything booting into a session does. It did not, and
the consequences were only visible in a browser.Boot claimed the local store for the account and started synchronising, but
only when somebody was already signed in — and the person signing in had, by
definition, not been. So for the whole of the session they had just started:
no synchronisation, noonlinelistener, no heartbeat, and no flush when the
application closed, which the code that registers it calls "the last chance".
Nothing was lost, because none of it is discarded, but nothing reached the
server until the application was reopened.Worse, the store was never claimed for the account that had just arrived.
Measured in a browser: signed in as a second person on the same device, the
local database still belonged to the first, with their rows and their sequence
number in it. Nothing of theirs was on screen — the screens that could show it
read from the server — but their queue was there, and a queue is sent under
whoever is signed in now. -
A parent that has not arrived and a parent that belongs to somebody else were
the same refusal. Both answered "missing parent", which was invisible while
every refusal was permanent and stopped being invisible the moment a missing
parent became something worth waiting for: a set aimed at a stranger's session
would have been offered again after every update, for ever. -
The installer no longer prints the updater's output on top of its own. An
upgrade hands the release tolastgym update, which is where the five
refusals live, and that command talks to whoever ran it — announcing its own
fetch, its own signature check and a column of steps, then writing the reason
it stopped twice. All of it landed in the middle of the installer's lines. It
is captured now and reported in the installer's own voice: one line for the
signature, one for the backup when one was really taken, and one for the
reason when it refuses. -
An upgrade downloads the binary once instead of twice. The installer fetched
it and then the updater fetched it again behind its own signature check —
fifteen megabytes, and the word "fetching" printed twice, which reads like
the script lost its place. -
The summary at the top of an install shows the address somebody can open
rather than the one the process binds to. It binds to every interface on
purpose, but0.0.0.0:8080is an implementation detail printed to somebody
who wants a link.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-