mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
docs: clarify message drag routing verification
This commit is contained in:
@@ -1,125 +1,56 @@
|
||||
# Message drag blob routing
|
||||
# Message drag regression tests
|
||||
|
||||
- Worktree: `/home/billy/work/bulwark-deploy/bulwark-drag-out`
|
||||
- Branch: `fix/message-drag-blob-routing`
|
||||
- Audited base and unchanged HEAD: `640d4b8c2e44bcb61b099a5511e06dbd5d7ca537`.
|
||||
The maintained drag tests use synthetic JMAP sessions and message bytes with real
|
||||
JMAP URL expansion, authentication and blob-fetch code. They verify:
|
||||
|
||||
Read repository guidance in `CONTRIBUTING.md`; no applicable `AGENTS.md` was
|
||||
present. The worktree was clean before adding these changes. Before editing the
|
||||
hook, verified that single-message prefetch and ZIP retrieval used the active
|
||||
client without an owner account, and that cache keys omitted routing identity.
|
||||
- Primary, directly shared and secondary-login message routing; each mixed-owner
|
||||
ZIP entry uses its originating client and owner, including colliding IDs.
|
||||
- Account-aware selection and expanded-thread members, filenames and drag payloads.
|
||||
- Pointer entry on actual message rows and thread headers prepares drag content
|
||||
while retaining working hover actions.
|
||||
- Cache identity across clients, owners, messages and blobs; stable-context
|
||||
pending fetches can warm a retry after dragend, while changed contexts and
|
||||
unmounted rows cannot publish stale content. Retired object URLs retain the
|
||||
60-second cleanup grace period.
|
||||
|
||||
The hook now reuses `resolveEmailBlobContext` for each originating message.
|
||||
Selections use the existing account-aware selection resolver, including loaded
|
||||
expanded-thread members. Cache identity includes the authenticated client object,
|
||||
login, owning JMAP account, message identity, blob ID and filename. Drag start
|
||||
checks that identity again; obsolete asynchronous completions cannot replace the
|
||||
current entry and their URLs receive the existing 60-second cleanup grace period.
|
||||
|
||||
`use-email-drag-routing.test.tsx` uses synthetic JMAP sessions and RFC 822 bytes
|
||||
with the real JMAP connection, URL expansion, authentication and blob-fetch code.
|
||||
Both logins use the same synthetic server to exercise authentication collisions.
|
||||
The tests inspect single-message bytes and ZIP entry contents/counts. No real
|
||||
messages or mail server are used. The existing `use-email-drag.test.tsx` assertions
|
||||
are retained unchanged.
|
||||
|
||||
Run the maintained drag regressions with:
|
||||
Run from the repository root with dependencies installed:
|
||||
|
||||
```sh
|
||||
./node_modules/.bin/vitest run hooks/__tests__/use-email-drag.test.tsx hooks/__tests__/use-email-drag-routing.test.tsx --maxWorkers=1 --no-file-parallelism --reporter=verbose
|
||||
./node_modules/.bin/vitest run \
|
||||
hooks/__tests__/use-email-drag.test.tsx \
|
||||
hooks/__tests__/use-email-drag-routing.test.tsx
|
||||
```
|
||||
|
||||
Dependencies were installed from the existing lockfile using `npm ci --cache
|
||||
/tmp/bulwark-drag-out-npm-cache --no-audit --no-fund --ignore-scripts`. Dependencies,
|
||||
Vitest caches and Next build outputs belong to this worktree; no sibling
|
||||
worktree or cache was modified.
|
||||
## Limitations
|
||||
|
||||
## Row hover and lifecycle correction
|
||||
`DownloadURL` must be available synchronously at dragstart. Hover preparation or
|
||||
a later attempt may be necessary when the cache is cold. Fetch completion never
|
||||
adds a file to a drag already in progress. Ready single-message caches are
|
||||
retired on dragend, so another hover may be needed before a later attempt.
|
||||
|
||||
Single-message rows and thread headers now call both the existing hover-action
|
||||
handler and the hook's hover-prefetch handler. The maintained tests render the
|
||||
real `ThreadListItem` and its real hover actions and drag hook, using synthetic
|
||||
network responses with real JMAP URL/authentication code.
|
||||
ZIP export silently omits failed fetches, messages without blob IDs and messages
|
||||
whose source login is unavailable. An archive can contain fewer entries than its
|
||||
filename suggests, or be empty if every eligible fetch fails. Partial or failed
|
||||
bundle builds remain cached until their cache key changes; the same selection
|
||||
is not automatically retried.
|
||||
|
||||
A single-message fetch that is still pending when dragend fires can finish into
|
||||
the cache for a later drag. Completion checks both the current cache entry and
|
||||
its freshly resolved client/owner/message identity. Navigation to another owner
|
||||
or login, message/blob changes, and unmount cannot publish obsolete bytes.
|
||||
Already-ready single-message URLs retain the existing dragend retirement and
|
||||
60-second revocation grace period. ZIP caches still survive dragend.
|
||||
## Manual desktop verification
|
||||
|
||||
## Remaining cold-cache limitation
|
||||
DataTransfer, object URLs and browser user agents are mocked under jsdom. Tests
|
||||
check payload construction, synthetic message/ZIP bytes and URL lifetime; these
|
||||
assertions do not establish native desktop file creation.
|
||||
|
||||
`DownloadURL` is written only synchronously during dragstart when the matching
|
||||
cache is ready. A cold first drag can still show the email preview and support
|
||||
internal mailbox dragging while providing no desktop file. Fetch completion
|
||||
never changes that drag's DataTransfer. If the pending request finishes after
|
||||
dragend in the same context, the next drag can use it synchronously. If it
|
||||
finishes before dragend, dragend retires that ready cache as before, so another
|
||||
hover-prefetch must warm the row before a later attempt. No asynchronous
|
||||
DataTransfer updates or native desktop delivery guarantees were added.
|
||||
1. In a supported desktop Chromium browser, hover a message row, confirm its
|
||||
hover actions still work, then drag its sender/subject area to the desktop.
|
||||
Confirm that an `.eml` file is created. Repeat for primary, shared and
|
||||
secondary-login messages using controlled test data.
|
||||
2. Try a cold-cache drag. If no file is created, allow preparation to complete,
|
||||
hover again and retry. Check file creation separately from the drag preview
|
||||
and successful network responses.
|
||||
3. Select controlled messages from multiple clients/owners, allow preparation,
|
||||
and drag them to the desktop. Confirm that a ZIP file is created; separately
|
||||
inspect its expected entry count and message contents.
|
||||
|
||||
## Remaining failure-handling gap
|
||||
|
||||
ZIP retrieval still silently skips failed entries, messages without blob IDs and
|
||||
messages whose source login is unavailable. An archive can contain fewer entries
|
||||
than the selection count in its filename; if every eligible fetch fails it can
|
||||
be empty. Failed/partial bundle builds remain cached until the selection/routing
|
||||
key changes. The regression suite explicitly retains the existing partial-failure
|
||||
behavior. No failure UI or unrelated export behavior was redesigned.
|
||||
|
||||
DataTransfer, object URLs and browser user agents are mocked under jsdom. These
|
||||
checks verify payload construction, routing, archive bytes and URL retirement;
|
||||
native browser/desktop drag-to-filesystem behavior has not been verified.
|
||||
|
||||
## Initial routing validation
|
||||
|
||||
- Exact final regression tests with only the hook replaced by the audited base:
|
||||
**20 failed, 4 passed**. Direct shared-folder requests used the primary owner;
|
||||
secondary-login requests used primary credentials; mixed ZIP contents were
|
||||
incorrect. The fixed hook was restored byte-for-byte after the replay.
|
||||
- With the fix: **24/24 drag tests passed**, including the retained original test.
|
||||
The broader focused drag/blob/account-selection/thread run passed **138/138**
|
||||
tests across seven files.
|
||||
- `npm run typecheck`: passed.
|
||||
- `npm run lint`: passed; 16 warnings in unchanged files. Targeted lint on the
|
||||
changed hook/test passed without warnings.
|
||||
- `npm run build`: passed; 16 filesystem-tracing warnings in unchanged files.
|
||||
- `git diff --check`, plus whitespace checks on both new files: passed.
|
||||
- `vitest run --maxWorkers=2`: **8,377 passed, 2 skipped, 1 failed**, across 783
|
||||
test files. The sole failure is `lib/__tests__/idn.test.ts:39`, where
|
||||
`toAsciiDomain('xn--zz.de')` returns the input instead of `null`. It also fails
|
||||
in isolation. Both the test and `lib/idn.ts` are byte-identical to the audited
|
||||
base; neither imports the drag hook. This unrelated behavior was left unchanged.
|
||||
|
||||
Session logs are in `/tmp/bulwark-drag-out-base-final-tests.log`,
|
||||
`/tmp/bulwark-drag-out-focused.log`, `/tmp/bulwark-drag-out-unit-tests.log`,
|
||||
`/tmp/bulwark-drag-out-final-drag-and-idn.log`, and the corresponding
|
||||
`bulwark-drag-out-{typecheck,lint,build}.log` files. No integration suite, real
|
||||
mailbox operation or native desktop drag verification was run. Nothing was
|
||||
staged, committed, pushed or published.
|
||||
|
||||
## Row/lifecycle validation
|
||||
|
||||
Before correcting the current uncommitted routing patch, the extended routing
|
||||
suite had **5 failures and 28 passes**. The failures were:
|
||||
|
||||
- Single-message row pointer entry did not start blob prefetch.
|
||||
- Thread-header pointer entry did not start ZIP prefetch.
|
||||
- Pointer entry on a selected real row did not prefetch the mixed-owner ZIP.
|
||||
- A pending cold drag could not supply `DownloadURL` on a retry after dragend and
|
||||
fetch completion, both through direct hook handlers and through the real row.
|
||||
|
||||
After correction, the drag suites passed **34/34** tests, including all retained
|
||||
original assertions. The focused row/drag/routing/selection/thread/context/JMAP
|
||||
run passed **262/262** tests across **17 files**. `npm run typecheck` passed;
|
||||
`npm run lint` passed with 16 warnings in unchanged files. Whitespace checks
|
||||
passed. The prior full-suite and build results above describe the initial
|
||||
routing validation; those broader checks were not repeated for this correction.
|
||||
|
||||
The before/after evidence is in `/tmp/bulwark-drag-out-lifecycle-before.log` and
|
||||
`/tmp/bulwark-drag-out-lifecycle-after.log`; the focused, typecheck and lint logs
|
||||
use the same prefix. The existing proxy, Next configuration, environment files,
|
||||
package manifest and lockfile were preserved byte-for-byte. Dependencies were
|
||||
unchanged. Native Chrome-to-Windows desktop file creation remains unverified
|
||||
until manually tested. Nothing was staged, committed or pushed.
|
||||
Record the browser version, operating system, file-creation results and whether
|
||||
ZIP entry contents were actually inspected. Observing a payload or a successful
|
||||
GET alone is not a successful native desktop check.
|
||||
|
||||
Reference in New Issue
Block a user