Client parity¶
Recipient chips and composer undo (R113, R114): all three clients show To, Cc
and Bcc as removable chips split by the shared recipient-cases.json rules,
while drafts keep the comma-separated value. Desktop keeps its own bounded undo
for the body, Subject and each recipient field, because iced has none. The
browser and Flutter keep native undo for Subject and the body and add a
per-field history for chip changes, with Ctrl/Cmd+Z, Ctrl+Shift+Z and Ctrl+Y.
Flutter's Android integration tests and Apple execution, and browsers other
than Chromium, remain unverified; see composer-recipient-chips-and-undo.
Mobile queued bulk Undo (#49) is merged for pending, paused and held-first-step work. The checked local decision removes forward projection and cancels only unsent items; actual late receipts retain their same-group inverse. Unknown replies keep exact status inspection/Retry, including visible capacity feedback and removal fences. The same owner preserves explicit Undo/Resume/Retry wakes through final History observation (#58). Native/mock, FFI, real compact controls and remaining integration/platform evidence are recorded in Completion.
Mobile bulk History schema25 separates retained durable history from its 20-active admission bound. The control keeps one 20-group page and one 50-item page, with indexed cursors and exact older recovery targets. Page generations fence late Retry/Accept completions, including same-group away-and-back, and local command revisions fence held screen/owner results and errors. Group, detail and owner readers each coalesce one request and its latest replacement. Failed detail reads retain visible Retry without blocking group controls. Host/native, Android journal and Appium fixture evidence is recorded in Completion; Apple, live providers and large-active-group performance remain separate.
The 6 October mobile functionality audit
checks the current Flutter implementation against desktop main and links
24 confirmed functional gaps plus a separate platform-verification ticket.
Its source inventory corrects stale broad Open entries below: mobile folder
mutations, CalDAV, durable bulk actions and ongoing preference reconciliation
already have implemented paths. Mobile layout choices are outside this audit.
Mobile bulk reviews retain the exact live selection through Cancel, Back and barrier dismissal. Approval releases only its matching capture after durable confirmation; lost replies inspect the same saved review identity. Failed decisions stay reviewable, while newer selections and scope changes fence late preparation results. Native journal, Dart model and actual Flutter control regressions cover this lifecycle. Android integration controls and exact journal restart also pass, along with four Appium flows and reviewed light/dark captures. Flutter-web, Apple, live-provider and performance verification remain separate. See issue #27 and the completion audit for executed evidence.
First-download composer ownership: desktop preserves the current draft and
typing target when the first mail page arrives, while explicit mail selection
can still park it. Flutter's separate composer route and browser's retained
modal have no matching automatic-selection path on source inspection. Exact
first-download focus regressions on both clients remain an active verification
gap; see first-download-composer-focus in the shared client scenarios.
Browser CalDAV schema19 and Flutter connection lifecycle v2 are integrated for combined verification. Browser setup retains local identity before discovery, keeps passwords in tab memory and rejects late activation after removal or newer Calendar changes. Flutter binds each native probe to its durable attempt and orders cancellation against provider start. Shared Google conditional restoration is a prerequisite; browser delete Undo integration, mobile Undo and live provider and Apple verification remain active work.
Desktop Activity schema11 is integrated for combined verification. Its fixed visible control and remappable shortcut observe existing journal owners, retain review targets through refresh and open exact folder/backup recovery records. Root verification passes four native Activity scenarios and six shortcut regressions, with reviewed captures and clean Clippy. Browser and Flutter common-domain Activity parity and final platform/latency verification remain active.
Desktop Preferences shows ? help beside seven easily misunderstood
settings (R98), on hover, click and Tab focus, hidden by its own synced
help_icons preference. The browser and Flutter clients label that shared
setting in profile reviews but do not act on it yet. The browser Preferences has none of these settings nor a Tooltips choice,
and Flutter was out of scope for this wave; both remain explicit gaps in TODO
R98 and should reuse the same help text when those settings arrive.
Desktop schema 10 removal hides the committed account/calendar before provider
drain and exposes failed local cleanup with Retry; ten integrated native scenarios
and 47 bulk/calendar/connection tests pass. Browser schema 17 adds checked subtree
Rename/Move/Delete with frozen metadata, receipt-first repair, uncertainty review
and outgoing filing fences. Its integrated 235 unit, 57 backend and 22 Chromium
checks pass, plus three 100,000-message browser scenarios. Native ten-of-100,000
review and confirmation pixel timing passes at 32.31 ms and 22.14 ms p95 with
provider capacity held. Implementation is checkpoint 8db87f1; other-platform
coverage remains separate.
Flutter schema 21 uses shared calendar event/receipt contracts for Google save and delete. Local admission precedes token access and retains its exact original request for lost-reply lookup. Coherent snapshots and queued work retain their Google subject; execution rechecks the SDK grant. Integrated Rust verification passes 153 tests after shared HTTP extraction, including stale sync, receipt repair and safe successive edits. Flutter passes 234 tests and 29 final focused controls/FFI cases for lost replies, bounded pending requests and editor close. The shared HTTP adapter passes eight tests; authenticated Calendar transport and common Drive/Calendar renewal pass 67 backend tests. Flutter/browser CalDAV controls, live Google and Apple execution remain open.
Browser Calendar schema 18 now admits Google event changes through the common background owner. It retains exact requests, receipt identities, pending cancellation and checked recovery, including lost replies while newer text is entered. Root verification passes 250 units, 20 combined control scenarios and 13 Calendar/storage scenarios; desktop light and compact dark recovery captures are reviewed. Calendar Undo after acknowledgement, timed creation, recurrence editing and final performance remain active gaps.
Flutter CalDAV controls now share the schema23 journal with folder creation. The integrated client passes 185 Rust and 260 Flutter tests, with clean analysis and reviewed compact setup, checked recovery and recurring-event views. Exact observations, connection replacement and provider routing retain their restart checks. The shared calendar provider has 19 parser/HTTP tests, including collection-specific privileges, recurring write refusal, UID decoding and daylight-saving durations. Credential read/cleanup errors retain visible Retry, including after restart. Browser CalDAV, live providers and Apple execution remain open.
Native group flag writes now retain provider receipts before cache updates; cache-only repair preserves Undo and never repeats a provider write. Native calendar actions now admit durable requests independently of provider capacity. Browser individuals retain Activity and safely resume orphan queued work; Flutter individuals admit exact UUID requests before credentials/provider waits and expose waiting/recovery controls. The browser and Flutter inventories retain remaining adoption and verification requirements. These migrations do not establish complete domain, Undo, offline-policy or platform parity.
Flutter schema 17 records individual receipts before cache work and saves the
still-owned field subset at claim for dispatch, repair, inspection and Undo. Cache-only
repair preserves newer fields and physical replacements, and acknowledged moves
without a UID retain read-only identity recovery through restart. Native groups
now share one lease across independent account items, retaining exact item repair,
Pause and Undo ownership. Other domain/lifecycle adapters remain unfinished.
Desktop draft feedback now stays with each editor or parked session, including
Retry and newer-revision ownership. Flutter/browser now retain parked draft text,
owned failures and Retry, with stale-result and Send/removal fences. Browser file
retries preserve exact identities after lost replies. Browser schema 15 now checks
observed text/revisions and offers explicit conflict review; wider suspension and
platform evidence remain active.
Native Preferences now retains revision-owned local save errors and Retry after
notice dismissal/navigation, without reverting the current choice. Focused unit
and desktop/compact native gates pass in shipped checkpoint d7f06b7.
Flutter Preferences also retains owned status and Retry
through unrelated notices; compact light/dark screenshots are reviewed. Browser
Preferences now owns failure/Retry, retains pending field intent and guards profile
application until admission succeeds; publication keeps its separate owner.
Native schema 8 stages checked account credential slots and activates them with settings atomically; provider, vault and backup readers resolve the binding. Incoming identity edits with cached mail require a reviewed migration. The account UI now admits locally, closes its matching form and exposes Connection activity; the integrated native held-capacity/close/restart/rejection controls pass. Flutter schema 18 now admits at most 32 attempts before probes and exposes Cancel/re-entry with same-ID execution generations and removal fences. Its integrated gates pass 134 Rust and 203 Flutter tests. Native candidate discovery and Flutter runnable actions now use indexed 50-row pages, with 100,000-row database-step tests. Flutter resumption retains per-account exclusion across failed reads and an explicit Activity Retry. These gates do not establish whole-app latency or platform parity.
Desktop schema 9 now admits a frozen draft as Preparing before MIME work and supports local cancellation before dispatch. Its combined native verification is in progress. Folder creation also admits locally and retains a logical pending row, receipt-first repair and explicit uncertain-result inspection. Browser schema 16 creation and its real authenticated gateway now pass 77 focused unit tests, 49 backend tests (one fixture prerequisite ignored), and 12 Chromium controls covering creation, upgrades, removal fences and preferences. Flutter schema 24 admits creation and checked rename/move/delete locally, shows logical pending sidebar entries and exposes bounded recovery through its existing account/provider owner. Exact reviewed membership and cache repair use batches of 50 rows. Host bridge, failure/restart and compact control evidence are recorded in Mobile folder creation; live-provider, Android and Apple folder execution remain open. Browser now saves queued Send before provider reservation, retains connection-attempt recovery and atomically saves preference values with intent revisions. Browser Activity also reads a bounded connection-attempt page from its existing owner, with reconnect navigation and exact-attempt dismissal. Reload and newer attempt tests retain unrelated mail failures. Other domain summaries remain open. Flutter now saves the exact message and delivery identity before returning from Send; delivery runs in the background and queued cancellation retains the draft. Account and credential changes are checked before SMTP. Outbox resumes the same saved attempt and refreshes its bounded page without clearing errors or review choices. Wider activity adoption remains open. Browser and Flutter still prepare MIME before Send admission; equivalent preparation lifecycle and timing gates remain open.
20 September immediate actions: the approved common lifecycle is being adopted
on desktop, starting with bulk review during pending mail writes and calendar
save/delete projections. shared/action-core defines projection outcomes but
does not provide durable admission. Flutter and browser adapters, equivalent
held-provider UI scenarios, and an audit of every mutation domain remain active
gaps in TODO. Native unit/protocol tests and five new real-control scenarios pass,
with reviewed light and compact dark captures. Existing browser ownership and receipt journals remain authoritative;
the shared type alone establishes neither behavioural nor provider parity.
22 September desktop destination follow-up: desktop moves resolve logical
Archive/Trash/Junk names from a fresh LIST before the first folder sync, fall back
to RFC 2342 NAMESPACE when neither LIST "" "" nor the reference listing reports
a root, and name the acknowledged physical folder in the move toast. The NAMESPACE
exchange lives in shared/mail-core, but the browser and Flutter have no
special-use destination resolution, fresh-listing fallback or acknowledged-folder
toast label yet; these remain active parity gaps.
13 September desktop follow-up: verify fresh Move/Delete after a kept recovery
copy's original reappears, library-backed HTML word/line selection, selectable
subjects, large-message receipt and the standard Spam shortcut. Browser and
Flutter retain their native selection controls. Browser subjects are native h1
text; Flutter subjects and cached From/To fields use selectable controls with
visible exact-value Copy actions. Native metadata keeps the actual receiving
account separate and never reconstructs missing recipients. Both clients
already list Spam, but mapping the reported server's Junk folder and equivalent
recovery/large-mail controls require explicit verification. Desktop Spam opens
the existing Junk mailbox, including the reported account; discovery of other
providers' specially named spam mailboxes remains an active gap.
Desktop ordinary-cache receiving now stages incoming IMAP/POP3 messages above
25 MiB, after smaller mail, and publishes the exact source atomically. Shared
providers retain the existing client path unless staged-receive is enabled;
Flutter/browser need their own reviewed staging and cache publication. Native
encrypted profiles reject unsupported large-message staging before creating
plaintext files. Large native plain bodies use successive reader previews;
complete raw export remains available. Full streaming reading/attachments,
full-body search indexing and encrypted staging remain R23 gaps.
12 September move/folder follow-up: desktop work adds missing-destination
creation before mail submission and server-verified automatic recovery, with
direct Retry instead of a mandatory review for routine cases. Flutter/browser
equivalents remain active gaps; sharing the protocol helper does not establish
client UI, durable recovery or live-provider parity. Sidebar New folder also
requires equivalent account/parent controls and failure/restart coverage.
The shared folder-creation contract also preserves a frozen target and its
encoding through uncertain results, exposes unfinished requests in the normal
form after restart, and waits for accepted writes when closing. Desktop
delivery is recorded in 842c570; both client implementations remain open.
Desktop text context menus cover editable inputs/composition and selectable
plain/formatted readers, with native clipboard actions and keyboard access.
Browser controls retain their browser menus and Flutter retains its platform
selection controls. Equivalent field, password, reader, focus and keyboard
coverage remains an active parity gap; default platform controls alone do not
establish it. See the shared text-context-menu contract.
Desktop History header follow-up: the mail-action History control uses a clock
arrow icon with the existing optional tooltip and unchanged dialog action.
Browser and Flutter header equivalence remains an active visual-parity item;
their existing History controls remain available. See the shared
history-header-control scenario for the expected interaction.
R64 desktop surface review: Linux launcher/dash/grid/switcher use the approved opaque light Shepherd through a full-colour scalable application icon. The tray uses matching colours with tighter padding and exact 1x/2x pixmaps; macOS retains its native template. These OS tray surfaces have no browser or Android/iOS equivalent. Their in-app Shepherd assets and approved design are unchanged; mobile launcher artwork remains part of R80's platform visual review.
The root Rust + iced app remains the reference. Android/iOS live in flutter/; the desktop-style browser client lives separately in web/. website/ promotes all clients. Development stays in review worktrees; the combined checkpoint is pushed to feat/mobile-web-clients. On 2026-09-09 main was merged into that branch, so main is now the single integration branch and desktop changes arrive through merges rather than ports; see the merge review below. The requested VPS installation awaits the supplied server and OAuth configuration.
The new clients are not feature-complete. Flutter production has a Rust bridge, SQLite cache/drafts, device credentials, mail setup and reviewed Outbox recovery. The Android integration suite and preview Appium scenarios cover the implemented paths; full protocol-success/recovery coverage remains open. The separate browser connects to the Rust gateway, with account verification, an IndexedDB mail/draft cache and reserved SMTP sends; complete provider/recovery parity remains open. Preview builds acknowledge fictional state only. No personal account or credential is used by these tests.
Every desktop feature/default/provider change must update this matrix and the corresponding client scenario, or leave an explicit gap in the active tracker. Agent instructions make this an ongoing requirement. scripts/clients/check_parity.py --base REV checks that desktop changes include a parity review; it does not certify feature equivalence.
| Behavior | Rust desktop reference | Flutter mobile | Separate browser |
|---|---|---|---|
| OAuth and continuous account/settings profiles | Scoped OAuth consent, durable discovery, reviewed initial publication and account/preferences enrollment; reviewed ongoing sync for implemented portable preferences with native controls; opt-in Google-only password vault sync with staged, tested import; conflict resolution, automatic setup, complete categories/settings and full DB transfer open | Scoped native consent, actual host/Android history bridge and saved-Google discovery and initialized first-profile publication controls; reviewed device enrollment and account/preferences application now have native/host and isolated control coverage; ongoing reconciliation of the nine portable preferences is connected with a native ledger, foreground cycle, per-field controls and paged conflict reviews (see the mobile profile page); automatic setup, background scheduling, accounts and other categories remain active in the handover. Credential protection and live cross-client access open | Server-mediated Google consent with saved versus requested permissions, a browser history worker over the shared WASM journal, per-identity durable discovery, reviewed publication and enrollment (accounts imported without passwords and marked Reconnect required, seven portable preferences, including the reply default and both move preferences) and first-setup onboarding with Chromium and HTTPS gate evidence (see the browser profile page); ongoing reconciliation, conflict decisions, removal reviews, remaining categories and a live provider remain open |
| Multiple accounts, unified/account folders | Implemented | Native setup/reconnect, atomic credential activation with stale-request binding checks, device credentials and cached folders; reviewed atomic removal with durable credential cleanup and stale-write protection tested; connection editing and Apple lifecycle open | Setup/reconnect, cached folders and unified view; reviewed atomic removal, stale-tab protection and cancellation tested; connection editing and wider lifecycle audit open |
| IMAP/POP3, TLS/STARTTLS, SMTP | Implemented, remaining live/protocol audit | Shared Rust provider adapter and native bridge implemented; complete device/protocol and live verification open | Shared Rust transport, authenticated VPS endpoints and browser adapter implemented; live verification open |
| Sender/subject/snippet, unread/flag/attachment indicators | Implemented | Implemented in preview; 0–4 snippet lines, avatars | Implemented in preview; 0–4 snippet lines, avatars |
| Configurable left/right swipes and icons | Touch adaptation | Archive, Trash, read/unread, flag, selection, move, spam, disabled; menu equivalents | Desktop controls; browser behavior follows iced |
| Optimistic flag/read/move with rollback | Implemented baseline | Per-message FIFO/revisions, stable SQLite move identity/receipts, queued/post-refresh Undo and unresolved-intent protection tested; ambiguous/recovery review open | Persistent per-field revisions reserved at input time, dispatch ownership checks and superseded-control reconciliation; atomic alias adoption and pending-intent removal review tested. Acknowledged receipts precede fallible cache/display work, and committed move counts/usable Undo survive display-only failures; queued/post-refresh Undo tested; durable group executor API tested, while visible group controls and ambiguous/recovery review remain open |
| Counted move notifications and grouped Undo | Implemented | Six-second grouped Archive/Delete/Move/Restored, Dismiss, pending cancellation, partial retry and reader/Inbox controls; provider receipts retained; Apple and durable history review open | Same grouping/expiry, independent refresh status, partial retry, dismissal and acknowledged-Undo protection; durable history review open |
| Cached paging, prefetch and strict latency budgets | Implemented baseline; covering unread-account index avoids mail-row reads/sorting on each page | SQLite WAL, two independent read connections, FIFO writes, 50-row metadata pages and on-demand bodies; bounded body parsing/prefetch/performance remain open | IndexedDB mail/raw cache with an active persistent SQLite/OPFS query worker: coalesced 50-row metadata pages, independent body/metadata reads, bounded speculative cache (8 bodies/32 MiB), source-incarnation/change-journal recovery, pending individual fields and explicit Retry. Indexed sync scans return 50 metadata rows; flag writes retain one body. Current integration verification is recorded in the completion log. Bulk projections, physical account-index cleanup lifecycle, full fuzzy ranking, provider metadata arrays, Outbox/draft/removal snapshot bounds, large-message parsing and final performance OPEN |
| Background sync and independent manual refresh | Five-second checks scheduled per account, independent queued manual refresh; IMAP IDLE watcher per account restarts when incoming settings or the credential binding change; CONDSTORE CHANGEDSINCE flag refresh with a saved per-folder HIGHESTMODSEQ, and QRESYNC VANISHED expunges instead of a per-folder UID listing. The 480-second no-progress watchdog remains. Background failures have a 30-second continuous observed-failure grace period per account, bound to its incoming connection identity, and the banner names a single failing account with its last error; explicit Refresh errors remain immediate. Mail sync, calendar refresh, unattended automatic backup and automatic move-recovery failures cannot reopen a tray-hidden window or cancel Quit; user-started writes, including explicit Activity move recovery, keep their recovery. Isolated native tray overlap, automatic-backup, required-write recovery and fictional reader scenarios pass. |
15-second foreground checks, independent manual queue and cache-first startup. Typed per-account outcomes retain incoming configuration and credential-slot identity; automatic failures wait 30 seconds from the first observed failure. Rename retains the episode; recovery, reconnect, reconfiguration and removal invalidate it. Expired foreground generations cannot publish or dispatch after credential waits. Unrelated action/save recovery remains owned; real Refresh, Retry and Dismiss controls have regressions. Explicit Refresh remains immediate. OPEN: background OS scheduling, live providers, Android/iOS restoration, IDLE push and CONDSTORE. | Visible browser tab checks every 15 seconds while connected; independent manual refresh queue. OPEN: origin-aware delayed background failure notice, per-account episodes, tab-loss/stale-result controls, lifecycle/performance review, IDLE push and CONDSTORE. Explicit Refresh currently reports errors immediately. |
| Captured selection and reviewed bulk actions | Implemented; remaining recovery audit tracked | Native SQLite capture drives Select mode, checkboxes, long-press/menu ranges and captured Select all/Clear; a durable group journal in the profile database runs frozen reviews, owned steps with receipts, Undo, Pause/Resume, retry/accept, 20-group History and conservative restart, with host, Flutter-web Playwright and Android integration/Appium evidence (Mobile group actions). Cross-account transport, live IMAP, large-group performance and Apple OPEN | Worker-owned SQLite capture/freeze and bounded controller; Select/all/Clear/Done, Ctrl/Shift/Mod+A, cross-page ranges, scope reset and recovery have Chromium control evidence; Separate durable journal and frozen export feed an owned provider executor with approval/Undo revisions, receipt-first cache repair, source guards, skipped outcomes and conservative tab-loss recovery. Real Chromium verifies complete 125-message execution, physical Undo and failure/retry; group-aware removal now reviews exact ownership, fences queued work and recovers bounded cleanup across tab loss, with real Preferences evidence. Production activation, full-group worker projections, exact reviews, History (20 groups/50 results), Pause/Resume, pending/acknowledged Undo and explicit failure/uncertainty review now have actual Chromium controls. Prepared group Undo paints rows/counts before decision persistence or follow-up queries, preserves newer reader flags and reports rejected decisions after History closes. Counterfactuals retain exact dispatch folders for successive moves. Abandoned reviews and staging are retired by bounded owner-wake and periodic sweeps; Undo after scope/page change, queued approval, partial failure and overlapping groups has Chromium evidence; Y/N/Enter/Escape and remappable approve/decline keys drive reviews and History. Group progress waits for the reads each round started, so refreshes cannot starve execution on a busy host. Group actions at 760 px and below (the selection summary is hidden), cross-account transport, large-group performance and native equivalents OPEN |
| Other accounts' folders when moving (R108) | Badged folders from other IMAP accounts appear only while typing, ranked by the shared matcher with a 15 point penalty; Enter/Y or Move confirms, Escape/N or Cancel returns with the query; a group choice opens the review naming the account | OPEN: decodes and labels foreign_move_folders only; Flutter changes deferred by the owner |
Implemented: synced preferences, shared WASM ranking, badges, confirmation, pick-list account and group review; the gateway transfer saves the destination receipt before removing the original, with Activity repair, checked review and Undo. Vitest, backend mockall and Playwright control evidence; live IMAP transfer unverified |
| Search and stable filters/sort | Abbreviations selected on 12 September: Nucleo/OSA labels and materialised phrase/literal mail tiers preserve shared page/selection ordering. Bounded vocabulary candidates exclude the exact token; complete prefix scans skip proved absences. Counts share ranked keys before reading 50 metadata rows, including projected destinations and empty-offset totals | Debounced SQLite FTS prefix search, flags/unread/sort; selected Nucleo/OSA and phrase-ranking parity open | Debounced local search, flags/unread/sort; selected Nucleo/OSA and phrase-ranking parity open |
| Reader, full reader, selectable text, quotes, find in message | Implemented; R95 puts selection above the HTML image, with native drag/pixel/Copy evidence in light, dark and compact readers; Ctrl+F/find shipped upstream c266035 | Shared Rust-prepared HTML in a persistent system WebView, inline WebP, selectable/plain choices, Find across spans and quotes; saved Android/Flutter browser scenarios; remote-image policy, Apple execution, large-text and keymap parity open; the shared frame runtime keeps an email's own opaque background and gives a transparent root white paper or a dark canvas from its text colours, reported to the reader surround (Android and Flutter browser evidence) | Worker-prepared confined HTML, authored CSS/tables/inline WebP, plain-text choice, persistent sandboxed frame, selection/Copy, shared Find across spans, quotes and remapping; the same readable-canvas rule colours the frame and viewport (formatted-canvas.spec.ts); remote-image policy, large-text and full lifecycle parity open |
| Preferences search catalogue | Indexes rendered control captions, sections, tabs, descriptions and synonyms with visible-caption weighting, typo matching that yields to real catalogue words, and no-results feedback. Results name the explaining control; selecting one scrolls to it and focuses its text field. A rendered-caption guard fails when a Preferences caption lacks a catalogue entry | Available-control catalogue uses shared native WordMatcher off-thread for accents/abbreviations/typos and exact mixed-numeric tokens. One running query plus latest replacement fences stale replies and exposes Retry. Results reveal actual controls/destinations, including conditional mail/Google/profile/CalDAV controls; local intent/save Retry/open CalDAV forms survive. Rust capacity, actual FFI/widget and compact/held-provider checks are separate from the preview's limited matcher. Native Android FFI/search/reveal/Theme and reviewed captures pass. Unimplemented desktop preferences stay tracked in #41; wider Android and iOS search execution remain OPEN | No Preferences search; catalogue, control reveal and coverage guard OPEN |
| Cached attachment download | Implemented | Shared Rust metadata/bytes, retained reader and native save/cancel/error controls; actual Android picker verifies exact bytes. Apple export implementation awaits execution; large/deep MIME and lifecycle audit open | Shared Rust WASM in a worker; names, sizes, duplicate identities, retry and exact offline downloads verified through Rust HTTPS controls; large/deep MIME and lifecycle audit open |
| Conversations and sender copy | Newest-first conversation cards in the reader and below inline replies; indexed Newer/Older pages preserve the expanded message and parked draft | Open, including newest-first thread order | Open, including newest-first thread order |
| Reader action footer | Reply, Reply all, Forward and Print stay below the scrolling body in individual and conversation readers, including collapsed expanded targets | Existing safe-area footer stays outside the body; separate conversation cards remain open | Existing stable footer stays outside the body; separate conversation cards remain open |
| Compose, Cc/Bcc, reply-all, MIME, attachment persistence | Implemented | Native From/To/Cc/Bcc, shared Reply/Reply all/MIME, independent file blobs/revisions, actual Android picker cancel/multi-select/reopen/removal verified; Apple picker and full composition audit open | Cached Reply/Reply all, shared reply fixtures, IndexedDB file blobs, real multi-file selection/removal/reopen, exact MIME/references/Bcc-envelope verified through Rust HTTPS fixture; full composition audit open |
| Reply quote preference (R97) | Preferences → General → Composing sets the starting state of Include original message for new Reply and Reply all drafts (default on); each reply can override it, saved drafts keep their own choice and forwards always include the original. Shared reply_include_original profile key retains field intent |
Include original message and a read-only original preview keep typed text separate. The searchable default affects only new replies; autosave, files, reopen and reviewed Outbox recovery retain the choice and thread headers. Schema26 rejects old writers before they can discard hidden quotes, with actual prior-library proof and exact25-to26 upgrade preservation. Old inline-quote drafts remain unchanged. Legacy eight-field profile reviews/receipts retain their exact fields | Shared codec, default and profile mapping preserve explicit false and field intent. Open gap: composer still embeds the original in editable text and has no per-reply control or new-reply default application |
| Autosave, multiple drafts, close/save recovery | Implemented baseline; inline improvements active | Versioned SQLite text plus independent attachment revisions, debounce autosave, file edits flush pending text, close/save recovery and discard tombstones; full multi-editor parity open | IndexedDB text/blob separation, versioned debounce autosave and reopen; failures retain editor, sent records prevent resurrection and file changes; full multi-editor conflict/recovery UI open |
| Durable SMTP/Outbox/Sent recovery | Implemented | Exact MIME before SMTP; 20-row Outbox, rejected/uncertain review, cloned draft/file ownership, local Sent repair and preserved acknowledgments tested. Shared handles and an OS profile lock protect active sends; host/Android second-process checks pass. Provider Sent discovery/lookup, background copy, reviewed retry, cache repair, policy/folder settings and synced-copy deduplication have protocol/native evidence. Local IMAP Sent flags/read/moves no longer access credentials, with host/Android scenarios; server identity routing preserves missing/locked-credential refusal. Atomic Sent identity adoption, retained IDs, logical folder grouping and physical Undo destinations have cache/host/Android-control evidence, including held sync, late bodies and pre-handover Undo. The open reader survives exclusion from a refreshed page. Separate edited local/provider copy labels, history cleanup and the wider reader lifecycle audit remain open | Exact prepared MIME/envelope commit before SMTP; local Sent/reload, rejected/uncertain review, unused-reservation cancellation, return-to-draft and manual-mark controls tested. Stored terminal acknowledgments survive receipt expiry. Provider Sent lookup/APPEND reservations, client journal, reviewed retry, acknowledged cache repair and account preferences now have Rust/browser control evidence. Atomic local/provider identity adoption, persistent aliases, logical Sent grouping, retained readers and physical Undo destinations now have model/IndexedDB/Rust HTTPS control evidence. Local edits persist during held sync. Copy labels/history and bounded Outbox/cache paging remain open |
| Month/agenda, edit/read-only calendar | Implemented | Native date/time pickers, All day and inclusive Last date support timed and multi-day events. Range checks reject end-before-start and nonexistent spring-DST times. Nominal all-day dates use exclusive UTC-midnight ends; legacy non-midnight pairs retain their exact timestamps until scheduling changes. Month/day projections retain multi-day coverage. Source, ETag/resource identity and untouched descriptions survive edits; held/lost admission retains exact requests and newer input. Read-only/expanded recurring events remain view-only. | Preview month, title/location edits preserve event identity/times/source; timed creation and scheduling controls remain open |
| Calendar providers, ETags, recurrence, source lifecycle | Implemented with documented limits | Open | Open |
| Light/Dark/System, approved logo | Implemented | Implemented; saved device preferences | Implemented; saved browser preferences |
| Visual likeness to the desktop (R80) | Reference shadcn-style palette, typography, spacing, controls and states | Desktop tokens, type scale, icon set, controls and states applied; reviewed light/dark montages and saved captures in flutter/e2e/web.mjs and theme_test.dart. Open: touch adaptations (composer actions in the app bar, full-bleed rows, unread-only header), device and Apple review |
Desktop tokens, custom selects/checkboxes, icons, reader and Preferences layout applied; saved captures in web/e2e/visual-parity.spec.ts. Open: light muted text kept darker for the contrast gate, no tabbed Preferences sections, formatted-frame styles unreviewed |
| Pane resizing, shortcuts and capture safety | Implemented | Touch layout; full shortcut parity open | Saved sidebar/list resizing; remapping/disable, retained shortcut capture/held presses through background completion, conflict/cancel/current-setting preservation, native action Enter/Space and focused-row reader bindings verified; complete keymap/focus behavior open |
| Dropdown keyboard dismissal | Implemented: an open pick list takes every key; Escape/Tab close only the menu, never a dialog, composer, Find or mail shortcut, and the covered control takes the next click (ui::dropdown, saved test_dropdown_* flows) |
OPEN: Flutter dropdown menus not reviewed in this wave | Native <select> popups are browser-owned and shortcuts ignore select targets; no change needed, no saved popup evidence |
| Contacts, remote-image exceptions and safe HTML | Selectable HTML integrated from upstream 1968e37 | Shared confined HTML implemented; external images blocked; contacts/exceptions/loading open | Sender active content removed, resources converted off-thread, inherited CSP permits only the fixed runtime, opaque sandbox denies app access; automatic remote images blocked, contacts/exceptions/loading open |
| Google OAuth/refresh/grants and keychain lifecycle | One Sign in with Google button with Shep's compiled-in Desktop OAuth client (no pasted credentials), loopback PKCE, cancel and bounded wait; feature-scoped Drive/Calendar consent, staged activation and refresh tested; self-configured grants keep refreshing. Sam's real client and a live audit remain | Native SDK sign-in, requested/saved permissions and durable local disconnect pass host, Android, Appium and offline preview-browser checks. Safe account switching, automatic session restore, provider integration and live/Apple execution remain open; SDK tokens stay outside preferences | Google beta gate tested in Rust and real HTTPS browser flow; provider grants/credential lifecycle open |
| Encrypted Local/Drive backup, journal, retention/restore | Implemented; multiple Local, Drive, S3, SFTP and FTP/FTPS destinations with per-destination formats, schedules, retention and history arrived from main (R32) | Open | Open; browser file/Drive adapters and client-side encryption required |
| Portable settings/account sync, large mail, cache encryption | Complete database export/import and local profiles shipped on main (R83); SQLCipher foundation shipped, production startup still plaintext (R22); large mail open (R23) | Must follow R02/R22/R23/R49; no client database transfer or cache encryption yet | Must follow R02/R22/R23/R49; no client database transfer or cache encryption yet |
| Forward complete cached source | Integrated desktop controls, HTML/CID and independent drafts | Atomic native draft/files, retained quote/CIDs through autosave/restart/recovery; Android controls and host contracts; Apple execution and multi-editor parity open | Independent WASM preparation, atomic IndexedDB draft/files, remappable Forward, retry/restart and independent editor controls; gateway preserves inline IDs; full composition audit open |
| Complete-source Print | Integrated desktop browser/PDF preview | Shared background preparation and Android printer/PDF controls verified; UIKit adapter added; responsive safe-area actions with host/Android held-touch/loading, native printer/PDF and Appium evidence; Apple execution and keymap/remote-image parity open | Independent preview/worker, remappable Print, retry/input isolation, stable action footer and native held-press/keyboard activation through preparation, plus actual paginated PDF verified; other browser engines and remote-image parity open |
| Read on leaving deliberate mail | Implemented | Native Back/composer/focus/navigation controls and explicit unread; projected SQLite pages stay available while read/move is pending; close/OS/Apple audit open | Navigation/composer/focus controls, explicit unread, quiet ordered updates and rollback; real HTTPS/cache evidence; tab-close lifecycle audit open |
| Bulk actions, folder trees/context menus, drag to folders, palette editor | Desktop shipped: bulk History/recovery (b352d12), drag to folders (ca39080), folder trees (6d520e9) and reviewed folder Move/Delete (3567de2, 97c9a9a), palette editor (4e75005); combined-folder reconciliation active | Selection and durable bulk actions have host, Flutter-web and Android evidence; folder trees/context menus, drag to folders and palette editing remain active parity work (R42/R45/R30/R25 entries in TODO) | Bulk selection/actions have Chromium evidence; folder trees/context menus, drag to folders and palette editing remain active parity work |
| Native tray, temporary saving tray, new-mail notifications, dock badges | Linux/X11 launch ownership and dock/keyboard/minimise restore pass real GNOME verification; Windows GNU checking passes. GNOME incoming-mail sender lifetime, details/private/muted arrival and no-duplicate refresh now pass real-shell verification; temporary-saving notices share the retained worker and cancel with their close attempt. Close to tray is on by default and closing quits normally where no tray host exists. Actual Windows/macOS delivery, audible sound and Wayland activation remain open | Mobile notification/badge equivalents and task/draft restoration verification open | Native single-instance/tray behaviour is not applicable; multiple tabs and their existing profile Web Locks remain intentional. Browser notification permission/privacy/duplicate-tab dispatch remain open |
| Compact rows, adjacent selection after delete, reading layout, F5 refresh, search across folders | Shipped from main (15a4a3c, 91ed9a9, 1bf6ac9, 80f5867, a81d767) | Compact K-9 rows exist; adjacent selection after delete, centred reading column, cross-folder search parity open | Adjacent selection after delete, centred reading column, F5 secondary refresh and cross-folder search parity open |
| Direct download installers, transparent launcher icons, duplicate-address labels | Shipped from main (3676dad, 0f2af1f, ce4a2a6, 15a4a3c, c0ebf3f) | Store/APK distribution open (R69/R72); duplicate-address account labels open | Browser deployment open (R71/R74); duplicate-address account labels open |
| Native accessibility, simulator and E2E coverage | Linux iced MCP suite | Flutter tests, Playwright semantics, Appium Android; Apple execution open | Model tests + Playwright controls/axe/layout; broader coverage open |
| Scheduled out-of-office replies, grouped accounts | R76 active: Preferences → Automatic replies | Open; message/group/date/time parity required | Open; message/group/date/time parity required |
| Distribution and coordinated release | Linux installer; dormant workflows | Android preview/production APKs; production-flavor release development-signed and installed on the authorized phone (R79); launcher icons/distribution signing/store and Apple builds open | Protected build + Rust beta gate; staging supported, VPS deployment pending |
Desktop integration checkpoint¶
The review worktree integrates committed desktop 10d8569: 15-second checks and independent Refresh, relevance search, draft navigation, read-on-leave, counted action toasts/Undo, native HTML/Find, Forward/Print, image reflow anchors, interface scaling, Linux badges and selection/bulk jobs. Independent uncommitted main-worktree edits are excluded. The merge ships for review in 72ca625; verification of this merged branch is recorded separately from imported main evidence in the completion log.
Shared mail types and routed provider transports remain authoritative. Native HTML uses the shared MIME selector with rewritten per-section CID identities; desktop-specific render payloads stay outside the transport crate. Complete-source Forward preparation, formatting metadata and MIME assembly are shared, including the client stable Message-ID entry point. Shared native/WASM fixtures cover binary files, duplicate names with distinct media types, scoped/ambiguous inline images, malformed resources and current limits. WASM retains files outside metadata JSON and exposes exact byte copies. Native/browser draft transactions, metadata ownership, retry/recovery and actual Forward controls now have the evidence recorded in the completion log. Apple and full composition execution remain open. Remaining Print platform/image-policy work, selection/bulk, remaining read-on-leave close/OS lifecycle and durable move-history/recovery, remote-image policy/anchors and OS badges/background lifecycle remain explicit gaps. Desktop request numbers R67 to R80 collide with the client numbers; older notes write main's as desktop-main:RNN, and the request audit states the collision once.
Browser transport and storage¶
A static browser app can be served to other devices over a network; that does not share a mailbox or authorize access to another device's secrets. Each browser has its own storage and provider session. The hosting server serves public promo assets and gates browser assets/API access through the Rust service. It has no persistent mail/password store. Authentication state is in memory; Google OAuth application credentials are deployment configuration, not mailbox credentials.
R74 now authorizes a Rust backend on the email VPS for beta verification and IMAP/POP3/SMTP. This supersedes static-only hosting and the optional local bridge. backend/ implements Google login, an administrator allowlist and bounded mail endpoints using shared/mail-core. All app/API access is gated server-side. Mail endpoints remain disabled until an administrator configures exact hostname/port/IP pins; the browser adapter uses per-identity IndexedDB and tab-memory passwords. Exact owner identity, OAuth configuration and VPS target are pending. Passwords/mail must remain transient on the VPS, with client-side durable state, TLS, bounded queues, per-user isolation and safe SMTP retry semantics before live transport is enabled.
Preference storage contains appearance/layout/shortcuts only, scoped by a hash of the verified Google subject and OAuth client. Production mail/raw MIME, accounts, drafts and delivery records use the matching IndexedDB profile. Passwords stay in tab memory and reconnect is required after reload. The browser cache is not encrypted; secure remembered credentials, encrypted cache and provider OAuth remain open. Fixture mail/drafts/events stay in memory. Never put passwords or refresh tokens in localStorage. Production builds exclude the separate fictional preview entry. The Flutter web build is an automation surface for the mobile UI; it is not the separately requested hosted desktop client.
Sources: K-9 swipe behavior, Flutter integration tests, browser WebSocket transport.
Review and release¶
Use flutter/test/preview_main.dart only for preview builds, with the Android preview flavor (separate package). Production uses flutter/lib/main.dart and the production flavor. Browser production uses web/index.html; preview.html has a separate build output. All artifacts/logs belong under ignored artifacts/.
The disabled quality definition includes the client checks alongside Rust so the existing release trigger still waits for the whole quality workflow. Store signing, Apple distribution and all-client artifact publication remain a release prerequisite; the disabled release workflow refuses publication until a reviewed parity/release-readiness record permits it. The existing documentation deployment workflow is unchanged.
Client text Find shares the desktop Unicode/whitespace contract with original UTF-16 ranges. Saved host, native and browser scenarios are listed in the shared scenario registry (see the testing guide). The completion log records actual execution and shipping; no claim of complete HTML, Apple or final performance parity follows from these fixtures. Mobile notification/badge equivalents remain open.
Shared MIME selection now retains the last supported nonempty alternatives, related-root identity and separate CID scopes for mixed sections. Cache text/replies and file indicators use the same classification; a named inline image is not an attachment unless explicitly attached. Native Rust and WASM use shared fixtures. Flutter prepares the same confined document through two independent native rendering slots and keeps its system WebView mounted through controls and plain-text switching. The separate browser now prepares resource-confined HTML on an independent cancellable worker and renders it in a persistent opaque sandbox. Shared native/WASM preparation tests and saved browser controls cover CSS/tables, inline images, selection/Copy, Find across spans, quote visibility, plain-text choice, links, cancellation/retry and active-content isolation. Native Flutter integration and saved Android/browser controls now have evidence in the completion log; remote-image policy, large-layout bounds and Apple execution remain open. Incoming raw MIME passes an iterative nesting check before the pinned recursive parser. This does not remove the 25 MiB limit, provide streaming, or establish final performance. Mobile/browser selection and bulk-action parity remain active.
The containing website CSP includes the exact shared display-runtime hash; the frame adds a restrictive policy and sandbox="allow-scripts" without same-origin permission. Keep the gateway and web build from the same source revision. Missing/mismatched runtime permission produces a visible plain-text fallback and Retry. The owned runtime alone controls document indexing/highlights; mail scripts, forms, frames and automatic remote resources do not survive preparation. Converted inline images currently retain dimensions up to 2048×2048, with at most 32 MiB of aggregate decoded pixels. These bounds do not fulfill R23 streaming/large-mail work.
Flutter uses Android WebView and iOS WKWebView; iOS targets 14.0 for the shared WebP resources. A separate native semaphore bounds preparation without occupying provider or Find slots. The trusted display bridge rejects stale generations/layouts and coalesces commands. Platform-view and Find accessibility boundaries prevent the search input from intercepting document clicks. Native navigation, device content/file access and permission grants are denied; reviewed external links use the system handler. Flutter browser tests use the same opaque document and a JavaScript identity comparison for its cross-origin window. Remote-image exceptions/loading and Apple execution remain open.
Client Print uses complete cached MIME, independently of provider and formatted-reader capacity. It includes Subject/From/To/Cc/Date, full quoted history, attachment names and bounded inline WebP resources; Bcc and reply-thread headers are excluded. Native Android and the separate browser have actual printer/PDF evidence. UIKit's native adapter is implemented but still needs Apple compilation and execution. Opening or cancelling a dialog is never called successful printing. Remote-image policy, native shortcut parity, large-mail bounds, lifecycle/performance and other browser engines remain open.
Browser group ordering now retains the reviewed message through acknowledged moves and validated canonical aliases. Receipts keep the actual dispatch/Undo folder and UID separately from the frozen review. Persistent metadata and worker projections reject unrelated identity replacements. Saved browser controls cover an Archive group followed by Flag over all 125 messages, plus clearing stale History controls while another group loads; protocol/storage tests cover individual moves, UID recovery, alias rollback/flattening and cache-checkpoint recovery without repeating provider mutations. Final execution and shipping evidence belongs in the completion log. Synchronous Undo before decision storage, native equivalents, broader lifecycle/performance and live-provider/Apple verification remain open.
Browser History progress refreshes independently of Undo-preview preparation. Held real-control and failed-preview/Refresh recovery scenarios preserve completed counts and keep other actions usable. Broader group lifecycle and native equivalents remain open.
Browser saved-group notices inspect indexed failed/unconfirmed/interrupted/cache state across all History pages and open the affected group directly. They do not classify another tab’s running step as unconfirmed. Coalesced status checks retain known targets on failure and reject observations crossing execution boundaries. Native group recovery and the wider lifecycle audit remain open.
The profile prerequisite in shared/profile-core adds bounded operation metadata, explicit account mapping and native/WASM common fixtures; see the format subset. Native validation is observation-only and keeps provider/credential state untouched. The optional native history worker now retains immutable operations, queued upload identities, concurrent values and deletion tombstones, with shared Rust and actual Dart FFI/Android coverage. The optional native Drive transport now verifies provider identity, owned file metadata/media and journal-backed upload recovery through scripted HTTP tests and a shared wire fixture. Fixture HTTP clients share the production redirect policy, so the redirect regression does not depend on a separately configured test policy. The optional discovery catalog now persists pages/file identities, replays arrivals, retains explicit missing/conflicting history and isolates remote summaries from enrolled offline edits. Host protocol/storage tests cover restart, failed receipts, bounded pages, held data/errors and independent-process ownership. Flutter now calls it from Profiles and sync, binding the provider-verified principal to secure Google metadata before exposing contents. Native session ownership and Dart generations fence late data/errors through disconnect, with paged retry/pause/rescan controls. Flutter publication adds frozen account/settings reviews, causal setup markers and tracked own-upload receipts. Flutter enrollment now copies original records into independent local history, reviews account/category choices and applies accounts/preferences with durable receipts and explicit Reconnect status. Full authenticated FFI/Google interchange, automatic setup, browser application, automatic desktop setup, category lifecycle, ongoing reconciliation, remaining portable settings and protected credentials remain open; standalone Node WASM is not browser-control evidence.
Desktop scoped-consent continuation adds explicit Drive backup and Calendar off/read/read-write choices for the next sign-in. Requested permissions remain separate from the active grant, survive saves and bind pending-grant retry/activation; a broader returned Google scope does not enable an unselected service. All 118 native functional scenarios and the protocol/lifecycle checks pass; light/dark/compact captures are reviewed. Flutter native consent now has the separately recorded SDK/host/Android evidence. Browser provider consent, verified profile identity and enrollment remain active R75/R02 gaps; beta login is unchanged.
Desktop Profiles and sync now connects the active Google grant to durable read-only discovery, bounded pages and pause/retry/restart controls. Reviewed desktop publication and account/preferences enrollment are now connected. Automatic setup, complete portable settings/categories and account reconciliation remain active gaps. The portable foreign_move_folders key (other accounts' folders in the Move chooser, R108) now drives the browser Move chooser together with cross_account_moves; Flutter decodes and labels it but its Move flow does not act on it yet.
Desktop publication now freezes account/settings reviews and resumes exact staged/uploaded records through the active grant. The separate browser still needs provider consent, discovery, publication and application; Flutter publication/enrollment is implemented separately, while authenticated cross-client interchange and continuous reconciliation remain open. Native/protocol results belong in the completion log.
Desktop enrollment preserves independent history and upload ownership, frozen 50-row reviews, stable account mappings, durable reconnect guards and newer local preference intent. Matching accounts retain mail/drafts/credentials; a different connection needs explicit selection as a separate account. Browser enrollment and credential handover remain gaps. Linux control, injected keychain and scripted Drive evidence do not establish live Google, Apple or continuous reconciliation.
Desktop profile reviews retain their current page after selection changes or recoverable failures. Native large-list scenarios cover discovery's 50/1 profiles, publication's 50/25 accounts and enrollment's 50/26 account/settings rows, including second-page choices and guarded application. Flutter already reloads the selected enrollment page after a choice; its saved mobile paging controls remain the counterpart. Separate browser enrollment is still open. See the completion log for executed results and shipping.
Desktop ongoing preference sync has reviewed setup, authenticated background scheduling, master/field pause controls and retry/status. Partial catalog-loss recovery checks acknowledged originals against verified inventory, and a new or reconnected owner performs a full scan. Native verification and shipping are in completion; the contract keeps complete settings/categories/accounts and ongoing Flutter/browser equivalents OPEN. Desktop checked preference decisions now have durable 50-row reviews, guarded choices and exact retry after a lost receipt. Flutter/browser decision controls remain OPEN. Sixteen Flutter Rust bridge checks cover the shared-core changes. The additional history export command changes local APIs, not the portable operation format. Existing mobile discovery/publication/enrollment contracts remain required.
Flutter enrollment now preserves original platform preference revisions through native acknowledgment and exact retry. Later or reverted local edits remain local intent, including before the storage reply paints. Native and browser control verification and shipping are recorded in completion; this is a recovery prerequisite for ongoing Flutter synchronization, which remains open.
Main merge parity review — 2026-09-09¶
main c414227 was merged into the client branch. Root desktop code follows main, so the desktop reference column now includes everything main shipped since 10d8569: multiple backup destinations and formats (R32), native tray and temporary saving tray (R86), new-mail notifications (R82), Windows/macOS badge adapters (R70), folder context menus and combined-folder deletion (R30), moved-mail recovery and search across folders (R73/R84), reading layout and F5 refresh (R81/R74), compact rows and adjacent selection after delete (R88/R89), inline composer ownership (R35), complete database export/import and local profiles (R83), main's continuous profile transport, discovery, enrollment, reviews and account linking (R02/R49/R92), the SQLCipher foundation (R22), channel-owned schedulers (R90/R91), palette editor (R25), transparent launcher icons (R64), direct download installers (R61) and duplicate-address labels (R15). Main's desktop profile implementation replaced the client branch's own desktop discovery/publication/enrollment/reconciliation code; the client branch's Flutter profile work (discovery, publication, enrollment, preference receipts) is unchanged and still targets the same shared profile-core contract, which is now a superset of both sides.
Client status after the merge: none of the desktop features above gained a mobile or browser equivalent by the merge itself. The table rows above and the R67/R68/R42/R45/R30/R25/R32/R22 entries in TODO carry the gaps. Shared transport changes from main (a81d767/5eabb52 destination recovery, folder mutation plans and checked provider commands) were ported into shared/mail-core, so Flutter and the browser use the same provider behaviour as the desktop; their UI equivalents for folder mutation review and destination recovery remain open. The mail-core, mail-content and profile-core fixtures in shared/ remain the parity contract; the merged tree has not been re-verified on Android, the Flutter browser or Chromium, and no performance figure was re-measured. Recorded merge-gate results belong in the completion entry "Main merged into the client branch".