184 lines
12 KiB
Markdown
184 lines
12 KiB
Markdown
# UX packages 4–6 — implementation and release evidence, 2026-10-07
|
||
|
||
The operator approved implementation, checks and rollout of packages 4–6
|
||
after accepting the package-0–3 live push test. In that earlier test, the
|
||
operator confirmed the notification and replied “Jo funktioniert”; the audit
|
||
account received it readably and all three test messages showed Displayed.
|
||
This is one operator-confirmed delivery/reply check, not blanket native-device
|
||
certification. Sol High retained; no model switch or delegation.
|
||
|
||
## Slow-start and reconnect follow-up (2026-10-07)
|
||
|
||
The operator clarified that the delay concerned Connecting/Retry. Two session
|
||
defects were reproduced: a socket closed before opening left the reconnect
|
||
promise pending and suppressed later attempts; Retry restarted the automatic
|
||
backoff, which can reach 30 seconds. `3b38c1c` releases the guard on disconnect
|
||
without letting an older completion clear a newer attempt, and starts a
|
||
coalesced stream-resume attempt immediately on Retry/network/app wakeups.
|
||
The baseline test stopped after one failed automatic reconnect; the corrected
|
||
test makes two failed attempts and then recovers on Retry. Dedicated audit
|
||
accounts and existing browser identities were reused.
|
||
|
||
An additional shell delay was demonstrated: the old navigation handler waited
|
||
for bundle/config/manifest/icon caching before returning HTML. A 1.5-second
|
||
manifest delay held HTML for about 1.6 seconds. With `c7d39e7` and the updated
|
||
worker explicitly activated, the same candidate fixture returns HTML in
|
||
21–54 ms; caching finishes in the background via synchronously registered
|
||
`waitUntil`. The offline HTML is still replaced only after its dependencies
|
||
are cached. Delayed-download/storage unit tests verify this ordering and
|
||
that a failed update retains the previous complete offline shell.
|
||
|
||
Checks: zero svelte-check errors/warnings, 68 passing tests, production build,
|
||
runner syntax and diff checks. Chromium candidate report
|
||
`state-chromium-1791408201264/report.json`: offline restart/history/draft,
|
||
automatic retries and token retention pass; Retry opens a socket in 48 ms
|
||
and is online in 331 ms. WebKit candidate
|
||
`state-webkit-1791408238917/report.json`: remembered startup online in
|
||
1242 ms, Retry socket in 119 ms and online in 426 ms; zero page errors.
|
||
These are Linux measurements, not timings from the operator's phone.
|
||
|
||
Blunix `5e9207c` enables gzip only for this chat vhost: the previous live
|
||
467 KB JS response was uncompressed even when compression was requested.
|
||
Release input advances to `3b38c1c` via `a6825e0`. Switch succeeded as
|
||
**generation 554**, system
|
||
`/nix/store/a8chqbya79yhnf53vsn0amdrlmci5sw9-nixos-system-blunix-26.11.20260910.8ce4ef6`;
|
||
nginx root `/nix/store/7pck4q3nhl5cwp742g6cdbq0bhqgkswl-0ff-chat-0.1.0`.
|
||
Live/store/candidate JS and worker hashes match. HTTPS 200, unchanged CSP,
|
||
gzip and `Vary: Accept-Encoding` verified: JS transfers 229623 compressed
|
||
bytes instead of 467547, about half the original transfer. Default gzip level
|
||
is used. Only nginx restarted; all ten checked platform services remain
|
||
active and there are zero failed units. Rollback is **553**.
|
||
|
||
Live Chromium `state-chromium-1791408360190/report.json`: remembered startup
|
||
online in 814 ms; Retry socket in 41 ms and online in 220 ms after two failed
|
||
attempts; closed-profile offline history/draft recovery passes. Live WebKit
|
||
`state-webkit-1791408400472/report.json`: remembered startup online in 891 ms;
|
||
Retry socket in 113 ms and online in 296 ms. Both load the matching HTTPS
|
||
bundle, retain the FAST token and report zero page errors. The fully offline
|
||
WebKit/native-iPhone limitations below remain; no personal account or server
|
||
authentication policy was changed. Original 177 handoff additions in blunix
|
||
remain unstaged and preserved.
|
||
|
||
Live delayed-manifest probe `load-probe-1791408463910.json`: with a confirmed
|
||
active updated worker, HTML first byte arrives in 25–82 ms despite the same
|
||
1.5-second manifest delay, zero page errors. The probe explicitly updates and
|
||
awaits worker activation; an immediate navigation can still be controlled by
|
||
the previous worker while its replacement installs. Existing PWA users should
|
||
reload, then close and reopen the app to pick up the update.
|
||
|
||
## Implementation
|
||
|
||
- `75f0875`: account/conversation drafts, revision-conditional clearing,
|
||
tab notifications, previews and visible-message reading anchors.
|
||
- `dd9ebfe`: opted-in local account startup, offline history, retry/backoff,
|
||
reconnect coalescing and credential-rejection handling; candidate runner.
|
||
- `c0294d6`: participant records, affiliation queries, group/person view and
|
||
navigation. No server privacy configuration changes.
|
||
- `6d6b787`: distinct resources keep concurrent tabs connected; login displays
|
||
the credential-rejection reason. Device identity remains stable.
|
||
- `55d7d05`: explicit latest-message jumps survive pending refresh/resize;
|
||
anchor writes tolerate a closing account DB.
|
||
- `7e3e3aa`: handle transports closing during initial presence and room joins.
|
||
- `9bb9cd1`: store the offline page only with its referenced bundles cached.
|
||
- `6806242`: expanded candidate checks and explicit WebKit limitations.
|
||
|
||
## Candidate verification
|
||
|
||
- `npm run check`: zero errors/warnings. `npm test -- --test-isolation=none`:
|
||
65 passing tests (draft account/peer/tab revisions, required anchor page,
|
||
presence identity/role/nickname/reset, closing transports, distinct
|
||
affiliation outcomes and complete/failed shell updates, plus prior
|
||
crypto/status/media tests). `npm run build`: passed. Script syntax and
|
||
whitespace/diff review passed.
|
||
- Chromium initial reading probe: 542px before navigation, 543px after.
|
||
`/tmp/chat-ux-runner/results/direct-pwa-chromium-1791394391830/report.json`.
|
||
- Chromium package-5 candidate: draft navigation/reload; closed-profile
|
||
offline startup with real worker/local history/draft; restored connectivity
|
||
without reload; network failures retain token and retry; last-jid without
|
||
token shows login; a deliberately invalid token returns to login and hides
|
||
cached history. All passed, zero page errors:
|
||
`/tmp/chat-ux-runner/results/state-chromium-1791395243602/report.json`.
|
||
|
||
- Final Chromium: `/tmp/chat-ux-runner/results/state-chromium-1791400348937/report.json`.
|
||
Every check passed, zero page errors: multiline/independent drafts through
|
||
list/settings/reload; visible-message key and offset through navigation,
|
||
reload and pagination; simulated late sizing above the viewport; latest
|
||
jump; failed send/typing-during-send/tab edit with both tabs connected;
|
||
closed-profile offline history/draft and recovery without reload; network
|
||
backoff/token retention/Retry; last-jid-only and invalid-token gates; full
|
||
group/person checks; empty offline store; logout deletes the local account
|
||
DB/draft. Reading anchor offset was exactly preserved in the final run.
|
||
- Final Linux WebKit: `state-webkit-1791400170578/report.json`, with corrected
|
||
offline-step runner `state-webkit-1791400293209/report.json`, under the same
|
||
private results directory. Drafts, anchors/pagination/late-size simulation,
|
||
latest jump, send races/tabs, network Retry, account gates, group/person
|
||
checks, empty store and logout passed; zero page errors. A Retry click raced
|
||
with automatic reconnection and is corrected in the runner.
|
||
- WebKit's **fully offline closed-profile navigation is not tested**: the
|
||
Linux runtime rejects worker-controlled navigation under `setOffline`, even
|
||
with cache data. The alternative restarted the same profile with the shell
|
||
online but XMPP blocked: local history/draft appeared and sending was disabled;
|
||
unblocking XMPP recovered without reload. The empty-store check uses the same
|
||
alternative. Do not call this a native iOS offline result. Upstream report:
|
||
[Playwright #42775](https://github.com/microsoft/playwright/issues/42775).
|
||
- Group checks use a disposable room: owner/admin/ordinary-member, denied
|
||
lists distinct from empty, loading/error/retry, absent member, usable
|
||
disclosed identity versus occupant nickname, private-chat target, message
|
||
nickname action, actual nickname-change presence, invite/leave and draft
|
||
restoration. No horizontal overflow at 320/402/874/1280px. Temporary admin
|
||
affiliation is restored; room destroyed and bookmarks removed.
|
||
- Cleanup confirmed every recorded temporary room absent, including a leftover
|
||
from the first failed probe: `/tmp/chat-ux-runner/state-room-cleanup.json`.
|
||
No new audit devices were deliberately added; stable profiles were reused.
|
||
|
||
## Proven shell-cache defect
|
||
|
||
Before the worker fix, Chromium's controlled cache contained only the old
|
||
`index-DLDjjWaX.js`/`index-BL9qAZyP.css`, while its cached HTML referenced the
|
||
current candidate. Offline JS/CSS requests failed and rendered no app.
|
||
`state-chromium-1791398778899/report.json` records those cached paths and zero
|
||
rendered app views; `state-chromium-1791398594769/report.json` records failed
|
||
current bundle requests. This established the package-5 worker defect rather
|
||
than extrapolating from WebKit's runtime limitation. Navigation now caches the
|
||
referenced hashed assets and shell metadata before replacing the offline page;
|
||
failed bundle download retains the old complete page. Fetch-handler writes are
|
||
awaited. Push/notification logic and cache namespaces remain unchanged.
|
||
Worker updates require script-byte changes; a client-only build does not by
|
||
itself repeat install precaching: [service worker lifecycle](https://web.dev/articles/service-worker-lifecycle).
|
||
|
||
## Release
|
||
|
||
The final candidate is `assets/index-B__HlxBv.js`, SHA-256
|
||
`a1414b26a67fab8cdd8ceecf24b48434e3f8a41f7b7421963f0e4afabc68e12a`.
|
||
Worker SHA-256:
|
||
`81833691c4d2f4198daca7aef3c57b92b2a4ac645bdf7d132dfccacfffa7368f`.
|
||
Client `97b35d6` is pushed to main and pinned by blunix `0b33e06`, pushed on
|
||
capability-layout. `sudo nixos-rebuild switch --flake .#blunix` succeeded:
|
||
**generation 553**, system
|
||
`/nix/store/rfsmizmpsp76cr26kw87nia8py7idsfg-nixos-system-blunix-26.11.20260910.8ce4ef6`.
|
||
nginx config `/nix/store/8zb3f1m6fq0q3qbrcxs7nhlgs6lwp5rw-nginx.conf`, root
|
||
`/nix/store/b6jdy7dbw97482sgnc0mjz3f5lvanfz6-0ff-chat-0.1.0`.
|
||
Live, Nix-store and candidate hashes match for both JS and worker. HTTPS 200
|
||
and the existing strict CSP verified. Only nginx restarted; nginx, Prosody,
|
||
Traefik, LLDAP, Dex, Headscale, Forgejo, GoToSocial, sshd and Tailscale active;
|
||
zero failed units.
|
||
Live Chromium `state-chromium-1791400807461/report.json`: matching bundle/CSP,
|
||
draft navigation, actual closed-profile offline worker/history/draft recovery,
|
||
and full group/person checks passed, zero page errors. Live WebKit
|
||
`state-webkit-1791401226266/report.json`: matching HTTPS bundle/CSP, draft
|
||
navigation and full group/person checks passed, zero page errors.
|
||
Prior encryption/status/media/worker regressions also passed against this
|
||
candidate, with zero page errors:
|
||
`direct-pwa-chromium-1791400531631/report.json`. Delivered→Displayed, retained
|
||
decrypt errors with no marker for the error, blocked selection/paste/drop with
|
||
zero slots/PUTs, group file/image and cancellation, and real worker control.
|
||
Before our bump, this checkout's newer network/calendar commits were already
|
||
active: `nix eval --raw .#nixosConfigurations.blunix.config.system.build.toplevel`
|
||
matched the running generation 552 at
|
||
`/nix/store/0v92cnnw5igmkrq6mpwphnxbf0ggpspm-nixos-system-blunix-26.11.20260910.8ce4ef6`.
|
||
Use **552** as the rollback generation, preserving that intervening work.
|
||
Pre-existing 177 added handoff lines remain unstaged/preserved in blunix.
|
||
Physical iPhone keyboard/safe areas, background/lock and VoiceOver remain
|
||
operator checks; no blanket native certification. No package 7–9 or personal
|
||
account/server privacy changes. Profiles, credentials, screenshots and reports
|
||
remain private under `/tmp/chat-ux-runner`.
|