5.8 KiB
Sleep Diary capture UX and black-screen correction evidence
Scope
This record covers the focused 0.1.4 Web correction and presentation tranche. It does not change Sleep Diary domain semantics, desktop schema v29, Android schema v26, synchronization, publication lifecycle, PDF semantics or any frozen exchange format.
Runtime diagnosis
The deployed bundle was run through http://trainlog.perf/analyse?section=sleep
in Firefox 156 with an isolated synthetic XDG data directory. The browser
reported isSecureContext === false and did not expose
crypto.randomUUID. Clicking Ajouter for a bedtime event raised:
TypeError: crypto.randomUUID is not a function
The stack entered the addEvent state updater in
web/src/routes/SleepDiaryWorkspace.tsx. React then unmounted the application
tree, leaving an empty body. The router remained on the Sleep Analyse URL.
There was no mutation request, HTTP status or response body because the
exception happened while constructing the optimistic event. No unhandled
promise rejection was present. Medication intake identity construction used
the same unsupported API and had the same latent failure.
Correction
Sleep event and medication-intake identities now use crypto.getRandomValues,
set the UUIDv4 version and RFC 4122 variant bits explicitly, and never fall back
to Math.random. A section-local React error boundary keeps the Trainlog shell,
header and navigation mounted and offers a retry card for unexpected future
render errors. This boundary is defense in depth; it is not the black-screen
fix.
The capture presentation now uses the existing Trainlog panel, quiet-action, primary-action and danger-action vocabulary. Dates, lifecycle badge and local save state form one night header. Morning/day appreciations, event creation, timeline, intake creation, notes and actions have explicit hierarchy. The medication catalog is a compact list whose creation form opens on demand and whose saved item becomes immediately selectable for an intake.
Validation evidence
- Web TypeScript, all Vitest tests and the Vite production build pass.
- Component regressions cover bedtime, sleep, long awakening, final get-up, nap and sleepiness, stable entry identity, advanced revisions, medication creation, intake creation, edit and delete.
- Real Firefox against the production C server created two medications, two intakes and five events, then reloaded the same durable entry and revision.
- Every captured mutation returned HTTP 200 with its expected JSON identity or revision response. The console error and unhandled-rejection collections remained empty.
- The responsive layout had no document-level horizontal overflow.
- The retained post-reload screenshot is
evidence/sleep-diary-v1-final-firefox.png.
Private deployment evidence
The functional bundle was built from
915728cec4ffbb2c90eb3f4b47d349a6ebd17fe9. Its embedded desktop binary has
SHA-256 e45c2fd8807dd9c28128206ee57e2869b64726397ae6072d521a903d3d4afdc9.
Before the switch, the live schema-v29 database was backed up as
trainlog-before-915728c97f420f824c7831024d61ee9c08645321.db, SHA-256
9579e1365164a082e328c4c5bc1ffc7b45bf234a1f5bf1812842837c8ecc05f7;
its integrity check was ok and its foreign-key check was empty.
The versioned installation is
~/.local/share/trainlog/installations/915728cec4ffbb2c90eb3f4b47d349a6ebd17fe9.
After the atomic user-bin switch and service restart,
trainlog-web.service was active as PID 2322898, and
/proc/2322898/exe resolved to that installation's libexec/trainlog.
The deployed executable and footer both reported version 0.1.4.
Real Firefox 156 then used the actual deployed profile to create TestMed A
5 mg and TestMed B 25 mg intakes at 22:00, bedtime at 22:30, sleep from
23:00 to 03:00, a long awakening from 03:00 to 03:30, sleep from 03:30 to
06:30 and final get-up at 07:00. Reload retained entry
sl_71b9c7a5-cabe-4d22-86fc-bde8a34590f9 at revision
slr_c1e8f641-4db7-43f1-8a9c-e7ef15b2c1df, with five events and two
intakes. All nine mutations returned HTTP 200. Browser console errors,
network fetch errors and unhandled rejections were all zero. The exact
390×844 viewport had zero document overflow. No main merge, tag or release
was created.
Live persisted Agenda follow-up
The Agenda now consumes the same canonical entry revision returned by Core as
the Chronology, factual summary, PDF and synchronization surfaces. After a
successful mutation the existing persistence queue re-reads the diary, finds
the exact returned entry_id and revision_id, and only then marks the entry
as locally saved. Request sequencing prevents an older GET from replacing a
newer projection, while the serialized mutation queue supplies each returned
revision to the next write.
The compact row derives bedtime, final get-up, declared sleep, time in bed, long-awakening totals, naps and sleepiness directly from the canonical event list. Medication intakes at one timestamp use one grouped marker and retain their factual dose snapshots. Catalog and selector labels use stable medication identities and display localized usual dose/unit, so same-name/different-dose records remain independently selectable.
The isolated real-Firefox scenario observed, without reload, two venlafaxine
intakes at 22:00 (75 mg and 37.5 mg), bedtime at 22:45, sleep from 23:15 to
03:00, a long awakening from 03:00 to 03:30, sleep from 03:30 to 06:45 and
final get-up at 07:10. The Agenda immediately reported 7 h 00 min declared
sleep, 8 h 25 min in bed, one 30-minute long awakening and one grouped M ×2
marker. All captured requests returned HTTP 200, browser error and unhandled
rejection collectors stayed empty, and reload reproduced the same Agenda row.
The retained capture is
evidence/sleep-diary-live-agenda-firefox.png.