feat: save search views and review unsubscribe actions#139

merged6
main
feat/saved-views-and-unsubscribe
opened4d agobySScreen
View on GitHubTwo-way sync enabledPR last imported 3d ago

Summary

Problem: Searches cannot be saved by name, and the reader has no reviewed List-Unsubscribe action.

Closes https://git.cafe/collection-of-devs/aggregate-mail/issues/57 Closes https://git.cafe/collection-of-devs/aggregate-mail/issues/58

Result: Save an encrypted query, account, mailbox, filters and sort as a named view, then open, rename or delete it through Commands. Review an unsubscribe destination before an HTTPS request, ordinary mailto draft or manual browser handoff. The integration preserves Contacts navigation and supports opening a saved query from Contacts.

Changelog: Unreleased describes both features. Repository knowledge and ADR 0099 document behavior and outbound-request limits.

Stack

  1. #140 Contacts and provider export imports, base main.
  2. #139 Saved views and reviewed unsubscribe, base feat/contacts-page-imports (this PR).

Merge bottom first, then refresh this PR onto the merged target before merging it. The App, navigation-test and changelog overlaps between these features are resolved in this stack.

Evidence

  • Before: No named-view persistence or Commands actions; no List-Unsubscribe reader path. The original Windows suite failed because a macOS fixture expected POSIX ownership checks to succeed without that API. After: Synthetic tests cover encrypted persistence/restart, filter restoration, keyboard editing, privacy, Contacts-to-saved-view navigation, three unsubscribe paths, malformed headers, DNS validation and no request before confirmation. The fixture retains all rejection cases and skips only its unsupported positive case without the ownership API. Production updater checks are unchanged.
Verification

Current combined revision fa52cd0bb9a512826d5f1b4349cfbe71dd3fb8ec, based on Contacts 1597831218000b6852a8f6d1869caa2d1b7d88c4 and main e13e9401053b88b91ec03ba5042675e98740fc49. Linux, Node 24.22.1, synthetic data only.

  • Final bounded npm test: 1523 passed, 0 failed, exit 0. This covers the complete combined stack on its exact revision.

  • Final npm run build: exit 0; strict TypeScript and production bundles pass. Existing bundle-size advisory remains.

  • Focused Contacts and saved-view integration: 3/3 pass, exit 0 before the unchanged-source phone-parent update.

  • Synthetic missing-POSIX-API regression: reproduced before the fix; 3 rejection cases pass and the unsupported positive case skips after correction. POSIX runs all four cases. This corrects the earlier Windows fixture failure; current native Windows acceptance remains unknown.

  • Isolated npm run check:desktop under Xvfb: exit 0, startup: passed, database opened, renderer loaded, isolated API and background close passed, packaged: false, Electron 44.9.3 on Linux x86_64. The owned process and fixed-port listener exited. The empty profile used the documented Linux local-key fallback with its visible warning; this is not system-keyring or installed acceptance proof.

  • node scripts/check-commit-emails.mjs feat/contacts-page-imports..HEAD and full outgoing history check: exit 0; original authors and new commits use GitHub noreply identities.

  • git diff --check and new local Markdown links pass. Tests/builds run serially with external memory and deadline containment.

  • No real email, unsubscribe request or account change was made. Installed visuals, native passkey/browser handoff and live-provider acceptance remain unknown. No release performed.

  • For application changes, npm test and npm run build pass; list the checks that apply to this change. Exact revision and results are above.

  • No mail content, addresses, account names, credentials or local paths in the diff, fixtures, logs or screenshots. Fixtures contain only synthetic identities and example-domain destinations; no personal data is included.

  • Documentation that this change makes wrong is updated in the same pull request.

Ownership and scope
  • Task owner: screen for the original implementation; maintainer-directed readiness follow-up by pekth.
  • Delivery owner (one writer): pekth's coding agent for this follow-up. Original commit authorship retained.
  • Owned paths: saved-view and unsubscribe modules/tests under server/shared/src; App, search and reader integration; affected styles, changelog, KB and ADR 0099. The shared updater fixture correction is inherited from #140.
  • Base branch and feature branch: main -> feat/saved-views-and-unsubscribe.
  • Related issue or pull request: the two linked git.cafe issues; bottom PR #140.
  • Coordination search completed; current owner confirmed: existing task and PR records inspected; readiness work stays on this PR. Foreign work preserved.
Review
  • Independent reviewer: separate coding agent. Current stacked source verdict: ship, no findings.
  • Reviewed base and head revisions: 1597831218000b6852a8f6d1869caa2d1b7d88c4 to fa52cd0bb9a512826d5f1b4349cfbe71dd3fb8ec, tree e07202273bd86947b9a37c3e85762e77da50cfde.
  • Required checks and approvals: local results above; forge state read back before handoff. No hosted run dispatched manually.
  • Blocking feedback resolved: main and cross-PR conflicts resolved, ADR numbers distinct, Windows fixture corrected, final verification completed.
  • Native, live-account or release proof still needed, if applicable: installed behavior and live-provider acceptance remain unknown. DKIM verification is not claimed; destinations are labeled as unauthenticated sender data.

Merge risk

Rollback: Revert this PR's squash commit. Encrypted saved definitions and prepared drafts remain. A completed external unsubscribe cannot be undone by reverting the code.

Affected scope: Cached search, Commands/privacy, MIME metadata and explicitly reviewed unsubscribe actions. POST validates every DNS answer, pins a public address, uses a five-second deadline and follows no redirects, without cookies or authorization. The system browser controls subsequent requests for manual links. Merge is approved to publish the combined 0.2.18 update through the existing automatic release workflow. Versioned release notes are prepared in CHANGELOG.md. Installed behavior and live-provider acceptance remain unverified.

Current integration: #140 merged as 26c4952d773f9c63e17254fbb427bf53d1e38b94; this PR is rebased onto that main commit at e5ba9f25a678eee60bc75d3d5534f57d6d3ab652. Before the documentation-only release header, the tree was byte-identical to the fully tested fa52cd0 candidate. Full-suite, build and isolated startup evidence above remains applicable to unchanged runtime inputs. Current-base independent review: ship, no findings, base 26c4952d773f9c63e17254fbb427bf53d1e38b94, head e5ba9f25a678eee60bc75d3d5534f57d6d3ab652, tree 2637371afca7b714f777e14a711d8eb5623d9f5e. Range-diff confirms implementation equivalence; only the release changelog heading changed.

Checks

3 skipped
All checks passed
e5ba9f2

Added 6 commits

  • test: correct portable updater fixture and disambiguate unsubscribe ADR0737263
  • test: cover opening saved search views from Contacts0746272
  • feat: save encrypted named search views5f8b00b
  • feat: review unsubscribe destinations before acting9265d8e
  • docs: number unsubscribe decision after merged phone decisionsead689b
  • docs: prepare 0.2.18 release notese5ba9f2