> mail-collector@0.14.1 test > node scripts/run-tests.mjs ✔ account sync payload is encrypted with a separate recovery key (8.969041ms) ✔ account sync payload rejects the wrong recovery key (0.848333ms) ✔ relay uses optimistic revisions and keeps tombstones (14.182166ms) ✔ a remote revision inserted between pull and push is not skipped (196.464209ms) ✔ two devices replicate an encrypted account and later observe its tombstone (233.645459ms) ✔ hashes passwords and rejects incorrect credentials (129.989417ms) ✔ normalizes email addresses and handles session cookies (1.318625ms) ✔ stores one administrator and expiring sessions (207.581375ms) ✔ migrates legacy administrator columns to email fields (96.4505ms) ✔ encrypts and decrypts a secret (1.368042ms) ✔ rejects a modified encrypted secret (0.205375ms) ✔ upgrades v0.5.1 without changing data or old revisions and runs once (418.593917ms) ✔ upgrades legacy UID identity without changing data or old revisions and runs once (167.381708ms) ✔ a failed legacy adoption rolls back schema changes and its marker (97.844792ms) ✔ Ptah rolls back an unsuccessful SQL migration, including FTS objects (149.511667ms) ✔ stores messages once and removes them with their account (308.706417ms) ✔ atomically resets messages when UIDVALIDITY changes (98.704ms) ✔ relativeDetailTime shows just now under one minute (0.877084ms) ✔ relativeDetailTime shows minutes under one hour (0.118459ms) ✔ relativeDetailTime shows hours for same-day older mail (0.065584ms) ✔ relativeDetailTime omits future and day-old relative labels (0.081625ms) ✔ later today stays in the future before 18:00 (1.636125ms) ✔ later today rolls to tomorrow morning after 18:00 (0.09ms) ✔ tomorrow is next day at 08:00 (0.058291ms) ✔ next monday always advances to a future Monday (0.056ms) ✔ migrates legacy messages to inbox received state (367.231458ms) ✔ supports folders, snooze, labels, bulk actions, and local conflict preservation (108.430875ms) ✔ stores and updates drafts, creates sent copies, and preserves local records on mailbox reset (76.834959ms) ✔ classifies confident subscription, work, and personal messages (2.15475ms) ✔ automatically labels inserted mail and preserves manual labels during reclassification (307.36075ms) {"event":"webhook_received","at":"2026-10-03T10:27:08.117Z","account_id":1,"provider":"imap","sync_job_id":null,"reason":"event-2"} {"event":"webhook_received","at":"2026-10-03T10:27:08.120Z","account_id":1,"provider":"imap","sync_job_id":null,"reason":"event-1"} {"event":"webhook_received","at":"2026-10-03T10:27:08.120Z","account_id":1,"provider":"imap","sync_job_id":null,"reason":"event-3"} {"event":"mail_sync_started","at":"2026-10-03T10:27:08.122Z","account_id":1,"provider":"imap","sync_job_id":1,"sync_type":"incremental"} {"event":"mail_sync_completed","at":"2026-10-03T10:27:08.124Z","account_id":1,"provider":"imap","sync_job_id":1,"sync_type":"incremental","webhook_to_sync_latency":2,"mail_sync_duration":2,"mail_sync_changes_count":1,"inserted":1,"mailbox_reset":false} {"event":"mail_sync_started","at":"2026-10-03T10:27:08.222Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial"} ✔ coalesces duplicate and out-of-order account events into one incremental job (256.176416ms) {"event":"mail_sync_completed","at":"2026-10-03T10:27:08.231Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial","webhook_to_sync_latency":null,"mail_sync_duration":10,"mail_sync_changes_count":0,"inserted":0,"mailbox_reset":false} ✔ serializes concurrent synchronization for the same account (103.6805ms) {"event":"mail_sync_started","at":"2026-10-03T10:27:08.521Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"incremental"} {"event":"cursor_invalid","at":"2026-10-03T10:27:08.521Z","account_id":1,"provider":"imap","sync_job_id":null} {"event":"mail_sync_completed","at":"2026-10-03T10:27:08.522Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"incremental","webhook_to_sync_latency":null,"mail_sync_duration":1,"mail_sync_changes_count":1,"inserted":1,"mailbox_reset":true} {"event":"mail_sync_started","at":"2026-10-03T10:27:08.568Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial"} {"event":"mail_sync_retry","at":"2026-10-03T10:27:08.569Z","account_id":1,"provider":"imap","sync_job_id":null,"attempt":1,"delay_ms":750,"error_kind":"rate_limited"} {"event":"mail_sync_completed","at":"2026-10-03T10:27:08.569Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial","webhook_to_sync_latency":null,"mail_sync_duration":1,"mail_sync_changes_count":0,"inserted":0,"mailbox_reset":false} {"event":"mail_sync_started","at":"2026-10-03T10:27:08.621Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial"} {"event":"mail_sync_failed","at":"2026-10-03T10:27:08.621Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial","error_kind":"reauth_required","error":"authentication failed"} {"event":"operation_failed","at":"2026-10-03T10:27:08.714Z","account_id":1,"provider":"imap","sync_job_id":1,"operation_id":1,"operation":"mark_read","retry_at":"2026-10-03T10:27:09.464Z","error":"network timeout"} ✔ reclaims account and job leases after a worker crash (112.245958ms) ✔ rolls back a partial batch and cursor advancement, then retries idempotently (109.076416ms) ✔ recovers an invalid incremental cursor with a scoped initial sync (69.788125ms) ✔ retries provider rate limits with backoff and marks authentication failures for reauthorization (99.363625ms) ✔ uses tombstones for provider and local deletion without physical row loss (51.047ms) {"event":"backfill_progress","at":"2026-10-03T10:27:09.557Z","account_id":1,"provider":"imap","sync_job_id":null,"inserted":2,"next_cursor":7,"complete":false} {"event":"backfill_progress","at":"2026-10-03T10:27:09.558Z","account_id":1,"provider":"imap","sync_job_id":null,"inserted":1,"next_cursor":null,"complete":true} ✔ retries a durable optimistic write operation and succeeds (842.775875ms) ✔ resumes paged backfill after restart without duplicating messages (42.249042ms) {"event":"webhook_received","at":"2026-10-03T10:27:09.606Z","account_id":1,"provider":"imap","sync_job_id":null,"reason":"imap_idle_exists"} {"event":"mail_sync_started","at":"2026-10-03T10:27:09.661Z","account_id":2,"provider":"imap","sync_job_id":null,"sync_type":"initial"} {"event":"mail_sync_started","at":"2026-10-03T10:27:09.661Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial"} ✔ debounces IMAP IDLE events and stops watchers for disabled accounts (58.369333ms) {"event":"mail_sync_completed","at":"2026-10-03T10:27:09.674Z","account_id":2,"provider":"imap","sync_job_id":null,"sync_type":"initial","webhook_to_sync_latency":null,"mail_sync_duration":13,"mail_sync_changes_count":0,"inserted":0,"mailbox_reset":false} {"event":"mail_sync_completed","at":"2026-10-03T10:27:09.685Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial","webhook_to_sync_latency":null,"mail_sync_duration":24,"mail_sync_changes_count":0,"inserted":0,"mailbox_reset":false} {"event":"mail_sync_started","at":"2026-10-03T10:27:09.735Z","account_id":1,"provider":"imap","sync_job_id":1,"sync_type":"incremental"} {"event":"mail_sync_failed","at":"2026-10-03T10:27:09.735Z","account_id":1,"provider":"imap","sync_job_id":1,"sync_type":"incremental","error_kind":"rate_limited","error":"too many requests"} {"event":"mail_sync_started","at":"2026-10-03T10:27:09.841Z","account_id":2,"provider":"imap","sync_job_id":null,"sync_type":"initial"} {"event":"mail_sync_started","at":"2026-10-03T10:27:09.841Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial"} {"event":"mail_sync_completed","at":"2026-10-03T10:27:09.842Z","account_id":2,"provider":"imap","sync_job_id":null,"sync_type":"initial","webhook_to_sync_latency":null,"mail_sync_duration":1,"mail_sync_changes_count":0,"inserted":0,"mailbox_reset":false} {"event":"mail_sync_failed","at":"2026-10-03T10:27:09.842Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial","error_kind":"permanent","error":"邮箱已停用"} {"event":"mail_sync_started","at":"2026-10-03T10:27:09.912Z","account_id":1,"provider":"imap","sync_job_id":1,"sync_type":"incremental"} {"event":"mail_sync_failed","at":"2026-10-03T10:27:09.913Z","account_id":1,"provider":"imap","sync_job_id":1,"sync_type":"incremental","error_kind":"transient","error":"operation was aborted"} ✔ limits concurrent requests independently per provider (68.61325ms) ✔ does not multiply provider retries inside a durable job attempt (68.834875ms) ✔ drops provider work waiting on concurrency when the account is disabled (88.022083ms) ✔ returns an aborted in-flight job to the durable queue during shutdown (70.593542ms) ✔ FTS follows insert, upsert, deferred body fetch, draft edit and account deletion (121.930792ms) ✔ 30,000 existing messages retain substring search results and use the trigram index (2184.1715ms) ℹ Upgrade and FTS backfill: 540.1 ms for 30,000 messages ℹ Mean selective count, 20 runs: LIKE 9.21 ms; FTS 0.32 ms. Timing is diagnostic, not a CI threshold. ✔ blocks loopback, private, link-local, and reserved mail addresses (11.042084ms) ✔ allows public addresses and an explicit private-network override (0.239084ms) ✔ allows proxy fake-IP DNS only for built-in TLS mail providers (344.761875ms) ✔ Google OAuth starts an authorization-code PKCE flow without a client secret (2.7555ms) ✔ Microsoft OAuth uses the native-app localhost callback and mail protocol scopes (0.253667ms) ✔ OAuth markers are encrypted and distinguish OAuth accounts from legacy passwords (5.13275ms) ✔ OAuth is disabled cleanly when a provider client ID is not configured (0.334792ms) ✔ VPS refreshes an imported OAuth credential with its per-account Client ID (49.887209ms) ✔ derives SMTP settings from supported IMAP hosts without opening a connection (1.91425ms) {"event":"mail_sync_started","at":"2026-10-03T10:27:08.546Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial"} {"event":"mail_sync_completed","at":"2026-10-03T10:27:08.548Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial","webhook_to_sync_latency":null,"mail_sync_duration":2,"mail_sync_changes_count":1,"inserted":1,"mailbox_reset":false} {"event":"mail_sync_started","at":"2026-10-03T10:27:08.604Z","account_id":2,"provider":"imap","sync_job_id":null,"sync_type":"initial"} {"event":"mail_sync_started","at":"2026-10-03T10:27:08.604Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial"} {"event":"mail_sync_failed","at":"2026-10-03T10:27:08.605Z","account_id":2,"provider":"imap","sync_job_id":null,"sync_type":"initial","error_kind":"reauth_required","error":"authentication failed"} {"event":"mail_sync_completed","at":"2026-10-03T10:27:08.605Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial","webhook_to_sync_latency":null,"mail_sync_duration":1,"mail_sync_changes_count":0,"inserted":0,"mailbox_reset":false} {"event":"mail_sync_started","at":"2026-10-03T10:27:08.658Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial"} {"event":"mail_sync_failed","at":"2026-10-03T10:27:08.659Z","account_id":1,"provider":"imap","sync_job_id":null,"sync_type":"initial","error_kind":"permanent","error":"connection failed"} ✔ records inserted messages and advances the last UID (69.205417ms) ✔ reports per-account failures when synchronizing all accounts (56.834042ms) ✔ records a synchronization error (53.317167ms) ✔ parseVersion accepts release tags and semantic versions (2.866791ms) ✔ compareVersions compares numeric semantic version parts (0.133917ms) ✔ release helpers require installer and checksum assets (0.113541ms) ℹ tests 61 ℹ suites 0 ℹ pass 61 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 2834.204625