monal-rebuild/UX-REPLY-RESULTS.md

7.6 KiB

Quoted replies — 2026-10-08

The operator approved package 8 and rollout after package 7. Sol High is retained; no delegation. Existing blunix handoff edits (177 lines) remain unstaged. Baseline release is generation 555, client f6feaa7.

Representation decision

XEP-0461 0.2.1 selects origin-id/message-id for direct messages and the room-issued stanza-id for group messages. MAM cursor IDs are separate. Replies carry a sender-scoped navigation hint; lookup never crosses a conversation/account, and omitted-sender ID collisions are unresolved. Fallback quotes use XEP-0428 codepoint counts, not UTF-16 string lengths. Stored quote snapshots survive missing/edited history without pretending to identify a different original. An existing edit can be quoted with the original ID; navigation displays its current saved version.

Legacy OMEMO still encrypts a UTF-8 string, now including the quoted prefix and answer. There is no new cryptographic payload/namespace. The outer body is content-independent. Reply ID/address and fallback range stay outside encryption; reply linkage and quote length are visible metadata. Quote text is never put there. The web client applies ranges after decryption only; for encrypted messages only an actual quoted prefix may be separated. Metadata is not authenticated and is used only as a navigation hint. Quoted encrypted originals fail closed if encryption is unavailable.

The operator reports Monal Stable 6.4.21. Public Monal source uses plain > text quotes and displays decrypted text as the body. Structured reply support is still an open upstream feature. Exact release mapping: Stable merge 9be038e9, subject 6.4.21 (#1650), also tag Build_iOS_1092. Its chatViewController.m Quote action prefixes each selected line with > and adds an empty line; MLMessageProcessor.m uses decrypted text as body without reply/fallback handling. Both exact 6.4.21 files were inspected, after checking develop and oldstable/6.4-line. Source evidence is not physical-client acceptance.

Sources: reply IDs/fallback, fallback ranges, Monal 6.4.21 release, Monal 6.4.21 text quotes, Monal 6.4.21 decrypted body.

Implementation and checks

Explicit Reply, composer preview/Cancel/Escape, draft snapshot persistence, focus return, same-chat jump/highlight, local missing-history status and 44px controls are implemented. Group reflections add their room stanza ID to an existing local echo. No database migration/dependency/server change.

Checks: zero svelte-check errors/warnings, 74 passing tests and production build. Tests exercise Unicode fallback, bad ranges/senders, group IDs vs archive IDs, ambiguous/cross-chat lookup, encrypted deferred parsing, draft restart/cancel/send races and real Double Ratchet/AES-GCM round trip of the complete quote. Wire XML contains neither original nor answer text; the legacy decoder receives the expected quoted text. The first candidate exposed a real Svelte-proxy/IndexedDB clone failure on reply-draft restart. Draft persistence and send capture now take a plain state snapshot; the restart regression passes in both engines.

Candidate Chromium state-chromium-1791411343829 and WebKit state-webkit-1791411434234 pass QUOTED-REPLIES: actual encrypted A/B send, zero quote/answer text in wire XML, Unicode, restart/settings/chat isolation/cancel focus, failed send retained, carbon/archive reload without duplication, focused original navigation, missing local history, an original outside the latest 60-message page, room-stamped group references and 44px/no-overflow layouts at 320/402/740/1280. Zero page errors. WebKit reading anchors/pagination/late sizing and draft-send races also pass. Its additional phone-menu check initially ran before roster-supplied actions were ready; the runner now waits for the contact Call control before checking menu order. Focused WebKit state-webkit-1791411540489 passes all phone controls (menu/modal focus, themes, safe-area layouts and large text), zero page errors. Production source did not change for that fixture correction. Chromium state-chromium-1791411605534 passes phone controls, reading anchors, draft-send races, actual closed-profile offline history/draft recovery and Retry (47 ms first socket, 292 ms online), zero page errors. Linux WebKit's fully offline cold-start limitation remains; actual offline coverage uses Chromium. The physical iPhone screen background remains operator-confirmed from package 7, not a new simulation claim.

Final candidate JS assets/index-DlzpKHNm.js, SHA-256 44b6735197c887591b15a7a87c7b1b196872f73347a6cec4ef5b7b5d8ad7a335. A separate candidate run sent the operator one original and one quoted answer from the existing audit account, both verified as legacy encrypted stanzas with no original/answer text in outer XML. The operator explicitly confirmed on Monal Stable 6.4.21: “Ja, beides einmal lesbar” for the quoted original and the answer. This is actual encrypted PWA → Monal display acceptance; Monal's own text-only replies remain the documented readable fallback without structured original navigation. No personal- account/device changes.

Release and live evidence

Client 8ea43b9 is pushed to main, pinned by the isolated blunix 084f7fa lock commit pushed to capability-layout. Switch succeeded as generation 556, system /nix/store/q06xgjsnkc4k1r0y9xx3cib0v4dwv3nk-nixos-system-blunix-26.11.20260910.8ce4ef6; nginx root /nix/store/8r40d45r1g73cr1mv55xa9jsglybslbx-0ff-chat-0.1.0. Candidate, store and HTTPS JS hashes match. Worker is unchanged: e28aaebf01c98e3252e29968a67f1bc8896518e465682f7dc54b3b2f06e85a06. HTTPS 200, revalidation/Vary and unchanged strict CSP verified; iPhone translucent-status metadata is retained. Only nginx restarted; all ten checked platform services are active, zero failed units. Rollback: 555, preserving phone/background and reconnect fixes. Existing 177 blunix handoff additions remain unstaged. The local preview is stopped.

Live Chromium state-chromium-1791412183448 passes matching HTTPS bundle/CSP and the full quoted-reply flow (encrypted direct, group, drafts, original/missing/older-history navigation and phone layouts), zero page errors. Retry opens a socket in 48 ms and is online in 204 ms. The first live run's expiry-only query-error fixture was healed by asynchronous freshness updates, so no send error occurred. The final fixture uses an explicit empty list for a known encrypted peer, fails closed, and restores its exact saved cache row before recovery; real ratchets/keys are untouched. Live WebKit state-webkit-1791412474302 passes matching HTTPS bundle/CSP, phone controls and the full quoted-reply flow, zero page errors. A preceding run passed all assertions but recorded Context is stopped; its historical report is retained. The final repeat did not reproduce it; error source and stack capture were added to the runner without filtering errors or changing the deployed client. All 19 owned audit rooms are confirmed absent; local seed fixtures were removed and the preview remains stopped. Actual Monal acceptance is recorded above; VoiceOver/keyboard/touch ergonomics and fully offline Linux WebKit remain separate checks/limitations. Package 9 still requires its own encrypted-attachment interoperability design.