BETTER SETTINGS: organise Settings so it feels non-overwhelming and close to the User (grill pending); includes Connected Accounts #407

Open
opened 2026-09-29 06:47:26 +00:00 by kayg · 124 comments
Owner

Request (owner, 2026-09-29)

"instead of having two sign in forms in Mail and Calendar, this stuff should live in Settings → Integrations and we should have checkboxes after the fact for mail/calendar/contacts"

Grill (open; do not build until answered and recorded in DESIGN.md)

  • I1 One account per provider sign-in in Settings → Integrations (iCloud, Fastmail, Gmail, Other; one app password), then checkboxes Mail / Calendar / Contacts, on by default where the provider supports them; unticking stops that service's sync. Recommended: yes.
  • I2 Settings → Mail and Settings → Calendars keep only per-service preferences and link to the account; no second sign-in form anywhere. Recommended: yes.
  • I3 Integrations = external accounts calternal signs in to; Apps = clients signing in to calternal (API, CLI, MCP, WebMCP, App Passwords). Recommended: yes.
  • I4 Gmail: IMAP works with an app password, but Google CalDAV/CardDAV need OAuth (#67, OPEN). Show Calendar/Contacts disabled with "needs Google sign-in (coming later)". Recommended: yes.
  • I5 Contacts checkbox hidden until Contacts (#297) exists; the account remembers the preference. Recommended: hide.
  • I6 Migrate existing Mail accounts and CalDAV calendars into Integrations accounts (merge when server and user match), no re-sign-in, credentials stay encrypted. Recommended: yes.
## Request (owner, 2026-09-29) "instead of having two sign in forms in Mail and Calendar, this stuff should live in Settings → Integrations and we should have checkboxes after the fact for mail/calendar/contacts" ## Grill (open; do not build until answered and recorded in DESIGN.md) - I1 One account per provider sign-in in Settings → Integrations (iCloud, Fastmail, Gmail, Other; one app password), then checkboxes Mail / Calendar / Contacts, on by default where the provider supports them; unticking stops that service's sync. Recommended: yes. - I2 Settings → Mail and Settings → Calendars keep only per-service preferences and link to the account; no second sign-in form anywhere. Recommended: yes. - I3 Integrations = external accounts calternal signs in to; Apps = clients signing in to calternal (API, CLI, MCP, WebMCP, App Passwords). Recommended: yes. - I4 Gmail: IMAP works with an app password, but Google CalDAV/CardDAV need OAuth (#67, OPEN). Show Calendar/Contacts disabled with "needs Google sign-in (coming later)". Recommended: yes. - I5 Contacts checkbox hidden until Contacts (#297) exists; the account remembers the preference. Recommended: hide. - I6 Migrate existing Mail accounts and CalDAV calendars into Integrations accounts (merge when server and user match), no re-sign-in, credentials stay encrypted. Recommended: yes.
Author
Owner

Decided (owner, 2026-09-29), recorded in DESIGN §49: I1 yes (Apple's Internet Accounts model); I2 yes; I3 yes; I4 Google OAuth if possible without a licence — research in #408; I5 hide Contacts until it exists; I6 no migration, users add accounts again.

Decided (owner, 2026-09-29), recorded in DESIGN §49: I1 yes (Apple's Internet Accounts model); I2 yes; I3 yes; I4 Google OAuth if possible without a licence — research in #408; I5 hide Contacts until it exists; I6 no migration, users add accounts again.
Author
Owner

Starting #407 on branch job/integrations, based on c46515046871936ad681c4d00e8b76de69dde3b7 (dev at worktree start). I am reading the recorded decisions and tracing the existing mail and CalDAV account stores before changing account/settings code.

Starting #407 on branch `job/integrations`, based on `c46515046871936ad681c4d00e8b76de69dde3b7` (`dev` at worktree start). I am reading the recorded decisions and tracing the existing mail and CalDAV account stores before changing account/settings code.
Author
Owner

Finding: Mail M1 currently stores its app-password envelope in mail_accounts; Calendar stores a separate credential envelope in calendar_accounts. Mail sync reads credentials from mail_accounts, and Calendar refresh reads them from calendar_accounts. This means a single Integrations sign-in needs one shared credential record plus service rows that reference it; duplicating the secret would preserve the current split model rather than satisfy §49.

Finding: Mail M1 currently stores its app-password envelope in `mail_accounts`; Calendar stores a separate credential envelope in `calendar_accounts`. Mail sync reads credentials from `mail_accounts`, and Calendar refresh reads them from `calendar_accounts`. This means a single Integrations sign-in needs one shared credential record plus service rows that reference it; duplicating the secret would preserve the current split model rather than satisfy §49.
Author
Owner

Progress: the shared Index account and credential layer is committed as 892cab35 (feat(db): store one shared integration credential). It stores one encrypted envelope per provider account, binds it to the User and stable account ID, and records Mail/Calendar support and enablement separately.

Focused gate output:

test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.28s

test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 1.27s

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Progress: the shared Index account and credential layer is committed as `892cab35` (`feat(db): store one shared integration credential`). It stores one encrypted envelope per provider account, binds it to the User and stable account ID, and records Mail/Calendar support and enablement separately. Focused gate output: ``` test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.28s test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 1.27s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ```
Author
Owner

Finding: the existing Mail and Calendar account PATCH/DELETE routes can change one service projection without changing the shared Integration row. I am making those routes reject changes for linked accounts and routing service toggles through the central Integration API. I am also persisting CardDAV discovery for future Contacts support while keeping the Contacts control hidden per I5.

Decision not specified in DESIGN: an account deep link uses /settings/integrations/accounts?account=<stable-account-id>. Copy link returns to that exact account row. I will keep this route in the final report for owner confirmation.

Finding: the existing Mail and Calendar account PATCH/DELETE routes can change one service projection without changing the shared Integration row. I am making those routes reject changes for linked accounts and routing service toggles through the central Integration API. I am also persisting CardDAV discovery for future Contacts support while keeping the Contacts control hidden per I5. Decision not specified in DESIGN: an account deep link uses `/settings/integrations/accounts?account=<stable-account-id>`. Copy link returns to that exact account row. I will keep this route in the final report for owner confirmation.
Author
Owner

Finding: Mail IMAP already pinned its socket to a public DNS answer, but the new CalDAV and autoconfiguration HTTP requests only validated DNS before reqwest resolved the host again. That left a DNS-rebinding path to private addresses. The setup probes now share the public-endpoint resolver and pin reqwest to its validated addresses; integrated Calendar clients repeat that resolution and pinning on each operation. These pinned requests also bypass environment proxies so the proxy cannot perform a second, unchecked resolution.

Finding: Mail IMAP already pinned its socket to a public DNS answer, but the new CalDAV and autoconfiguration HTTP requests only validated DNS before reqwest resolved the host again. That left a DNS-rebinding path to private addresses. The setup probes now share the public-endpoint resolver and pin reqwest to its validated addresses; integrated Calendar clients repeat that resolution and pinning on each operation. These pinned requests also bypass environment proxies so the proxy cannot perform a second, unchecked resolution.
Author
Owner

Finding: the first implementation rejected the state where both service checkboxes were off. The issue says each checkbox controls that service's sync independently, so I removed the last-service restriction. The shared account and credential stay saved, while both sync projections can be disabled and re-enabled later.

Finding: the first implementation rejected the state where both service checkboxes were off. The issue says each checkbox controls that service's sync independently, so I removed the last-service restriction. The shared account and credential stay saved, while both sync projections can be disabled and re-enabled later.
Author
Owner

Follow-up decision: the account schema already has a CHECK constraint that requires Mail or Calendar to remain enabled, and the existing database test asserts that invariant. I restored the UI/API guard and kept that existing behavior. Each service can be switched off while the other remains on; Disconnect removes the account. The issue does not state whether both may be off, so I retained the schema invariant for owner confirmation.

Follow-up decision: the account schema already has a CHECK constraint that requires Mail or Calendar to remain enabled, and the existing database test asserts that invariant. I restored the UI/API guard and kept that existing behavior. Each service can be switched off while the other remains on; Disconnect removes the account. The issue does not state whether both may be off, so I retained the schema invariant for owner confirmation.
Author
Owner

Finding: the existing Mail table rejects a duplicate owner/email/IMAP endpoint, and Calendar rejects a duplicate owner/endpoint. Because #407 does not migrate legacy accounts, trying to add one of those accounts through Integrations could hit a service projection unique index after the central row was inserted and return HTTP 500. The transaction rolls back; Mail and Calendar projection unique violations now return HTTP 409 with a fixed message.

Finding: the existing Mail table rejects a duplicate owner/email/IMAP endpoint, and Calendar rejects a duplicate owner/endpoint. Because #407 does not migrate legacy accounts, trying to add one of those accounts through Integrations could hit a service projection unique index after the central row was inserted and return HTTP 500. The transaction rolls back; Mail and Calendar projection unique violations now return HTTP 409 with a fixed message.
Author
Owner

Finding: Mail's existing row menu still showed Turn off for Integration-backed Mail accounts. That action called the legacy Mail endpoint, which correctly returns 409 because the shared account must be changed in Integrations. Linked rows now show Manage in Integrations and hide the legacy service toggle and Disconnect actions. A UI test covers this menu.

Finding: Mail's existing row menu still showed Turn off for Integration-backed Mail accounts. That action called the legacy Mail endpoint, which correctly returns 409 because the shared account must be changed in Integrations. Linked rows now show Manage in Integrations and hide the legacy service toggle and Disconnect actions. A UI test covers this menu.
Author
Owner

Implementation report

Built and pushed job/integrations at head 90071e870a179203ec97326ee3f2e9a9ae00a626.

Delivered

  • Added the shared Integration account API and encrypted credential storage. Mail and Calendar read the same credential, with service projections written in one transaction.
  • Added Settings → Integrations with iCloud, Fastmail, Gmail, and Other. Other checks Mozilla mail autoconfig and .well-known CalDAV/CardDAV endpoints. Mail and Calendar settings now link to the shared account.
  • Added owner and scope isolation, bounded provider probes, public-only outbound endpoint checks, input limits, and the real-server hostile-input probe.
  • Generated and committed the OpenAPI contract and TypeScript client types. The contract check found 284 operation IDs and no duplicates.
  • Captured and attached production screenshots for Integrations, Mail, and Calendar at 390, 820, and 1440 px in light and dark themes. The probe asserted each theme before capture.

Focused gate output

cargo test -p calternal-plugin
Finished `test` profile [unoptimized + debuginfo] target(s) in 7m 46s
 test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.38s
cargo test -p calternal-plugin-mail
Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 20s
 test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.88s
cargo test -p calternal-plugin-calendar
Finished `test` profile [unoptimized + debuginfo] target(s) in 60m 22s
 test result: ok. 49 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.54s
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s
 test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s
cargo test -p calternal-server
Finished `test` profile [unoptimized + debuginfo] target(s) in 6m 33s
 test result: ok. 83 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 28.79s
bun run --cwd apps/web test -- src/routes/settings/integrations/IntegrationsSection.svelte.test.ts src/routes/settings/mail/MailSection.svelte.test.ts src/routes/settings/sections.test.ts
 Test Files  3 passed (3)
      Tests  13 passed (13)
Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed

Decisions and known gaps

  • Account deep links use /settings/integrations/accounts?account=<stable account id>.
  • Other uses Mozilla autoconfig plus imap.<domain> / smtp.<domain> fallback and .well-known DAV discovery.
  • At least one of Mail or Calendar must stay enabled. The existing database CHECK and test enforce this; the issue did not decide the both-off state.
  • Existing accounts are not migrated. Contacts remain hidden until #297. Gmail Calendar waits for #408. The adversarial probe used no real provider credential or login.
  • The job reached the four-hour limit before the final merge and full workspace gates. git merge dev, cargo fmt --check, cargo clippy --all-targets -- -D warnings, full cargo test, bun run --cwd apps/web check, and full bun run --cwd apps/web test remain outstanding. The focused tests above and one endpoint-specific adversarial round passed.

Screenshot attachments

Integrations

Mail

Calendar

## Implementation report Built and pushed `job/integrations` at head `90071e870a179203ec97326ee3f2e9a9ae00a626`. ### Delivered - Added the shared Integration account API and encrypted credential storage. Mail and Calendar read the same credential, with service projections written in one transaction. - Added Settings → Integrations with iCloud, Fastmail, Gmail, and Other. Other checks Mozilla mail autoconfig and `.well-known` CalDAV/CardDAV endpoints. Mail and Calendar settings now link to the shared account. - Added owner and scope isolation, bounded provider probes, public-only outbound endpoint checks, input limits, and the real-server hostile-input probe. - Generated and committed the OpenAPI contract and TypeScript client types. The contract check found 284 operation IDs and no duplicates. - Captured and attached production screenshots for Integrations, Mail, and Calendar at 390, 820, and 1440 px in light and dark themes. The probe asserted each theme before capture. ### Focused gate output ```text cargo test -p calternal-plugin Finished `test` profile [unoptimized + debuginfo] target(s) in 7m 46s test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.38s ``` ```text cargo test -p calternal-plugin-mail Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 20s test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.88s ``` ```text cargo test -p calternal-plugin-calendar Finished `test` profile [unoptimized + debuginfo] target(s) in 60m 22s test result: ok. 49 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.54s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s ``` ```text cargo test -p calternal-server Finished `test` profile [unoptimized + debuginfo] target(s) in 6m 33s test result: ok. 83 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 28.79s ``` ```text bun run --cwd apps/web test -- src/routes/settings/integrations/IntegrationsSection.svelte.test.ts src/routes/settings/mail/MailSection.svelte.test.ts src/routes/settings/sections.test.ts Test Files 3 passed (3) Tests 13 passed (13) ``` ```text Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed ``` ### Decisions and known gaps - Account deep links use `/settings/integrations/accounts?account=<stable account id>`. - Other uses Mozilla autoconfig plus `imap.<domain>` / `smtp.<domain>` fallback and `.well-known` DAV discovery. - At least one of Mail or Calendar must stay enabled. The existing database CHECK and test enforce this; the issue did not decide the both-off state. - Existing accounts are not migrated. Contacts remain hidden until #297. Gmail Calendar waits for #408. The adversarial probe used no real provider credential or login. - The job reached the four-hour limit before the final merge and full workspace gates. `git merge dev`, `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, full `cargo test`, `bun run --cwd apps/web check`, and full `bun run --cwd apps/web test` remain outstanding. The focused tests above and one endpoint-specific adversarial round passed. ### Screenshot attachments **Integrations** - [390 light](https://git.kayg.org/attachments/588ab593-1df7-4671-8d20-b895ba7b565a) · [390 dark](https://git.kayg.org/attachments/697b466f-8e95-446e-a640-bc07788891c7) - [820 light](https://git.kayg.org/attachments/b9d4e1be-2aca-4665-b586-19f4f06d65b6) · [820 dark](https://git.kayg.org/attachments/b63429bc-abf1-4995-bb7b-01ff838d1f12) - [1440 light](https://git.kayg.org/attachments/99821351-f980-4c5d-a403-1e2b789f81db) · [1440 dark](https://git.kayg.org/attachments/57cfcb23-12f1-4932-b8e0-68cdeedf8d24) **Mail** - [390 light](https://git.kayg.org/attachments/6672cb8d-c0b3-4c1e-8012-3d747143a415) · [390 dark](https://git.kayg.org/attachments/757db9f5-bb53-434a-92cc-8fb8db892588) - [820 light](https://git.kayg.org/attachments/fa0474a4-6e8a-4602-adab-2ceb9b68e5fe) · [820 dark](https://git.kayg.org/attachments/23166f6a-1dc4-469e-a640-bc07788891c7) - [1440 light](https://git.kayg.org/attachments/3a8663bd-bc15-45b9-a4d5-110ef0c4cc76) · [1440 dark](https://git.kayg.org/attachments/2c9df99b-f98a-4712-8ab2-19e5acd3a31a) **Calendar** - [390 light](https://git.kayg.org/attachments/5263b286-7d72-4322-b16a-a9afb41ef49b) · [390 dark](https://git.kayg.org/attachments/19a428be-f344-4825-ae9f-ff8ce47b38bc) - [820 light](https://git.kayg.org/attachments/6c0e6dd4-353c-48a5-a5d8-e0ec903da162) · [820 dark](https://git.kayg.org/attachments/5638a1a0-83e4-44aa-a7e6-6306a9761940) - [1440 light](https://git.kayg.org/attachments/bf63b88e-922e-4509-bdd3-bfbc06e75140) · [1440 dark](https://git.kayg.org/attachments/91bb14ce-3655-42de-8109-508f9d00a621)
Author
Owner

Starting #407 on branch job/integrations. Current head: 90071e870a. Current merge-base with dev: c465150468 (dev is 70fce97594). Continuing after visual review rejection with the Apple-style provider chooser, provider-specific sheet, service switches, and connected account status requested in the job.

Starting #407 on branch job/integrations. Current head: 90071e870a179203ec97326ee3f2e9a9ae00a626. Current merge-base with dev: c46515046871936ad681c4d00e8b76de69dde3b7 (dev is 70fce975945c272c7ed7f3e1844949e818ac778f). Continuing after visual review rejection with the Apple-style provider chooser, provider-specific sheet, service switches, and connected account status requested in the job.
Author
Owner

Finding: IntegrationsSection.svelte still renders a segmented provider control and shows username/server fields in the default flow. Its empty state contains #297, “source of truth,” and “encrypted app password,” which are internal terms the requested screen must not show. IntegrationAccountView exposes enablement but no sync state; the existing Mail sync endpoint exposes last_error and backfill_complete, and Calendar account rows expose last_error. I will compose status from those real account APIs and use their existing retry operations.

Finding: `IntegrationsSection.svelte` still renders a segmented provider control and shows username/server fields in the default flow. Its empty state contains `#297`, “source of truth,” and “encrypted app password,” which are internal terms the requested screen must not show. `IntegrationAccountView` exposes enablement but no sync state; the existing Mail sync endpoint exposes `last_error` and `backfill_complete`, and Calendar account rows expose `last_error`. I will compose status from those real account APIs and use their existing retry operations.
Author
Owner

Decision for #407: add Yahoo as a supported provider preset because it is explicitly requested and Yahoo documents an app password plus IMAP/SMTP and CalDAV access (https://help.yahoo.com/kb/SLN4075.html, https://help.yahoo.com/kb/SLN4707.html). The current API contract has no Outlook preset, so I will omit Outlook. Provider marks will use neutral calternal glyphs with provider names; I will not copy brand artwork without a verified usage guideline.

Decision for #407: add Yahoo as a supported provider preset because it is explicitly requested and Yahoo documents an app password plus IMAP/SMTP and CalDAV access (https://help.yahoo.com/kb/SLN4075.html, https://help.yahoo.com/kb/SLN4707.html). The current API contract has no Outlook preset, so I will omit Outlook. Provider marks will use neutral calternal glyphs with provider names; I will not copy brand artwork without a verified usage guideline.
Author
Owner

Finding: the existing integration_accounts.provider CHECK rejects Yahoo with SQLite code 275 (CHECK constraint failed: provider IN (\x27icloud\x27, \x27fastmail\x27, \x27gmail\x27, \x27other\x27)). I added a migration regression test that inserts an existing Fastmail account before the provider migration, then checks that the account remains after Yahoo is enabled.

Finding: the existing `integration_accounts.provider` CHECK rejects Yahoo with SQLite code 275 (`CHECK constraint failed: provider IN (\x27icloud\x27, \x27fastmail\x27, \x27gmail\x27, \x27other\x27)`). I added a migration regression test that inserts an existing Fastmail account before the provider migration, then checks that the account remains after Yahoo is enabled.
Author
Owner

Progress: committed the Yahoo provider storage migration as 2b24ed67. The migration widens the provider CHECK while preserving existing credentials and service selections. Evidence: cargo test -p calternal-db passed (15 unit tests; 16 passed, 1 ignored in integration tests), and cargo clippy -p calternal-db --all-targets -- -D warnings passed. The server API and Settings flow are in progress.

Progress: committed the Yahoo provider storage migration as 2b24ed67. The migration widens the provider CHECK while preserving existing credentials and service selections. Evidence: `cargo test -p calternal-db` passed (15 unit tests; 16 passed, 1 ignored in integration tests), and `cargo clippy -p calternal-db --all-targets -- -D warnings` passed. The server API and Settings flow are in progress.
Author
Owner

Progress: the Settings flow now has provider rows, provider-specific setup sheets, initial Mail/Calendars switches, stable provider/account links, and connected-account status with retry. The focused UI suite passes: 5 tests passed. Connected status comes from the existing Mail and Calendar APIs; the error-row test uses test fixtures only. Rust API gates and production screenshot proof remain in progress.

Progress: the Settings flow now has provider rows, provider-specific setup sheets, initial Mail/Calendars switches, stable provider/account links, and connected-account status with retry. The focused UI suite passes: 5 tests passed. Connected status comes from the existing Mail and Calendar APIs; the error-row test uses test fixtures only. Rust API gates and production screenshot proof remain in progress.
Author
Owner

Progress update: the Yahoo provider migration commit is 036a8bbf (the earlier progress note named its pre-amend hash). The chooser, provider-specific setup sheets, service switches, connected-account status rows, and focused UI tests are now implemented. Current focused UI result: 1 file passed, 5 tests passed. The local review harness covers the requested 48 screenshots. Remaining: finish server clippy/tests, merge dev once, run final gates and the production screenshot matrix, then attach the evidence here.

Progress update: the Yahoo provider migration commit is `036a8bbf` (the earlier progress note named its pre-amend hash). The chooser, provider-specific setup sheets, service switches, connected-account status rows, and focused UI tests are now implemented. Current focused UI result: 1 file passed, 5 tests passed. The local review harness covers the requested 48 screenshots. Remaining: finish server clippy/tests, merge `dev` once, run final gates and the production screenshot matrix, then attach the evidence here.
Author
Owner

Finding: the first cargo clippy -p calternal-server --all-targets -- -D warnings run stopped in crates/calternal-plugin/src/outbound.rs:57 and :63 with clippy::needless_return. git blame shows both lines were added in this integrations branch's outbound DNS helper (87fc9aec). Removing the two unnecessary return keywords preserves the validated-address behavior and lets the server gate reach this route.

Finding: the first `cargo clippy -p calternal-server --all-targets -- -D warnings` run stopped in `crates/calternal-plugin/src/outbound.rs:57` and `:63` with `clippy::needless_return`. `git blame` shows both lines were added in this integrations branch's outbound DNS helper (`87fc9aec`). Removing the two unnecessary `return` keywords preserves the validated-address behavior and lets the server gate reach this route.
Author
Owner

Resolved finding: the two unnecessary returns in the outbound DNS helper were removed without changing its address validation. Per-crate gates passed for the helper crate:

cargo clippy -p calternal-plugin --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 9m 06s

cargo test -p calternal-plugin
running 24 tests
test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.30s
Doc-tests calternal_plugin: 0 passed, 0 failed

The fix is committed as c28e6f44. I will repeat the required gates on the single merged dev tree before the final report.

Resolved finding: the two unnecessary returns in the outbound DNS helper were removed without changing its address validation. Per-crate gates passed for the helper crate: ```text cargo clippy -p calternal-plugin --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 9m 06s cargo test -p calternal-plugin running 24 tests test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.30s Doc-tests calternal_plugin: 0 passed, 0 failed ``` The fix is committed as `c28e6f44`. I will repeat the required gates on the single merged `dev` tree before the final report.
Author
Owner

Finding: the first server all-targets check reached the API source and caught an incomplete Yahoo mapping in mail_settings at crates/calternal-server/src/integrations.rs:399: Provider::Yahoo was missing from the MailProvider match (E0004). The fix maps the Yahoo preset to the existing MailProvider::Custom projection and adds an assertion to the Yahoo preset unit test. The same attempt also showed the server binary embeds apps/web/build; I will build the production SPA before repeating this gate.

Finding: the first server all-targets check reached the API source and caught an incomplete Yahoo mapping in `mail_settings` at `crates/calternal-server/src/integrations.rs:399`: `Provider::Yahoo` was missing from the `MailProvider` match (`E0004`). The fix maps the Yahoo preset to the existing `MailProvider::Custom` projection and adds an assertion to the Yahoo preset unit test. The same attempt also showed the server binary embeds `apps/web/build`; I will build the production SPA before repeating this gate.
Author
Owner

Finding after the required dev merge: the production SPA build failed with Could not resolve '../parts/AccountRow.svelte' in IntegrationsSection.svelte:13. The merge brings the shared SettingsRow from #402 and removes AccountRow; I am moving the connected account row to SettingsRow, which supports the stable anchor, selection, status, actions, and full-width service controls used here.

Finding after the required `dev` merge: the production SPA build failed with `Could not resolve '../parts/AccountRow.svelte'` in `IntegrationsSection.svelte:13`. The merge brings the shared `SettingsRow` from #402 and removes `AccountRow`; I am moving the connected account row to `SettingsRow`, which supports the stable anchor, selection, status, actions, and full-width service controls used here.
Author
Owner

The post-merge cargo clippy -p calternal-server --all-targets -- -D warnings gate found two collapsible_if errors: the Mail re-enable sync queue condition in integrations.rs:986 and the nested integration-key guard in system_plugin.rs:70. Both were folded into let-chain conditions without changing behavior. I am rerunning the server gates now.

The post-merge `cargo clippy -p calternal-server --all-targets -- -D warnings` gate found two `collapsible_if` errors: the Mail re-enable sync queue condition in `integrations.rs:986` and the nested integration-key guard in `system_plugin.rs:70`. Both were folded into let-chain conditions without changing behavior. I am rerunning the server gates now.
Author
Owner

The production screenshot run captured the chooser at 390 px in light mode, then stopped at iCloud because the provider-heading locator used a non-exact name and matched both the sheet title and the page heading. I am tightening that locator to the exact provider label before recapturing the full 48-image matrix.

The production screenshot run captured the chooser at 390 px in light mode, then stopped at iCloud because the provider-heading locator used a non-exact name and matched both the sheet title and the page heading. I am tightening that locator to the exact provider label before recapturing the full 48-image matrix.
Author
Owner

The exact-label locator passed iCloud, Google, Fastmail, and Yahoo, then found two identical “Other account” headings. The sheet title and form heading share that label, so the exact match is still ambiguous for Other. I am scoping the wait to the provider form heading id and will rerun the matrix.

The exact-label locator passed iCloud, Google, Fastmail, and Yahoo, then found two identical “Other account” headings. The sheet title and form heading share that label, so the exact match is still ambiguous for Other. I am scoping the wait to the provider form heading id and will rerun the matrix.
Author
Owner

The review harness captured all eight 390 px light states. On the first dark state it detected that the app correctly maps the paper family to its midnight palette, while the harness expected the light palette name. I am updating the fixture to expect midnight in dark mode, then will capture the full matrix again.

The review harness captured all eight 390 px light states. On the first dark state it detected that the app correctly maps the paper family to its midnight palette, while the harness expected the light palette name. I am updating the fixture to expect `midnight` in dark mode, then will capture the full matrix again.
Author
Owner

The first connected-list screenshots showed the shared row icon centered on its title-and-meta stack, several pixels below the email cap line. I added a SettingsRow title-alignment option using CSS lh and cap units and enabled it on the connected Mail, Calendar, and Integration account rows. I am rebuilding and recapturing before attaching evidence.

The first connected-list screenshots showed the shared row icon centered on its title-and-meta stack, several pixels below the email cap line. I added a `SettingsRow` title-alignment option using CSS `lh` and `cap` units and enabled it on the connected Mail, Calendar, and Integration account rows. I am rebuilding and recapturing before attaching evidence.
Author
Owner

Integrations #407 complete

Branch: job/integrations
Head: 16d6b06c7b9372945becc00c40370c336f2c10e3
Working tree: clean. The single required dev merge is included. No push, deployment, or merge was performed.

Built

  • Replaced the generic connection form with provider rows and provider-specific sheets for iCloud, Google/Gmail, Fastmail, Yahoo, and Other. Preset sheets ask for email and app password, include provider help links, and show supported Mail/Calendar switches. Other keeps username and server fields under Advanced.
  • Added connected-account rows with enabled services, Syncing/Error state, Retry, Copy link, and service switches. Deep links use /settings/integrations/accounts?account=<id>.
  • Added Yahoo as a persisted provider, used its published IMAP/SMTP/CalDAV endpoints, and stored selected services with their Mail/Calendar projections in one transaction. Mail is tested and its initial sync is queued only when Mail is enabled. At least one supported service must remain enabled.
  • Reused the shared Settings card and row. Added cap-line icon alignment for account rows and kept Mail/Calendar account links pointed at Integrations.
  • Regenerated the OpenAPI contract and API client; added the adversarial probe and the production-SPA screenshot harness.

Files

Cargo.lock
apps/web/e2e/integrations-review.mjs
apps/web/package.json
apps/web/src/routes/settings/[...path]/+page.svelte
apps/web/src/routes/settings/calendars/CalendarsSection.svelte
apps/web/src/routes/settings/integrations/IntegrationsSection.svelte
apps/web/src/routes/settings/integrations/IntegrationsSection.svelte.test.ts
apps/web/src/routes/settings/mail/MailSection.svelte
apps/web/src/routes/settings/mail/MailSection.svelte.test.ts
apps/web/src/routes/settings/parts/SettingsRow.svelte
apps/web/src/routes/settings/sections.test.ts
apps/web/src/routes/settings/sections.ts
contracts/openapi.json
crates/calternal-db/Cargo.toml
crates/calternal-db/src/integrations.rs
crates/calternal-db/src/lib.rs
crates/calternal-db/src/migrations.rs
crates/calternal-db/src/migrations/0007_integrations.sql
crates/calternal-db/src/migrations/0008_integration_carddav.sql
crates/calternal-db/src/migrations/0009_yahoo_provider.sql
crates/calternal-plugin/Cargo.toml
crates/calternal-plugin/src/lib.rs
crates/calternal-plugin/src/outbound.rs
crates/calternal-server/Cargo.toml
crates/calternal-server/src/integrations.rs
crates/calternal-server/src/main.rs
crates/calternal-server/src/system_plugin.rs
crates/calternal-server/src/wire.rs
crates/plugins/calendar/src/cache/crypto.rs
crates/plugins/calendar/src/cache/mod.rs
crates/plugins/calendar/src/cache/store.rs
crates/plugins/calendar/src/client/mod.rs
crates/plugins/calendar/src/items.rs
crates/plugins/calendar/src/routes.rs
crates/plugins/calendar/src/search.rs
crates/plugins/calendar/src/view.rs
crates/plugins/calendar/tests/cache.rs
crates/plugins/mail/src/cache.rs
crates/plugins/mail/src/cache/store.rs
crates/plugins/mail/src/crypto.rs
crates/plugins/mail/src/imap.rs
crates/plugins/mail/src/lib.rs
crates/plugins/mail/src/routes.rs
crates/plugins/mail/src/sync.rs
packages/api-client/src/generated.ts
tests/adversarial/integrations_api.mjs
tests/adversarial/run.sh

Gates

Output excerpts are verbatim. cargo fmt --all --check exited 0 with empty stdout.

cargo clippy -p calternal-db --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 03s

cargo test -p calternal-db
 test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.82s
 test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.85s
 test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 11s

cargo test -p calternal-plugin
 test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.13s
 test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-server --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 23.86s

cargo test -p calternal-server
 test result: ok. 87 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 46.47s

bun run check
Text sizes use shared role tokens.
svelte-check found 0 errors and 0 warnings

bun run test
 Test Files  129 passed (129)
      Tests  820 passed (820)

bun run build
✓ built in 29.86s
  Wrote site to "build"
  ✔ done

packages/api-client/check-generated.sh
✨ openapi-typescript 7.13.0
🚀 ../../contracts/openapi.json → src/generated.ts [944.3ms]

bun run test:e2e:integrations-review
PASS Integrations review: 48 screenshots in /home/kayg/Developer/calternal-wt/integrations/artifacts/integrations

bun tests/adversarial/integrations_api.mjs
Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed

cargo clean
     Removed 15507 files, 8.1GiB total

The API-client check exited 0 with no generated diff. Screenshots are untracked and not committed; all 48 PNGs are attached to this issue. Web build output was deleted after capture. Cargo search confirmed the manifest/lock versions used for chacha20poly1305 0.11.0, getrandom 0.4.3, quick-xml 0.42.0, url 2.5.8, and tokio 1.53.1.

Decisions

  • Yahoo was added because the requested chooser includes it. The Mail projection uses its existing Custom provider value because the Mail provider enum has no Yahoo variant; the shared account retains Yahoo identity.
  • Outlook is omitted because the current presets do not support it.
  • Recognized providers use a neutral globe mark and visible provider names because no reviewed brand assets were available in this account UI.
  • Calendar starts enabled only when discovery finds support. Gmail Calendar stays off until Google sign-in exists. The database invariant requires at least one supported service enabled.
  • Contacts controls stay hidden until the Contacts plugin exists. The sheet says: “Contacts will appear here when calternal supports them.”

Known gaps

  • No Contacts plugin or Google Calendar sign-in is available yet, and there is no Outlook preset.
  • The screenshot account and error rows are Playwright fixtures; no live provider credential was used. The API adversarial probe ran against a real local server and rejected hostile input before provider login.
  • Production build output includes existing Rolldown warnings about vendored analytics "use client" directives; the build exited 0.
  • Rust gates were run per touched crate as required; the full-workspace gates remain with the orchestrator.
# Integrations #407 complete Branch: `job/integrations` Head: `16d6b06c7b9372945becc00c40370c336f2c10e3` Working tree: clean. The single required `dev` merge is included. No push, deployment, or merge was performed. ## Built - Replaced the generic connection form with provider rows and provider-specific sheets for iCloud, Google/Gmail, Fastmail, Yahoo, and Other. Preset sheets ask for email and app password, include provider help links, and show supported Mail/Calendar switches. Other keeps username and server fields under Advanced. - Added connected-account rows with enabled services, Syncing/Error state, Retry, Copy link, and service switches. Deep links use `/settings/integrations/accounts?account=<id>`. - Added Yahoo as a persisted provider, used its published IMAP/SMTP/CalDAV endpoints, and stored selected services with their Mail/Calendar projections in one transaction. Mail is tested and its initial sync is queued only when Mail is enabled. At least one supported service must remain enabled. - Reused the shared Settings card and row. Added cap-line icon alignment for account rows and kept Mail/Calendar account links pointed at Integrations. - Regenerated the OpenAPI contract and API client; added the adversarial probe and the production-SPA screenshot harness. ## Files ```text Cargo.lock apps/web/e2e/integrations-review.mjs apps/web/package.json apps/web/src/routes/settings/[...path]/+page.svelte apps/web/src/routes/settings/calendars/CalendarsSection.svelte apps/web/src/routes/settings/integrations/IntegrationsSection.svelte apps/web/src/routes/settings/integrations/IntegrationsSection.svelte.test.ts apps/web/src/routes/settings/mail/MailSection.svelte apps/web/src/routes/settings/mail/MailSection.svelte.test.ts apps/web/src/routes/settings/parts/SettingsRow.svelte apps/web/src/routes/settings/sections.test.ts apps/web/src/routes/settings/sections.ts contracts/openapi.json crates/calternal-db/Cargo.toml crates/calternal-db/src/integrations.rs crates/calternal-db/src/lib.rs crates/calternal-db/src/migrations.rs crates/calternal-db/src/migrations/0007_integrations.sql crates/calternal-db/src/migrations/0008_integration_carddav.sql crates/calternal-db/src/migrations/0009_yahoo_provider.sql crates/calternal-plugin/Cargo.toml crates/calternal-plugin/src/lib.rs crates/calternal-plugin/src/outbound.rs crates/calternal-server/Cargo.toml crates/calternal-server/src/integrations.rs crates/calternal-server/src/main.rs crates/calternal-server/src/system_plugin.rs crates/calternal-server/src/wire.rs crates/plugins/calendar/src/cache/crypto.rs crates/plugins/calendar/src/cache/mod.rs crates/plugins/calendar/src/cache/store.rs crates/plugins/calendar/src/client/mod.rs crates/plugins/calendar/src/items.rs crates/plugins/calendar/src/routes.rs crates/plugins/calendar/src/search.rs crates/plugins/calendar/src/view.rs crates/plugins/calendar/tests/cache.rs crates/plugins/mail/src/cache.rs crates/plugins/mail/src/cache/store.rs crates/plugins/mail/src/crypto.rs crates/plugins/mail/src/imap.rs crates/plugins/mail/src/lib.rs crates/plugins/mail/src/routes.rs crates/plugins/mail/src/sync.rs packages/api-client/src/generated.ts tests/adversarial/integrations_api.mjs tests/adversarial/run.sh ``` ## Gates Output excerpts are verbatim. `cargo fmt --all --check` exited 0 with empty stdout. ```text cargo clippy -p calternal-db --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 03s cargo test -p calternal-db test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.82s test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.85s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s cargo clippy -p calternal-plugin --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 11s cargo test -p calternal-plugin test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.13s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s cargo clippy -p calternal-server --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 23.86s cargo test -p calternal-server test result: ok. 87 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 46.47s bun run check Text sizes use shared role tokens. svelte-check found 0 errors and 0 warnings bun run test Test Files 129 passed (129) Tests 820 passed (820) bun run build ✓ built in 29.86s Wrote site to "build" ✔ done packages/api-client/check-generated.sh ✨ openapi-typescript 7.13.0 🚀 ../../contracts/openapi.json → src/generated.ts [944.3ms] bun run test:e2e:integrations-review PASS Integrations review: 48 screenshots in /home/kayg/Developer/calternal-wt/integrations/artifacts/integrations bun tests/adversarial/integrations_api.mjs Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed cargo clean Removed 15507 files, 8.1GiB total ``` The API-client check exited 0 with no generated diff. Screenshots are untracked and not committed; all 48 PNGs are attached to this issue. Web build output was deleted after capture. Cargo search confirmed the manifest/lock versions used for `chacha20poly1305` 0.11.0, `getrandom` 0.4.3, `quick-xml` 0.42.0, `url` 2.5.8, and `tokio` 1.53.1. ## Decisions - Yahoo was added because the requested chooser includes it. The Mail projection uses its existing `Custom` provider value because the Mail provider enum has no Yahoo variant; the shared account retains Yahoo identity. - Outlook is omitted because the current presets do not support it. - Recognized providers use a neutral globe mark and visible provider names because no reviewed brand assets were available in this account UI. - Calendar starts enabled only when discovery finds support. Gmail Calendar stays off until Google sign-in exists. The database invariant requires at least one supported service enabled. - Contacts controls stay hidden until the Contacts plugin exists. The sheet says: “Contacts will appear here when calternal supports them.” ## Known gaps - No Contacts plugin or Google Calendar sign-in is available yet, and there is no Outlook preset. - The screenshot account and error rows are Playwright fixtures; no live provider credential was used. The API adversarial probe ran against a real local server and rejected hostile input before provider login. - Production build output includes existing Rolldown warnings about vendored analytics `"use client"` directives; the build exited 0. - Rust gates were run per touched crate as required; the full-workspace gates remain with the orchestrator.
Author
Owner

Starting round 3 of #407.

  • Branch: job/integrations
  • Base SHA: 9bf3d549b41f5fe97c29148220a1a9c484faf63d (current merge-base with origin/dev)
  • Starting HEAD: 16d6b06c7b9372945becc00c40370c336f2c10e3

I am applying the resolved §49 provider-capability defaults and finishing the chooser, provider sheet, and connected-account row fixes. I will fetch and merge origin/dev once before final gates, then report the gate output and capture set here.

Starting round 3 of #407. - Branch: `job/integrations` - Base SHA: `9bf3d549b41f5fe97c29148220a1a9c484faf63d` (current merge-base with `origin/dev`) - Starting HEAD: `16d6b06c7b9372945becc00c40370c336f2c10e3` I am applying the resolved §49 provider-capability defaults and finishing the chooser, provider sheet, and connected-account row fixes. I will fetch and merge `origin/dev` once before final gates, then report the gate output and capture set here.
Author
Owner

Round 3 finding: the attached chooser capture shows the same globe on iCloud, Google, Fastmail, Yahoo, and Other, with a separate Copy link control on every provider row. The iCloud capture shows Calendars off, and its Services legend sits 18 px farther right than the email field. The connected error capture shows Copy link and Disconnect as separate actions beside Retry.

I checked the providers’ official mark terms before choosing glyphs: Apple requires express authorization for its graphic marks, Google’s published G asset rules cover approved Google sign-in buttons (this flow uses app passwords), Fastmail grants limited approved use and bars logo distribution, and Yahoo requires express permission unless a use is expressly allowed. The component records the source URLs and uses distinct neutral glyphs instead.

Round 3 finding: the attached chooser capture shows the same globe on iCloud, Google, Fastmail, Yahoo, and Other, with a separate Copy link control on every provider row. The iCloud capture shows Calendars off, and its Services legend sits 18 px farther right than the email field. The connected error capture shows Copy link and Disconnect as separate actions beside Retry. I checked the providers’ official mark terms before choosing glyphs: Apple requires express authorization for its graphic marks, Google’s published G asset rules cover approved Google sign-in buttons (this flow uses app passwords), Fastmail grants limited approved use and bars logo distribution, and Yahoo requires express permission unless a use is expressly allowed. The component records the source URLs and uses distinct neutral glyphs instead. - Apple: https://www.apple.com/legal/intellectual-property/guidelinesfor3rdparties.html - Google: https://developers.google.com/identity/branding-guidelines - Fastmail: https://www.fastmail.com/policies/brand-guidelines/ - Yahoo: https://legal.yahoo.com/us/en/yahoo/permissions/requests/index.html
Author
Owner

Progress: committed the chooser and connected-row fixes as 816319f5, then merged the once-fetched origin/dev (918b4764a) cleanly. Current head is 791cd7a7dcb95d0b65989e6423197bd2a4f0e2b0.

Focused UI tests passed (7 tests). Post-merge cargo fmt --check passed with empty output, and bun run check reported svelte-check found 0 errors and 0 warnings. The migration audit found no collision: origin/dev has DB migrations 0001–0006; this branch keeps 0007–0009.

The full bun run test suite is running. Next are the requested per-crate gates, production screenshot matrix, API-client check and integrations adversarial probe.

Progress: committed the chooser and connected-row fixes as `816319f5`, then merged the once-fetched `origin/dev` (`918b4764a`) cleanly. Current head is `791cd7a7dcb95d0b65989e6423197bd2a4f0e2b0`. Focused UI tests passed (7 tests). Post-merge `cargo fmt --check` passed with empty output, and `bun run check` reported `svelte-check found 0 errors and 0 warnings`. The migration audit found no collision: `origin/dev` has DB migrations `0001`–`0006`; this branch keeps `0007`–`0009`. The full `bun run test` suite is running. Next are the requested per-crate gates, production screenshot matrix, API-client check and integrations adversarial probe.
Author
Owner

Finding: the post-merge full web suite exited 1 with 2 failed | 127 passed (129) files and 2 failed | 826 passed (828) tests. Both failures hit the configured 5 s timeout: the first Integrations test and the unchanged ThemePicker variant test. The focused Integrations suite passed all 7 tests before the full run. At the end of the run, ps showed Vitest active in both this worktree and agenda-413 for about 3 minutes. This is timing evidence under concurrent CPU load; no existing assertion was changed. I am recording the failed full-suite gate rather than increasing its timeout.

Finding: the post-merge full web suite exited 1 with `2 failed | 127 passed (129)` files and `2 failed | 826 passed (828)` tests. Both failures hit the configured 5 s timeout: the first Integrations test and the unchanged ThemePicker variant test. The focused Integrations suite passed all 7 tests before the full run. At the end of the run, `ps` showed Vitest active in both this worktree and `agenda-413` for about 3 minutes. This is timing evidence under concurrent CPU load; no existing assertion was changed. I am recording the failed full-suite gate rather than increasing its timeout.
Author
Owner

Starting round 3 on branch job/integrations. Current HEAD: 791cd7a7d (includes the prior merge of origin/dev). I am fixing provider marks, chooser actions and provider sheet layout, then I will run the requested web and Rust gates and refresh artifacts/integrations screenshots.

Starting round 3 on branch job/integrations. Current HEAD: 791cd7a7d (includes the prior merge of origin/dev). I am fixing provider marks, chooser actions and provider sheet layout, then I will run the requested web and Rust gates and refresh artifacts/integrations screenshots.
Author
Owner

Finding from the supplied artifacts: the three flagged 1440px PNGs still show the earlier chooser and account row (shared globe icons, visible Copy link/Disconnect pills, and the old right-overlapping setup card). The current source at 816319f5b already uses distinct glyphs, overflow menus, a centered glass OverlaySurface and provider capability defaults. I am rebuilding the production binary and refreshing the evidence matrix so the screenshots match the reviewed source; I will fix any remaining layout issue visible in the new captures.

Finding from the supplied artifacts: the three flagged 1440px PNGs still show the earlier chooser and account row (shared globe icons, visible Copy link/Disconnect pills, and the old right-overlapping setup card). The current source at 816319f5b already uses distinct glyphs, overflow menus, a centered glass OverlaySurface and provider capability defaults. I am rebuilding the production binary and refreshing the evidence matrix so the screenshots match the reviewed source; I will fix any remaining layout issue visible in the new captures.
Author
Owner

Resuming round 3 on branch job/integrations. HEAD: 8ffc68b980; origin/dev: 55a2f90feb; merge base: 918b4764ad. Worktree was clean. Continuing the requested chooser, provider sheet, service defaults, and connected-row menu fixes, then gates and visual captures.

Resuming round 3 on branch job/integrations. HEAD: 8ffc68b980a1a91103ce24e1fe2297297b2b508a; origin/dev: 55a2f90feb8a52d91f8bbc1347889b509af02260; merge base: 918b4764aded5aa385ef784acb8887cf4361bf36. Worktree was clean. Continuing the requested chooser, provider sheet, service defaults, and connected-row menu fixes, then gates and visual captures.
Author
Owner

Merge finding: origin/dev added a second Mail sign-in form, which conflicts with DESIGN §49 I2. I am keeping the Integrations-only setup already on this branch and preserving origin/dev's independent Mail read-marking preference and reader/cache features.

Merge finding: origin/dev added a second Mail sign-in form, which conflicts with DESIGN §49 I2. I am keeping the Integrations-only setup already on this branch and preserving origin/dev's independent Mail read-marking preference and reader/cache features.
Author
Owner

Round 3 resumed on job/integrations at 8ffc68b98, after origin/dev merge 791cd7a7d. This worktree has unrelated staged changes outside integrations; I am preserving those and continuing only the remaining #407 fixes.

Round 3 resumed on job/integrations at 8ffc68b98, after origin/dev merge 791cd7a7d. This worktree has unrelated staged changes outside integrations; I am preserving those and continuing only the remaining #407 fixes.
Author
Owner

Owner decision (2026-09-30): the section is named Connected Accounts, not "Integrations".

  • Connected Accounts: external services calternal signs in to (iCloud, Fastmail, Gmail, Other).
  • Apps: clients that sign in to calternal (App Passwords, CLI, MCP, WebMCP). Unchanged.
    Apply it to the sidebar label, the page title, the deep-link slug (settings/connected-accounts; keep a redirect from settings/integrations if it ever shipped), the i18n strings, tests, DESIGN §49 and CONTEXT.md. Code identifiers may stay integrations internally if renaming them is noisy, but user-facing text must say Connected Accounts.
**Owner decision (2026-09-30):** the section is named **Connected Accounts**, not "Integrations". - Connected Accounts: external services calternal signs in to (iCloud, Fastmail, Gmail, Other). - Apps: clients that sign in to calternal (App Passwords, CLI, MCP, WebMCP). Unchanged. Apply it to the sidebar label, the page title, the deep-link slug (`settings/connected-accounts`; keep a redirect from `settings/integrations` if it ever shipped), the i18n strings, tests, DESIGN §49 and CONTEXT.md. Code identifiers may stay `integrations` internally if renaming them is noisy, but user-facing text must say Connected Accounts.
kayg changed title from SETTINGS → Integrations: one sign-in per provider account, then Mail/Calendar/Contacts checkboxes (grill) to BETTER SETTINGS: organise Settings so it feels non-overwhelming and close to the User (grill pending); includes Connected Accounts 2026-09-30 04:21:07 +00:00
Author
Owner

Scope widened (owner, 2026-09-30): this issue is now Better Settings: "organise it in a better way that it feels non-overwhelming, and closely clustered to the user so everything makes sense." It needs a grill before any reorganisation is built (the owner will run it later).

  • The Connected Accounts work already decided here (I1–I6, the name "Connected Accounts") stays in scope and continues as the first slice.
  • Title Case for section names is #474.
  • Open for the grill: the section grouping and order, what sits under Account vs. the rest, flat vs. nested sections, the User/Admin split, search in Settings, and which settings move next to the feature they affect.
**Scope widened (owner, 2026-09-30):** this issue is now **Better Settings**: "organise it in a better way that it feels non-overwhelming, and closely clustered to the user so everything *makes* sense." It needs a grill before any reorganisation is built (the owner will run it later). - The Connected Accounts work already decided here (I1–I6, the name "Connected Accounts") stays in scope and continues as the first slice. - Title Case for section names is #474. - Open for the grill: the section grouping and order, what sits under Account vs. the rest, flat vs. nested sections, the User/Admin split, search in Settings, and which settings move next to the feature they affect.
Author
Owner

Review finding: the fresh 390 px run stopped because the runner waited for #integration-provider-title to be visible. The phone layout intentionally hides that body heading and uses OverlaySurface's sticky sheet title. I am updating the runner to assert the visible provider sheet and its chrome title; the product view was not reached by this assertion.

Review finding: the fresh 390 px run stopped because the runner waited for #integration-provider-title to be visible. The phone layout intentionally hides that body heading and uses OverlaySurface's sticky sheet title. I am updating the runner to assert the visible provider sheet and its chrome title; the product view was not reached by this assertion.
Author
Owner

Review finding: desktop geometry checks ran during OverlaySurface's entrance motion. A new provider can still be 24 px into its horizontal fly transform after two frames; the settled card is centered at x=440..1000 in the 1440 px capture. I am making the runner wait for finite surface animations before checking placement.

Review finding: desktop geometry checks ran during OverlaySurface's entrance motion. A new provider can still be 24 px into its horizontal fly transform after two frames; the settled card is centered at x=440..1000 in the 1440 px capture. I am making the runner wait for finite surface animations before checking placement.
Author
Owner

Finding during final checks: the merged web token guard flagged local radius/leading values in the integration sheet plus a numeric fallback in shared SettingsRow. Replaced them with shared role tokens; the focused token check now passes. The initial full web check had failed at this guard.

Finding during final checks: the merged web token guard flagged local radius/leading values in the integration sheet plus a numeric fallback in shared SettingsRow. Replaced them with shared role tokens; the focused token check now passes. The initial full web check had failed at this guard.
Author
Owner

Finding during merged-tree web validation: also exposed that workspace dependencies were not installed ( is declared and locked; bun install v1.4.2 (744846f84)

Checked 631 installs across 749 packages (no changes) [7.00s] installed it) and an incoming Mail settings test imported from Vitest instead of Testing Library. Corrected the import without changing assertions; rerunning the web check now.

Finding during merged-tree web validation: also exposed that workspace dependencies were not installed ( is declared and locked; bun install v1.4.2 (744846f84) Checked 631 installs across 749 packages (no changes) [7.00s] installed it) and an incoming Mail settings test imported from Vitest instead of Testing Library. Corrected the import without changing assertions; rerunning the web check now.
Author
Owner

Owner confirmed the Better Settings plan (2026-09-30): DESIGN §50 at 0dc772c36. Build launches after the Connected Accounts job (integrations) merges; it folds in #474 (Title Case) and uses #482's header.

Owner confirmed the Better Settings plan (2026-09-30): DESIGN §50 at 0dc772c36. Build launches after the Connected Accounts job (integrations) merges; it folds in #474 (Title Case) and uses #482's header.
Author
Owner

Merged-tree validation findings for #407:

  • The role-token guard found local radius and leading values in the provider sheet and a numeric fallback in SettingsRow. Replaced them with shared tokens; the token check and full web type check now pass.
  • The workspace install was stale although fast-check is declared and locked. A frozen Bun install supplied it. The Mail settings test also imported waitFor from Vitest; moved that import to Testing Library without changing assertions.
  • The full web test run completed with 137 files and 888 tests passing. One unrelated ThemePicker keyboard submenu test timed out at 5 seconds under high shared-host load. No expectation was changed.
Merged-tree validation findings for #407: - The role-token guard found local radius and leading values in the provider sheet and a numeric fallback in SettingsRow. Replaced them with shared tokens; the token check and full web type check now pass. - The workspace install was stale although fast-check is declared and locked. A frozen Bun install supplied it. The Mail settings test also imported waitFor from Vitest; moved that import to Testing Library without changing assertions. - The full web test run completed with 137 files and 888 tests passing. One unrelated ThemePicker keyboard submenu test timed out at 5 seconds under high shared-host load. No expectation was changed.
Author
Owner

#407 final report

Branch: job/integrations
HEAD: 6276f89e438f21bdce247d0fb8338e08f4ac98e0
Merged origin/dev once in bfd4a811c.

Built

  • Added shared provider accounts in Settings → Integrations, with Mail and Calendar service switches stored through the server-owned account and service rows.
  • Replaced the identical provider globes with distinct in-house glyphs. Provider chooser links are in row menus; connected rows keep Retry and move Disconnect and Copy link into the ⋯ menu.
  • Used the shared OverlaySurface for the desktop provider sheet and full mobile sheet. Aligned Services to the form field inset.
  • Derived initial switches from the provider capability table: iCloud, Fastmail, and Yahoo start with Mail and Calendars on; Gmail Calendar waits for OAuth; Other starts with both on while server discovery checks CalDAV.
  • Added the API, encrypted shared account persistence, Mail/Calendar projections, and adversarial coverage.

The 48 production-build review captures are in artifacts/integrations/ and attached to this issue. They cover phone (390 px), tablet (820 px), and desktop (1440 px), in light and dark. The issue currently has 66 attachments including this set.

Files (48)

  • Web settings and review: apps/web/e2e/integrations-review.mjs, apps/web/package.json, apps/web/src/routes/settings/[...path]/+page.svelte, apps/web/src/routes/settings/calendars/CalendarsSection.svelte, apps/web/src/routes/settings/integrations/IntegrationsSection.svelte, apps/web/src/routes/settings/integrations/IntegrationsSection.svelte.test.ts, apps/web/src/routes/settings/mail/MailSection.svelte, apps/web/src/routes/settings/mail/MailSection.svelte.test.ts, apps/web/src/routes/settings/parts/SettingsRow.svelte, apps/web/src/routes/settings/parts/icons.ts, apps/web/src/routes/settings/sections.test.ts, apps/web/src/routes/settings/sections.ts.
  • API contract and generated client: contracts/openapi.json, packages/api-client/src/generated.ts.
  • Shared account storage: crates/calternal-db/Cargo.toml, crates/calternal-db/src/integrations.rs, crates/calternal-db/src/lib.rs, crates/calternal-db/src/migrations.rs, crates/calternal-db/src/migrations/0007_integrations.sql, crates/calternal-db/src/migrations/0008_integration_carddav.sql, crates/calternal-db/src/migrations/0009_yahoo_provider.sql.
  • Plugin and server: crates/calternal-plugin/Cargo.toml, crates/calternal-plugin/src/lib.rs, crates/calternal-plugin/src/outbound.rs, crates/calternal-server/Cargo.toml, crates/calternal-server/src/integrations.rs, crates/calternal-server/src/main.rs, crates/calternal-server/src/system_plugin.rs, crates/calternal-server/src/wire.rs.
  • Calendar: crates/plugins/calendar/src/cache/crypto.rs, crates/plugins/calendar/src/cache/mod.rs, crates/plugins/calendar/src/cache/store.rs, crates/plugins/calendar/src/client/mod.rs, crates/plugins/calendar/src/items.rs, crates/plugins/calendar/src/routes.rs, crates/plugins/calendar/src/search.rs, crates/plugins/calendar/src/view.rs, crates/plugins/calendar/tests/cache.rs.
  • Mail: crates/plugins/mail/src/cache.rs, crates/plugins/mail/src/cache/store.rs, crates/plugins/mail/src/crypto.rs, crates/plugins/mail/src/imap.rs, crates/plugins/mail/src/lib.rs, crates/plugins/mail/src/routes.rs, crates/plugins/mail/src/sync.rs.
  • Other: Cargo.lock, tests/adversarial/integrations_api.mjs, tests/adversarial/run.sh.

Gates

cargo fmt --check: exit 0; stdout and stderr empty.

bun run check:

Text sizes and UI shape values use shared role tokens.
svelte-check found 0 errors and 0 warnings

Full bun run test:

Error: Test timed out in 5000ms.
Test Files  1 failed | 137 passed (138)
Tests  1 failed | 888 passed (889)
error: script "test" exited with code 1

The timeout was in the unrelated ThemePicker.svelte.test.ts keyboard submenu test. Focused rerun:

Test Files  1 passed (1)
Tests  2 passed (2)

bun run build:

✓ built in 4m 26s
Wrote site to "build"
✔ done

Clippy:

calternal-db: Finished 'dev' profile [unoptimized + debuginfo] target(s) in 1m 56s
calternal-plugin: Finished 'dev' profile [unoptimized + debuginfo] target(s) in 2m 59s
calternal-server: Finished 'dev' profile [unoptimized + debuginfo] target(s) in 52m 36s
calternal-plugin-calendar: Finished 'dev' profile [unoptimized + debuginfo] target(s) in 9m 41s
calternal-plugin-mail: Finished 'dev' profile [unoptimized + debuginfo] target(s) in 6m 21s

Rust tests:

calternal-db:
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; finished in 6.00s
test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; finished in 11.31s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; finished in 0.00s

calternal-plugin:
test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; finished in 38.86s

calternal-server:
test result: ok. 90 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 42.69s

calternal-plugin-calendar:
test result: ok. 51 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 25.11s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

calternal-plugin-mail:
test result: ok. 34 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.24s

bash packages/api-client/check-generated.sh:

Finished 'dev' profile [unoptimized + debuginfo] target(s) in 57m 15s
Running '/mnt/hdd/targets/jobs/integrations/debug/calternal-server openapi'
$ bunx --package openapi-typescript@7.13.0 openapi-typescript ../../contracts/openapi.json -o src/generated.ts
✨ openapi-typescript 7.13.0
🚀 ../../contracts/openapi.json → src/generated.ts [8.3s]

Generated diff check passed with no changes.

Integrations adversarial probe:

Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed

Cleanup:

Removed 18656 files, 11.1GiB total

Web build output was removed.

Known gaps

  • The full web test gate remains red due to the single 5-second ThemePicker timeout; its isolated rerun passed. No existing assertion expectations were changed.
  • Contacts controls remain hidden until Contacts (#297) exists. Gmail Calendar remains unavailable pending OAuth, per DESIGN §49 I4.

Decisions not specified in DESIGN

  • Used neutral in-house marks after recording each provider's published branding limits in a code comment; Google gets a plain accent G because this app-password chooser is not a Google sign-in flow.
  • Other starts with both Mail and Calendars selected; server discovery checks whether CalDAV is available.
  • The screenshot harness waits 500 ms for the sheet entrance to settle before reading geometry. This only affects review timing.
#407 final report Branch: `job/integrations` HEAD: `6276f89e438f21bdce247d0fb8338e08f4ac98e0` Merged `origin/dev` once in `bfd4a811c`. ## Built - Added shared provider accounts in Settings → Integrations, with Mail and Calendar service switches stored through the server-owned account and service rows. - Replaced the identical provider globes with distinct in-house glyphs. Provider chooser links are in row menus; connected rows keep Retry and move Disconnect and Copy link into the ⋯ menu. - Used the shared OverlaySurface for the desktop provider sheet and full mobile sheet. Aligned Services to the form field inset. - Derived initial switches from the provider capability table: iCloud, Fastmail, and Yahoo start with Mail and Calendars on; Gmail Calendar waits for OAuth; Other starts with both on while server discovery checks CalDAV. - Added the API, encrypted shared account persistence, Mail/Calendar projections, and adversarial coverage. The 48 production-build review captures are in `artifacts/integrations/` and attached to this issue. They cover phone (390 px), tablet (820 px), and desktop (1440 px), in light and dark. The issue currently has 66 attachments including this set. ## Files (48) - Web settings and review: `apps/web/e2e/integrations-review.mjs`, `apps/web/package.json`, `apps/web/src/routes/settings/[...path]/+page.svelte`, `apps/web/src/routes/settings/calendars/CalendarsSection.svelte`, `apps/web/src/routes/settings/integrations/IntegrationsSection.svelte`, `apps/web/src/routes/settings/integrations/IntegrationsSection.svelte.test.ts`, `apps/web/src/routes/settings/mail/MailSection.svelte`, `apps/web/src/routes/settings/mail/MailSection.svelte.test.ts`, `apps/web/src/routes/settings/parts/SettingsRow.svelte`, `apps/web/src/routes/settings/parts/icons.ts`, `apps/web/src/routes/settings/sections.test.ts`, `apps/web/src/routes/settings/sections.ts`. - API contract and generated client: `contracts/openapi.json`, `packages/api-client/src/generated.ts`. - Shared account storage: `crates/calternal-db/Cargo.toml`, `crates/calternal-db/src/integrations.rs`, `crates/calternal-db/src/lib.rs`, `crates/calternal-db/src/migrations.rs`, `crates/calternal-db/src/migrations/0007_integrations.sql`, `crates/calternal-db/src/migrations/0008_integration_carddav.sql`, `crates/calternal-db/src/migrations/0009_yahoo_provider.sql`. - Plugin and server: `crates/calternal-plugin/Cargo.toml`, `crates/calternal-plugin/src/lib.rs`, `crates/calternal-plugin/src/outbound.rs`, `crates/calternal-server/Cargo.toml`, `crates/calternal-server/src/integrations.rs`, `crates/calternal-server/src/main.rs`, `crates/calternal-server/src/system_plugin.rs`, `crates/calternal-server/src/wire.rs`. - Calendar: `crates/plugins/calendar/src/cache/crypto.rs`, `crates/plugins/calendar/src/cache/mod.rs`, `crates/plugins/calendar/src/cache/store.rs`, `crates/plugins/calendar/src/client/mod.rs`, `crates/plugins/calendar/src/items.rs`, `crates/plugins/calendar/src/routes.rs`, `crates/plugins/calendar/src/search.rs`, `crates/plugins/calendar/src/view.rs`, `crates/plugins/calendar/tests/cache.rs`. - Mail: `crates/plugins/mail/src/cache.rs`, `crates/plugins/mail/src/cache/store.rs`, `crates/plugins/mail/src/crypto.rs`, `crates/plugins/mail/src/imap.rs`, `crates/plugins/mail/src/lib.rs`, `crates/plugins/mail/src/routes.rs`, `crates/plugins/mail/src/sync.rs`. - Other: `Cargo.lock`, `tests/adversarial/integrations_api.mjs`, `tests/adversarial/run.sh`. ## Gates `cargo fmt --check`: exit 0; stdout and stderr empty. `bun run check`: ``` Text sizes and UI shape values use shared role tokens. svelte-check found 0 errors and 0 warnings ``` Full `bun run test`: ``` Error: Test timed out in 5000ms. Test Files 1 failed | 137 passed (138) Tests 1 failed | 888 passed (889) error: script "test" exited with code 1 ``` The timeout was in the unrelated `ThemePicker.svelte.test.ts` keyboard submenu test. Focused rerun: ``` Test Files 1 passed (1) Tests 2 passed (2) ``` `bun run build`: ``` ✓ built in 4m 26s Wrote site to "build" ✔ done ``` Clippy: ``` calternal-db: Finished 'dev' profile [unoptimized + debuginfo] target(s) in 1m 56s calternal-plugin: Finished 'dev' profile [unoptimized + debuginfo] target(s) in 2m 59s calternal-server: Finished 'dev' profile [unoptimized + debuginfo] target(s) in 52m 36s calternal-plugin-calendar: Finished 'dev' profile [unoptimized + debuginfo] target(s) in 9m 41s calternal-plugin-mail: Finished 'dev' profile [unoptimized + debuginfo] target(s) in 6m 21s ``` Rust tests: ``` calternal-db: test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; finished in 6.00s test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; finished in 11.31s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; finished in 0.00s calternal-plugin: test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; finished in 38.86s calternal-server: test result: ok. 90 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 42.69s calternal-plugin-calendar: test result: ok. 51 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 25.11s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s calternal-plugin-mail: test result: ok. 34 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.24s ``` `bash packages/api-client/check-generated.sh`: ``` Finished 'dev' profile [unoptimized + debuginfo] target(s) in 57m 15s Running '/mnt/hdd/targets/jobs/integrations/debug/calternal-server openapi' $ bunx --package openapi-typescript@7.13.0 openapi-typescript ../../contracts/openapi.json -o src/generated.ts ✨ openapi-typescript 7.13.0 🚀 ../../contracts/openapi.json → src/generated.ts [8.3s] ``` Generated diff check passed with no changes. Integrations adversarial probe: ``` Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed ``` Cleanup: ``` Removed 18656 files, 11.1GiB total ``` Web build output was removed. ## Known gaps - The full web test gate remains red due to the single 5-second ThemePicker timeout; its isolated rerun passed. No existing assertion expectations were changed. - Contacts controls remain hidden until Contacts (#297) exists. Gmail Calendar remains unavailable pending OAuth, per DESIGN §49 I4. ## Decisions not specified in DESIGN - Used neutral in-house marks after recording each provider's published branding limits in a code comment; Google gets a plain accent G because this app-password chooser is not a Google sign-in flow. - Other starts with both Mail and Calendars selected; server discovery checks whether CalDAV is available. - The screenshot harness waits 500 ms for the sheet entrance to settle before reading geometry. This only affects review timing.
Author
Owner

Starting the Connected Accounts rename on job/integrations, based on 6276f89e438f21bdce247d0fb8338e08f4ac98e0. I am fetching and merging origin/dev first, then I will update the user-facing names, canonical settings deep link and legacy redirect, DESIGN §49, and the glossary. I will leave the separate §50 reorganisation untouched.

Starting the Connected Accounts rename on `job/integrations`, based on `6276f89e438f21bdce247d0fb8338e08f4ac98e0`. I am fetching and merging `origin/dev` first, then I will update the user-facing names, canonical settings deep link and legacy redirect, DESIGN §49, and the glossary. I will leave the separate §50 reorganisation untouched.
Author
Owner

Finding: Mail and Calendar still expose the old section name in their linked-account conflict messages, so those API errors remain visible to Users after the Settings rename. I changed those messages and nearby account documentation to say Connected Accounts. The API route names and Rust identifiers remain unchanged.

Finding: Mail and Calendar still expose the old section name in their linked-account conflict messages, so those API errors remain visible to Users after the Settings rename. I changed those messages and nearby account documentation to say Connected Accounts. The API route names and Rust identifiers remain unchanged.
Author
Owner

Finding: cargo test -p calternal-server completed with 89 tests passed, 1 failed and 2 ignored. The sole failure was the existing serialized wire::tests::live_apps_run_in_separate_processes wrapper: its full_app_setup_session_config_and_backup child timed out at wire.rs:7104 after 16.60 seconds. Several other server builds were active during this run. I did not change the test or its expectation; I am treating this as a load-only timeout per the job rules.

Finding: `cargo test -p calternal-server` completed with 89 tests passed, 1 failed and 2 ignored. The sole failure was the existing serialized `wire::tests::live_apps_run_in_separate_processes` wrapper: its `full_app_setup_session_config_and_backup` child timed out at `wire.rs:7104` after 16.60 seconds. Several other server builds were active during this run. I did not change the test or its expectation; I am treating this as a load-only timeout per the job rules.
Author
Owner

Completed

The Settings label, page title, and account group title now say Connected Accounts. The canonical deep link is /settings/connected-accounts; old /settings/integrations links resolve to it. Mail and Calendars use the canonical links and updated copy. I updated DESIGN §49 and the CONTEXT glossary. Code identifiers remain integrations; I did not start the §50 reorganisation.

Branch: job/integrations
Head: 493a9510be56e84e4bc552bf76884a581b51e105

Files

  • Web settings routing, labels, copy and tests: apps/web/src/routes/settings/
  • Production screenshot matrix: apps/web/e2e/integrations-review.mjs
  • Route performance profile: apps/web/e2e/route-perf.mjs
  • Mail and Calendar conflict copy: crates/plugins/mail/, crates/plugins/calendar/
  • Connected Account provider errors and docs: crates/calternal-db/src/integrations.rs, crates/calternal-server/src/integrations.rs
  • Product wording: docs/DESIGN.md, CONTEXT.md

Gates

bun run check output:

$ node scripts/check-type-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
Text sizes and UI shape values use shared role tokens.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/integrations/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

bun run test output:

 Test Files  138 passed (138)
      Tests  896 passed (896)
   Start at  13:45:35
   Duration  198.13s (transform 61%, import 17%, environment 11%, tests 8%, setup 2%)

cargo fmt --check: exit 0, no output.

cargo clippy -p calternal-db --all-targets -- -D warnings: exit 0; Finished dev profile in 3m 02s.

cargo test -p calternal-db output:

test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.83s
test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.94s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s

cargo clippy -p calternal-server --all-targets -- -D warnings: exit 0; Finished dev profile in 1m 25s.

cargo test -p calternal-server: 89 passed, 1 failed, 2 ignored. The existing wire::tests::live_apps_run_in_separate_processes wrapper timed out in full_app_setup_session_config_and_backup at crates/calternal-server/src/wire.rs:7104 after 16.60s while the shared host had concurrent Rust jobs. No test expectation changed. This was reported as a load-only timeout.

cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings: exit 0; Finished dev profile in 2m 42s.

cargo test -p calternal-plugin-calendar: 51 library tests, 1 cache integration test and 3 protocol tests passed; 1 manual benchmark ignored.

cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings: exit 0; Finished dev profile in 28.99s.

cargo test -p calternal-plugin-mail: 34 tests passed.

bun run build passed: ✓ built in 3m 1s; Wrote site to "build". The existing Rolldown "use client" module directive warnings remained. I ran cargo clean and removed apps/web/build after evidence capture.

Screenshots

The production SPA review passed: PASS Connected Accounts review: 60 screenshots. It covers the chooser, five provider forms, service checklist, connected account state, Mail and Calendar views at 390, 820 and 1440 px in light and dark themes. The API account rows are Playwright fixtures in the review harness only.

Performance

Measured on perf-test under /root/perf.lock, three runs at 390 and 1440 px. Load average inside the lock: before 0.01, 0.09, 0.13; after 3.44, 1.14, 0.49.

  • Connected Accounts route p50/p95: 390 px 1072/1080 ms; 1440 px 1633/3195 ms.
  • Canonical route and old alias had the same bundle: 422869 JS gzip bytes and 68636 CSS gzip bytes.
  • Idle server CPU/RSS: 0.2% / 164930355 bytes. Peak CPU/RSS during the burst: 248.13% / 182079488 bytes.
  • 24-client burst: 80273 requests, p50 2 ms, p95 10 ms; all 80273 returned HTTP 200.
  • docs/perf/baseline.json is commit 37788888. Its Appearance route p50/p95 was 390 px 3246/5190 ms, 1440 px 2953/4055 ms; settings bundle 321592 JS gzip and 53020 CSS gzip. That baseline predates this build. In the measured build, Appearance p50/p95 was 1104/1218 ms at 390 px and 1606/1787 ms at 1440 px.
  • The general shell interaction portion was skipped for this path-focused run. It timed out when selecting Photos because the app stayed at Opening Photos…; this is outside #407 and is filed as #521. The route samples and burst completed.

Decisions and gaps

Product decisions follow the 2026-09-30 owner instruction and DESIGN §49: retain the internal ID, use the new canonical slug, redirect the old slug, and leave §50 for its separate job. The only gate gap is the shared-host timeout in the server test above. The separate Photos Tab navigation issue is recorded in #521.

## Completed The Settings label, page title, and account group title now say **Connected Accounts**. The canonical deep link is `/settings/connected-accounts`; old `/settings/integrations` links resolve to it. Mail and Calendars use the canonical links and updated copy. I updated DESIGN §49 and the CONTEXT glossary. Code identifiers remain `integrations`; I did not start the §50 reorganisation. Branch: `job/integrations` Head: `493a9510be56e84e4bc552bf76884a581b51e105` ## Files - Web settings routing, labels, copy and tests: `apps/web/src/routes/settings/` - Production screenshot matrix: `apps/web/e2e/integrations-review.mjs` - Route performance profile: `apps/web/e2e/route-perf.mjs` - Mail and Calendar conflict copy: `crates/plugins/mail/`, `crates/plugins/calendar/` - Connected Account provider errors and docs: `crates/calternal-db/src/integrations.rs`, `crates/calternal-server/src/integrations.rs` - Product wording: `docs/DESIGN.md`, `CONTEXT.md` ## Gates `bun run check` output: ```text $ node scripts/check-type-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json Text sizes and UI shape values use shared role tokens. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/integrations/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` `bun run test` output: ```text Test Files 138 passed (138) Tests 896 passed (896) Start at 13:45:35 Duration 198.13s (transform 61%, import 17%, environment 11%, tests 8%, setup 2%) ``` `cargo fmt --check`: exit 0, no output. `cargo clippy -p calternal-db --all-targets -- -D warnings`: exit 0; `Finished dev profile in 3m 02s`. `cargo test -p calternal-db` output: ```text test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.83s test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.94s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s ``` `cargo clippy -p calternal-server --all-targets -- -D warnings`: exit 0; `Finished dev profile in 1m 25s`. `cargo test -p calternal-server`: 89 passed, 1 failed, 2 ignored. The existing `wire::tests::live_apps_run_in_separate_processes` wrapper timed out in `full_app_setup_session_config_and_backup` at `crates/calternal-server/src/wire.rs:7104` after 16.60s while the shared host had concurrent Rust jobs. No test expectation changed. This was reported as a load-only timeout. `cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings`: exit 0; `Finished dev profile in 2m 42s`. `cargo test -p calternal-plugin-calendar`: 51 library tests, 1 cache integration test and 3 protocol tests passed; 1 manual benchmark ignored. `cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings`: exit 0; `Finished dev profile in 28.99s`. `cargo test -p calternal-plugin-mail`: 34 tests passed. `bun run build` passed: `✓ built in 3m 1s`; `Wrote site to "build"`. The existing Rolldown `"use client"` module directive warnings remained. I ran `cargo clean` and removed `apps/web/build` after evidence capture. ## Screenshots The production SPA review passed: `PASS Connected Accounts review: 60 screenshots`. It covers the chooser, five provider forms, service checklist, connected account state, Mail and Calendar views at 390, 820 and 1440 px in light and dark themes. The API account rows are Playwright fixtures in the review harness only. - [Full 60-image matrix](https://git.kayg.org/attachments/40aecf4f-eba8-42a3-b0ca-7927f5c3c7c2) - Account row: [390 light](https://git.kayg.org/attachments/cf578955-41cf-4e09-9739-d101bcccfeb3), [390 dark](https://git.kayg.org/attachments/2d9d11e7-3ee7-446b-8dc6-57acd3a910f8), [820 light](https://git.kayg.org/attachments/76e6ce48-3fc7-4ac0-863f-ea2ea72caeed), [820 dark](https://git.kayg.org/attachments/f73c2710-ce00-45e1-911a-ee7af3b75d1c), [1440 light](https://git.kayg.org/attachments/931e912f-5778-4f0d-969f-8d8dcc565e6b), [1440 dark](https://git.kayg.org/attachments/d8318be5-0fca-4426-a5a2-09a945ad80d3) ## Performance Measured on `perf-test` under `/root/perf.lock`, three runs at 390 and 1440 px. Load average inside the lock: before `0.01, 0.09, 0.13`; after `3.44, 1.14, 0.49`. - Connected Accounts route p50/p95: 390 px `1072/1080 ms`; 1440 px `1633/3195 ms`. - Canonical route and old alias had the same bundle: `422869` JS gzip bytes and `68636` CSS gzip bytes. - Idle server CPU/RSS: `0.2%` / `164930355` bytes. Peak CPU/RSS during the burst: `248.13%` / `182079488` bytes. - 24-client burst: `80273` requests, p50 `2 ms`, p95 `10 ms`; all `80273` returned HTTP 200. - `docs/perf/baseline.json` is commit `37788888`. Its Appearance route p50/p95 was 390 px `3246/5190 ms`, 1440 px `2953/4055 ms`; settings bundle `321592` JS gzip and `53020` CSS gzip. That baseline predates this build. In the measured build, Appearance p50/p95 was `1104/1218 ms` at 390 px and `1606/1787 ms` at 1440 px. - The general shell interaction portion was skipped for this path-focused run. It timed out when selecting Photos because the app stayed at `Opening Photos…`; this is outside #407 and is filed as [#521](https://git.kayg.org/kayg/calternal/issues/521). The route samples and burst completed. ## Decisions and gaps Product decisions follow the 2026-09-30 owner instruction and DESIGN §49: retain the internal ID, use the new canonical slug, redirect the old slug, and leave §50 for its separate job. The only gate gap is the shared-host timeout in the server test above. The separate Photos Tab navigation issue is recorded in #521.
Author
Owner

Starting #407 on branch job/integrations at base 493a9510be. I am auditing the Connected Accounts UI, routes, shared surfaces and existing e2e coverage before making the requested polish changes.

Starting #407 on branch job/integrations at base 493a9510be56e84e4bc552bf76884a581b51e105. I am auditing the Connected Accounts UI, routes, shared surfaces and existing e2e coverage before making the requested polish changes.
Author
Owner

Finding: IntegrationsSection.svelte still renders a separate provider ⋯ control beside the full-row open action, styles fields locally with var(--surface)/var(--line), uses text pills for Copy link, and shows the Contacts promise below Services. The shared Settings input recipe uses --input-surface; packages/ui has no reusable text input component. I will use one shared component for this form and move provider extras into the row context menu.

Finding: `IntegrationsSection.svelte` still renders a separate provider ⋯ control beside the full-row open action, styles fields locally with `var(--surface)`/`var(--line)`, uses text pills for Copy link, and shows the Contacts promise below Services. The shared Settings input recipe uses `--input-surface`; `packages/ui` has no reusable text input component. I will use one shared component for this form and move provider extras into the row context menu.
Author
Owner

#407 implementation slice committed on job/integrations at f45c72a16.

The first bun run check found a direct 140ms ease provider-row transition in the touched component. I replaced it with the shared --dur-press and --ease-standard-out tokens required by #477. The next check found an over-narrow test comparison against the removed section ID; the assertion now checks the section ID and label arrays. Focused tests passed (3 files, 21 tests); the corrected bun run check passed with 0 errors and 0 warnings.

#407 implementation slice committed on `job/integrations` at `f45c72a16`. The first `bun run check` found a direct `140ms ease` provider-row transition in the touched component. I replaced it with the shared `--dur-press` and `--ease-standard-out` tokens required by #477. The next check found an over-narrow test comparison against the removed section ID; the assertion now checks the section ID and label arrays. Focused tests passed (3 files, 21 tests); the corrected `bun run check` passed with 0 errors and 0 warnings.
Author
Owner

The first desktop screenshot matrix run captured all 390 px and 820 px states. It stopped on the Gmail dialog at 1440 px when its center was 1.016 px from the viewport center, just outside the existing 1 px assertion. A separate stabilized geometry probe measured the same shared dialog at 0 px offset. The review helper now waits for the entrance transform to finish before measuring; the 1 px expectation remains unchanged. I am rerunning the matrix to regenerate the full screenshot set.

The first desktop screenshot matrix run captured all 390 px and 820 px states. It stopped on the Gmail dialog at 1440 px when its center was 1.016 px from the viewport center, just outside the existing 1 px assertion. A separate stabilized geometry probe measured the same shared dialog at 0 px offset. The review helper now waits for the entrance transform to finish before measuring; the 1 px expectation remains unchanged. I am rerunning the matrix to regenerate the full screenshot set.
Author
Owner

cargo fmt --check found one ordering mismatch in the server module declarations from the origin/dev merge resolution (integrations and location). I am applying rustfmt's order before the per-crate gates; no server behavior changes.

`cargo fmt --check` found one ordering mismatch in the server module declarations from the `origin/dev` merge resolution (`integrations` and `location`). I am applying rustfmt's order before the per-crate gates; no server behavior changes.
Author
Owner

Completed: Connected Accounts polish (#407)

Branch: job/integrations
Head: 920bfd3d51676217c66d13db144f35e119e66a15

Built

  • Renamed the Settings section, sidebar label, page heading, search result, and canonical deep link to Connected Accounts. The old /settings/integrations path and #integrations hash resolve to the canonical section.
  • Changed provider rows to one full-row action with a trailing chevron. Provider Copy link is in the row context menu and form header.
  • Reused the shared TextInput and OverlaySurface, improved field and service spacing, made Copy link an icon button with its warm tooltip, and removed the Contacts placeholder.
  • Updated Mail and Calendars links and help text to use the new name.

The existing /api/v1/system/integrations/* API paths stay intact. The e2e review used deterministic UI fixtures with the production app and a real local server. No fixture data ships in the UI.

Screenshots and e2e

The e2e captured 60 review screenshots across phone (390), tablet (820), and desktop (1440), in both themes. I attached 18 representative chooser/list, Gmail form, and connected-state screenshots to this issue, covering each viewport and theme.

PASS Connected Accounts review: 60 screenshots in /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts

The authenticated two-User route matrix passed:

test integrations::tests::account_list_and_mutations_are_scoped_to_the_authenticated_user ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 100 filtered out; finished in 0.43s

Gates

cargo fmt --check exited 0 with no output.

cargo clippy -p calternal-server --all-targets -- -D warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 13m 20s

cargo test -p calternal-server
test result: ok. 98 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 35.67s

cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 59s

cargo test -p calternal-plugin-mail
test result: ok. 34 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.58s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 04s

cargo test -p calternal-plugin-calendar
test result: ok. 80 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.98s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.20s
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
bun run check
$ node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/integrations/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings
bun run test
Test Files  141 passed (141)
     Tests  941 passed (941)
  Duration  194.37s (transform 53%, environment 17%, import 14%, tests 12%, setup 4%)

Vitest also printed jsdom Window.scrollTo() and CSS parsing notices; the suite exited 0. The production build used by e2e passed earlier in this run. Cargo output was cleaned after the gates (Removed 17369 files, 9.8GiB total); apps/web/build and .svelte-kit output were removed.

Performance profile

The existing route profile now includes the Connected Accounts list, Gmail form, and legacy route. I ran it locally with 3 samples per viewport, a 2,000-file Home, and a 24-request concurrency burst. The local host load average was [26.28, 25.81, 24.18] before and [17.32, 25.83, 26.53] after the run.

Connected Accounts list p50/p95 (ms): 390px 4143/6260; 820px 4409/4513; 1440px 1575/2764. Gmail form p50/p95 (ms): 390px 2411/5268; 820px 5108/5463; 1440px 2292/3876. The connected-accounts API read measured 4.8/20 ms with 50 successful 200 responses. The request burst served 16,938 requests in 12,015ms; p50/p95 was 8.5/56.3 ms, all responses were 200, and peak RSS was 342,913,024 bytes.

docs/perf/baseline.json has no Connected Accounts route or API sample. Its closest Settings route, Appearance, recorded p50/p95 of 1037/1190, 1144/1157, and 1584/2069 ms at 390, 820, and 1440px. Its baseline server burst recorded 2.1/11.9 ms and 71,751 successful requests; the baseline host load was [0.15, 0.39, 1.03] before. These figures are not directly comparable to this run because the local host was heavily loaded.

Files

apps/web/e2e/integrations-review.mjs, apps/web/e2e/route-perf.mjs, apps/web/src/lib/search/providers.test.ts, apps/web/src/routes/settings/[...path]/+page.svelte, apps/web/src/routes/settings/calendars/CalendarsSection.svelte, apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte, apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte.test.ts, apps/web/src/routes/settings/mail/MailSection.svelte, apps/web/src/routes/settings/parts/settings-forms.css, apps/web/src/routes/settings/sections.test.ts, apps/web/src/routes/settings/sections.ts, crates/calternal-server/src/main.rs, packages/ui/src/components/TextInput.svelte, and packages/ui/src/index.ts.

Known gaps and decisions

Live third-party provider connections were not part of the e2e; it uses local API fixtures for repeatable UI states. I kept the existing API paths and made the former Settings path and hash aliases to preserve saved links. Those are the only compatibility decisions beyond the name and layout already set by DESIGN §49 and this issue.

## Completed: Connected Accounts polish (#407) **Branch:** `job/integrations` **Head:** `920bfd3d51676217c66d13db144f35e119e66a15` ### Built - Renamed the Settings section, sidebar label, page heading, search result, and canonical deep link to **Connected Accounts**. The old `/settings/integrations` path and `#integrations` hash resolve to the canonical section. - Changed provider rows to one full-row action with a trailing chevron. Provider Copy link is in the row context menu and form header. - Reused the shared `TextInput` and `OverlaySurface`, improved field and service spacing, made Copy link an icon button with its warm tooltip, and removed the Contacts placeholder. - Updated Mail and Calendars links and help text to use the new name. The existing `/api/v1/system/integrations/*` API paths stay intact. The e2e review used deterministic UI fixtures with the production app and a real local server. No fixture data ships in the UI. ### Screenshots and e2e The e2e captured 60 review screenshots across phone (390), tablet (820), and desktop (1440), in both themes. I attached 18 representative chooser/list, Gmail form, and connected-state screenshots to this issue, covering each viewport and theme. ```text PASS Connected Accounts review: 60 screenshots in /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts ``` The authenticated two-User route matrix passed: ```text test integrations::tests::account_list_and_mutations_are_scoped_to_the_authenticated_user ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 100 filtered out; finished in 0.43s ``` ### Gates `cargo fmt --check` exited 0 with no output. ```text cargo clippy -p calternal-server --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 13m 20s cargo test -p calternal-server test result: ok. 98 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 35.67s cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 59s cargo test -p calternal-plugin-mail test result: ok. 34 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.58s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 04s cargo test -p calternal-plugin-calendar test result: ok. 80 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.98s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.20s test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` ```text bun run check $ node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/integrations/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` ```text bun run test Test Files 141 passed (141) Tests 941 passed (941) Duration 194.37s (transform 53%, environment 17%, import 14%, tests 12%, setup 4%) ``` Vitest also printed jsdom `Window.scrollTo()` and CSS parsing notices; the suite exited 0. The production build used by e2e passed earlier in this run. Cargo output was cleaned after the gates (`Removed 17369 files, 9.8GiB total`); `apps/web/build` and `.svelte-kit` output were removed. ### Performance profile The existing route profile now includes the Connected Accounts list, Gmail form, and legacy route. I ran it locally with 3 samples per viewport, a 2,000-file Home, and a 24-request concurrency burst. The local host load average was `[26.28, 25.81, 24.18]` before and `[17.32, 25.83, 26.53]` after the run. Connected Accounts list p50/p95 (ms): 390px `4143/6260`; 820px `4409/4513`; 1440px `1575/2764`. Gmail form p50/p95 (ms): 390px `2411/5268`; 820px `5108/5463`; 1440px `2292/3876`. The connected-accounts API read measured `4.8/20` ms with 50 successful 200 responses. The request burst served 16,938 requests in 12,015ms; p50/p95 was `8.5/56.3` ms, all responses were 200, and peak RSS was `342,913,024` bytes. `docs/perf/baseline.json` has no Connected Accounts route or API sample. Its closest Settings route, Appearance, recorded p50/p95 of `1037/1190`, `1144/1157`, and `1584/2069` ms at 390, 820, and 1440px. Its baseline server burst recorded `2.1/11.9` ms and 71,751 successful requests; the baseline host load was `[0.15, 0.39, 1.03]` before. These figures are not directly comparable to this run because the local host was heavily loaded. ### Files `apps/web/e2e/integrations-review.mjs`, `apps/web/e2e/route-perf.mjs`, `apps/web/src/lib/search/providers.test.ts`, `apps/web/src/routes/settings/[...path]/+page.svelte`, `apps/web/src/routes/settings/calendars/CalendarsSection.svelte`, `apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte`, `apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte.test.ts`, `apps/web/src/routes/settings/mail/MailSection.svelte`, `apps/web/src/routes/settings/parts/settings-forms.css`, `apps/web/src/routes/settings/sections.test.ts`, `apps/web/src/routes/settings/sections.ts`, `crates/calternal-server/src/main.rs`, `packages/ui/src/components/TextInput.svelte`, and `packages/ui/src/index.ts`. ### Known gaps and decisions Live third-party provider connections were not part of the e2e; it uses local API fixtures for repeatable UI states. I kept the existing API paths and made the former Settings path and hash aliases to preserve saved links. Those are the only compatibility decisions beyond the name and layout already set by DESIGN §49 and this issue.
Author
Owner

Starting round 3 on branch job/integrations. Base SHA: cc25c441b7. I am checking the Connected Accounts UI, shared Settings add-flow surfaces, and legacy Mail/Calendar schemas before changes.

Starting round 3 on branch job/integrations. Base SHA: cc25c441b7a974185622a1dee853cf38686d2b67. I am checking the Connected Accounts UI, shared Settings add-flow surfaces, and legacy Mail/Calendar schemas before changes.
Author
Owner

Upgrade finding: the old Mail credential AAD is calternal-mail-app-password-v1\0owner\0account, while Calendar binds its credential kind into calternal-calendar-credential-v1\0owner\0account\0kind. Mail also stores SMTP username/password separately from the IMAP login. A byte-for-byte copy into the shared Integration row would therefore fail decryption and lose SMTP identity. The upgrade now re-wraps each credential in memory into the shared encrypted payload, including SMTP fields, then clears the source credential only in the same transaction that stores the central row. I am adding regression coverage for the cached Mail projection and rollback behavior.

Upgrade finding: the old Mail credential AAD is `calternal-mail-app-password-v1\0owner\0account`, while Calendar binds its credential kind into `calternal-calendar-credential-v1\0owner\0account\0kind`. Mail also stores SMTP username/password separately from the IMAP login. A byte-for-byte copy into the shared Integration row would therefore fail decryption and lose SMTP identity. The upgrade now re-wraps each credential in memory into the shared encrypted payload, including SMTP fields, then clears the source credential only in the same transaction that stores the central row. I am adding regression coverage for the cached Mail projection and rollback behavior.
Author
Owner

Migration test finding: Mail and Calendar can use the same visible address but keep different app passwords. The first merge rule treated that as a conflict, which safely rolled back but did not carry both service sign-ins into Connected Accounts. I am updating the shared encrypted credential envelope to preserve a separate Calendar login/password when needed, just as it now preserves Mail's separate SMTP login/password. The linked Calendar cache keeps its existing projection ID.

Migration test finding: Mail and Calendar can use the same visible address but keep different app passwords. The first merge rule treated that as a conflict, which safely rolled back but did not carry both service sign-ins into Connected Accounts. I am updating the shared encrypted credential envelope to preserve a separate Calendar login/password when needed, just as it now preserves Mail's separate SMTP login/password. The linked Calendar cache keeps its existing projection ID.
Author
Owner

UI verification finding: the production E2E measured 0 px between the Services legend and the first Mail row. The 12 px CSS grid gap does not apply between a fieldset legend and its first child in the rendered browser. I am replacing that gap with explicit legend spacing and will rerun the real-browser geometry check.

UI verification finding: the production E2E measured 0 px between the Services legend and the first Mail row. The 12 px CSS grid gap does not apply between a fieldset legend and its first child in the rendered browser. I am replacing that gap with explicit legend spacing and will rerun the real-browser geometry check.
Author
Owner

Desktop E2E evidence: the shared dialog received the correct 120 px Settings-pane offset, but a Connected Accounts style still set left: 50%, overriding the shared placement rule. The rendered center therefore stayed at the viewport center and missed the content center by 120 px. I am removing that local position override and keeping only the provider form's width and height limits.

Desktop E2E evidence: the shared dialog received the correct 120 px Settings-pane offset, but a Connected Accounts style still set `left: 50%`, overriding the shared placement rule. The rendered center therefore stayed at the viewport center and missed the content center by 120 px. I am removing that local position override and keeping only the provider form's width and height limits.
Author
Owner

Finding: Calendar's stored credential type includes an encrypted OAuth2 variant (crates/plugins/calendar/src/cache/crypto.rs, Credential::OAuth2). The first migration draft treated that payload as unsupported, which would have left all legacy Mail and Calendar rows unmigrated if one OAuth row existed. The shared encrypted envelope now retains its access and refresh tokens, and the upgrade regression checks both tokens and the linked Calendar projection. Existing CalDAV OAuth behavior remains unchanged because the client has not implemented OAuth authentication.

Finding: Calendar's stored credential type includes an encrypted OAuth2 variant (`crates/plugins/calendar/src/cache/crypto.rs`, `Credential::OAuth2`). The first migration draft treated that payload as unsupported, which would have left all legacy Mail and Calendar rows unmigrated if one OAuth row existed. The shared encrypted envelope now retains its access and refresh tokens, and the upgrade regression checks both tokens and the linked Calendar projection. Existing CalDAV OAuth behavior remains unchanged because the client has not implemented OAuth authentication.
Author
Owner

Finding from the final DB gate: migration 0010 must allow both service switches off so it can preserve a legacy row exactly, while the normal create and update API still requires a service. The existing account_cannot_have_no_enabled_services DB test asserted the old schema constraint. I replaced that expectation with a regression that stores and reads the both-off legacy state, as required by #407 I6; the API validation remains unchanged.

Finding from the final DB gate: migration 0010 must allow both service switches off so it can preserve a legacy row exactly, while the normal create and update API still requires a service. The existing `account_cannot_have_no_enabled_services` DB test asserted the old schema constraint. I replaced that expectation with a regression that stores and reads the both-off legacy state, as required by #407 I6; the API validation remains unchanged.
Author
Owner

Merged origin/dev code failed server clippy: state.client(&account)? used an async future without awaiting it at crates/plugins/calendar/src/routes.rs:1201. Updated it to await the client result; this is on the Calendar event duplication path. Re-running the affected gates.

Merged origin/dev code failed server clippy: state.client(&account)? used an async future without awaiting it at crates/plugins/calendar/src/routes.rs:1201. Updated it to await the client result; this is on the Calendar event duplication path. Re-running the affected gates.
Author
Owner

Server clippy found the upgrade-test helper seed_legacy_mail_account exceeded the argument limit (10/7) at integrations.rs:1795. Grouped its fixture fields in LegacyMailAccountSeed; Gmail/custom fixtures and assertions are unchanged. Re-running the server gate.

Server clippy found the upgrade-test helper seed_legacy_mail_account exceeded the argument limit (10/7) at integrations.rs:1795. Grouped its fixture fields in LegacyMailAccountSeed; Gmail/custom fixtures and assertions are unchanged. Re-running the server gate.
Author
Owner

Decision where DESIGN §49 I6 is silent: run the one-time move during server startup and record completion in the database; expose only a safe state/error code through the authenticated migration-status route so old accounts are available before Settings loads and failures stay visible there. Reuse each Mail account ID as the shared account ID to preserve Mail foreign keys and links. Keep each Calendar projection/cache ID unchanged and add its shared-account link. This leaves provider cache identities stable while the shared row owns credentials and service switches.

Decision where DESIGN §49 I6 is silent: run the one-time move during server startup and record completion in the database; expose only a safe state/error code through the authenticated migration-status route so old accounts are available before Settings loads and failures stay visible there. Reuse each Mail account ID as the shared account ID to preserve Mail foreign keys and links. Keep each Calendar projection/cache ID unchanged and add its shared-account link. This leaves provider cache identities stable while the shared row owns credentials and service switches.
Author
Owner

The first post-merge E2E exited before captures at harness.mjs:94: saveThemePreference accessed window.__userStorageTest.getItem, which was undefined in the fresh viewport context created by captureWidth. The signed-in setup context had installed the test seam, but new capture contexts had not. I am installing the existing test seam in each capture context and will rerun the production matrix.

The first post-merge E2E exited before captures at harness.mjs:94: saveThemePreference accessed window.__userStorageTest.getItem, which was undefined in the fresh viewport context created by captureWidth. The signed-in setup context had installed the test seam, but new capture contexts had not. I am installing the existing test seam in each capture context and will rerun the production matrix.
Author
Owner

#407 round 3 report

Branch: job/integrations
Head: ffb73a099ad521cca3d854507a2ad02f198c27e8

Built

  • Kept the page title Connected Accounts and changed the card sub-heading to Your accounts. Add an account remains.
  • Opened provider setup through the shared OverlaySurface: centered in the Settings detail pane on desktop and displayed as the floating sheet on phones. This follows Settings → Apps → Calendar Feeds → Create calendar feed.
  • Added standard space above service rows. The password help sentence and provider help link now use one inline text block.
  • Kept the provider/account deep links and Copy link action in the shared flow.
  • Added the shared credential store, Mail/Calendar service projections, migration status route, and Settings failure state.

Upgrade safety

The one-time startup migration moves pre-branch Mail and Calendar accounts into integration_accounts in one transaction. It re-wraps each legacy secret into the shared AEAD envelope in memory, preserves separate SMTP and Calendar sign-ins and encrypted OAuth tokens, infers providers from saved values or server hosts, and carries service switches forward. Mail IDs stay stable. Calendar cache IDs and cached Events stay stable and link to the shared account ID. Old service rows remain read-only projections; legacy ciphertext is cleared only inside the successful transaction. A failed migration rolls back and leaves source rows in place, with a safe status available in Settings.

legacy_accounts_upgrade_losslessly_and_only_once builds the origin/dev schema, seeds a Gmail-style account, a custom IMAP account, cached Mail messages and UID state, plus Calendar Basic and OAuth rows. It verifies the same Mail page, IDs, flags and cursor after migration, preserved account names and credentials, stable Calendar cache IDs, and idempotency. legacy_account_failure_keeps_source_rows_and_reports_safe_status verifies rollback and the failure status.

Screenshots

Fresh screenshots from the production SPA and real server. The connected-row state uses test-only API fixtures; no provider credentials were used.

View 390 light 390 dark 1440 light 1440 dark
Accounts list PNG PNG PNG PNG
Fastmail form PNG PNG PNG PNG
Connected state PNG PNG PNG PNG

Verification

Gate output excerpts are verbatim. cargo fmt --all --check exited 0 with no output. The final commit only changes documentation; formatting was rerun after it.

cargo clippy -p calternal-db --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 9.09s

cargo test -p calternal-db
 test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.65s
 test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.53s

cargo clippy -p calternal-plugin --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 42.11s

cargo test -p calternal-plugin
 test result: ok. 26 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.65s

cargo clippy -p calternal-server --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 29.79s

cargo test -p calternal-server
 test integrations::tests::legacy_account_failure_keeps_source_rows_and_reports_safe_status ... ok
 test integrations::tests::legacy_accounts_upgrade_losslessly_and_only_once ... ok
 test result: ok. 114 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 11.67s

cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 50.32s

cargo test -p calternal-plugin-calendar
 test result: ok. 83 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.14s
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.16s
 test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s

cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 15.21s

cargo test -p calternal-plugin-mail
 test result: ok. 38 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 1.32s

bun run --cwd apps/web check
svelte-check found 0 errors and 0 warnings

bun run --cwd apps/web test
 Test Files  149 passed (149)
      Tests  1023 passed (1023)

bun run --cwd apps/web build
  ✔ done

bun run --cwd apps/web test:e2e:integrations-review
PASS Connected Accounts review: 60 screenshots in /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts

bun tests/adversarial/integrations_api.mjs
Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed

Performance

bench/integrations-407.mjs ran locally with 250 non-secret rows on a busy host (load average 9.53, 10.92, 14.38). Account list p50/p95 was 22.8/89.8 ms; migration status was 8.0/52.9 ms. The 24-request burst completed in 641.3 ms for account lists and 223.79 ms for migration status. Mean/peak server RSS was 135,841,515/137,207,808 bytes; mean/peak CPU was 30.12/73.9%. docs/perf/baseline.json has no directly comparable Connected Accounts profile, so these numbers do not establish a regression.

Known gap

Legacy Calendar OAuth token pairs remain encrypted and preserved, but the current CalDAV client still does not support OAuth sync. The migration does not add an OAuth flow or change that existing behavior. E2E connected-state screenshots use test-only account API fixtures.

Decisions where DESIGN §49 was silent

  • Run migration once during server startup, record a completion marker, and expose a safe authenticated status so Settings can explain a failure.
  • Reuse each Mail account ID as the shared account ID to preserve Mail identities and links. Preserve each Calendar projection/cache ID and add a link to its shared account.
  • Match separate service rows by provider and login; custom Other rows also require the displayed email. Keep both-services-disabled legacy rows as-is during migration; new create/update requests still require one service enabled.
  • Use the shared Settings OverlaySurface create-flow pattern named above for provider setup.

Main files

Settings UI and tests: apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte, apps/web/src/routes/settings/[...path]/+page.svelte, apps/web/src/routes/settings/parts/SettingsRow.svelte, Settings Mail/Calendar sections, styles and E2E review.

API and storage: crates/calternal-server/src/integrations.rs, crates/calternal-db/src/integrations.rs, core migrations 0007–0010, and crates/plugins/calendar/migrations/0005_integration_account_link.sql. Mail/Calendar credential, cache, route and client adapters are under crates/plugins/mail/src/ and crates/plugins/calendar/src/.

Contracts and evidence: contracts/openapi.json, packages/api-client/src/generated.ts, tests/adversarial/integrations_api.mjs, and bench/integrations-407.mjs.

## #407 round 3 report Branch: `job/integrations` Head: `ffb73a099ad521cca3d854507a2ad02f198c27e8` ### Built - Kept the page title **Connected Accounts** and changed the card sub-heading to **Your accounts**. **Add an account** remains. - Opened provider setup through the shared `OverlaySurface`: centered in the Settings detail pane on desktop and displayed as the floating sheet on phones. This follows Settings → Apps → Calendar Feeds → **Create calendar feed**. - Added standard space above service rows. The password help sentence and provider help link now use one inline text block. - Kept the provider/account deep links and Copy link action in the shared flow. - Added the shared credential store, Mail/Calendar service projections, migration status route, and Settings failure state. ### Upgrade safety The one-time startup migration moves pre-branch Mail and Calendar accounts into `integration_accounts` in one transaction. It re-wraps each legacy secret into the shared AEAD envelope in memory, preserves separate SMTP and Calendar sign-ins and encrypted OAuth tokens, infers providers from saved values or server hosts, and carries service switches forward. Mail IDs stay stable. Calendar cache IDs and cached Events stay stable and link to the shared account ID. Old service rows remain read-only projections; legacy ciphertext is cleared only inside the successful transaction. A failed migration rolls back and leaves source rows in place, with a safe status available in Settings. `legacy_accounts_upgrade_losslessly_and_only_once` builds the `origin/dev` schema, seeds a Gmail-style account, a custom IMAP account, cached Mail messages and UID state, plus Calendar Basic and OAuth rows. It verifies the same Mail page, IDs, flags and cursor after migration, preserved account names and credentials, stable Calendar cache IDs, and idempotency. `legacy_account_failure_keeps_source_rows_and_reports_safe_status` verifies rollback and the failure status. ### Screenshots Fresh screenshots from the production SPA and real server. The connected-row state uses test-only API fixtures; no provider credentials were used. | View | 390 light | 390 dark | 1440 light | 1440 dark | |---|---|---|---|---| | Accounts list | [PNG](https://git.kayg.org/attachments/5d1f63ec-d320-41c6-98f7-2f3b29ac5278) | [PNG](https://git.kayg.org/attachments/7bb716de-19e7-412b-9e59-009922e3a197) | [PNG](https://git.kayg.org/attachments/87e8deb9-bc09-4f37-8b1d-accd99c148fa) | [PNG](https://git.kayg.org/attachments/17d0ebdf-d6ba-4c10-b9b3-cff79f5bab4f) | | Fastmail form | [PNG](https://git.kayg.org/attachments/9069e4b3-da06-44e8-833c-7e5044d19640) | [PNG](https://git.kayg.org/attachments/2ef2f7b1-1a33-4da2-b08a-f8747e1ffe86) | [PNG](https://git.kayg.org/attachments/a922a05d-f757-41d3-b7d6-ab38db9094f6) | [PNG](https://git.kayg.org/attachments/c480730f-6976-4451-a263-62921fe3226e) | | Connected state | [PNG](https://git.kayg.org/attachments/a88bb6f1-4521-4cee-822e-c4b6cda0d152) | [PNG](https://git.kayg.org/attachments/97d0f56c-16f4-4630-bc3b-21622b65acc9) | [PNG](https://git.kayg.org/attachments/843872f3-224b-47c9-8935-5bb9d116e586) | [PNG](https://git.kayg.org/attachments/8ecb0c1c-2a78-49f3-8bbb-f99cc435659f) | ### Verification Gate output excerpts are verbatim. `cargo fmt --all --check` exited 0 with no output. The final commit only changes documentation; formatting was rerun after it. ```text cargo clippy -p calternal-db --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 9.09s cargo test -p calternal-db test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.65s test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.53s cargo clippy -p calternal-plugin --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 42.11s cargo test -p calternal-plugin test result: ok. 26 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.65s cargo clippy -p calternal-server --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 29.79s cargo test -p calternal-server test integrations::tests::legacy_account_failure_keeps_source_rows_and_reports_safe_status ... ok test integrations::tests::legacy_accounts_upgrade_losslessly_and_only_once ... ok test result: ok. 114 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 11.67s cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 50.32s cargo test -p calternal-plugin-calendar test result: ok. 83 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.14s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.16s test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 15.21s cargo test -p calternal-plugin-mail test result: ok. 38 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 1.32s bun run --cwd apps/web check svelte-check found 0 errors and 0 warnings bun run --cwd apps/web test Test Files 149 passed (149) Tests 1023 passed (1023) bun run --cwd apps/web build ✔ done bun run --cwd apps/web test:e2e:integrations-review PASS Connected Accounts review: 60 screenshots in /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts bun tests/adversarial/integrations_api.mjs Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed ``` ### Performance `bench/integrations-407.mjs` ran locally with 250 non-secret rows on a busy host (load average 9.53, 10.92, 14.38). Account list p50/p95 was 22.8/89.8 ms; migration status was 8.0/52.9 ms. The 24-request burst completed in 641.3 ms for account lists and 223.79 ms for migration status. Mean/peak server RSS was 135,841,515/137,207,808 bytes; mean/peak CPU was 30.12/73.9%. `docs/perf/baseline.json` has no directly comparable Connected Accounts profile, so these numbers do not establish a regression. ### Known gap Legacy Calendar OAuth token pairs remain encrypted and preserved, but the current CalDAV client still does not support OAuth sync. The migration does not add an OAuth flow or change that existing behavior. E2E connected-state screenshots use test-only account API fixtures. ### Decisions where DESIGN §49 was silent - Run migration once during server startup, record a completion marker, and expose a safe authenticated status so Settings can explain a failure. - Reuse each Mail account ID as the shared account ID to preserve Mail identities and links. Preserve each Calendar projection/cache ID and add a link to its shared account. - Match separate service rows by provider and login; custom `Other` rows also require the displayed email. Keep both-services-disabled legacy rows as-is during migration; new create/update requests still require one service enabled. - Use the shared Settings `OverlaySurface` create-flow pattern named above for provider setup. ### Main files Settings UI and tests: `apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte`, `apps/web/src/routes/settings/[...path]/+page.svelte`, `apps/web/src/routes/settings/parts/SettingsRow.svelte`, Settings Mail/Calendar sections, styles and E2E review. API and storage: `crates/calternal-server/src/integrations.rs`, `crates/calternal-db/src/integrations.rs`, core migrations `0007`–`0010`, and `crates/plugins/calendar/migrations/0005_integration_account_link.sql`. Mail/Calendar credential, cache, route and client adapters are under `crates/plugins/mail/src/` and `crates/plugins/calendar/src/`. Contracts and evidence: `contracts/openapi.json`, `packages/api-client/src/generated.ts`, `tests/adversarial/integrations_api.mjs`, and `bench/integrations-407.mjs`.
Author
Owner

Independent data-integrity review started on job/integrations-review, based on ffb73a099a. No production code changes, push or deploy. Tests will be supplied as patches. Fetched origin/dev is 687ff70313. At this SHA, Mail migration 0009 from #626 is not yet present; the duplicate-message hotfix keeps the first UID. I will check the #626 branch separately and label that fixture clearly.

Independent data-integrity review started on job/integrations-review, based on ffb73a099ad521cca3d854507a2ad02f198c27e8. No production code changes, push or deploy. Tests will be supplied as patches. Fetched origin/dev is 687ff703136e71e89f8dfba139e93cd0788b25c1. At this SHA, Mail migration 0009 from #626 is not yet present; the duplicate-message hotfix keeps the first UID. I will check the #626 branch separately and label that fixture clearly.
Author
Owner

Independent #407 review: two blocking findings at ffb73a099.

  1. Migrated Mail accounts cannot change read state or download upstream attachments. crates/plugins/mail/src/routes.rs:1532–1535 and 1635–1638 still decrypt account.encrypted_credential. The account migration explicitly clears that ciphertext (crates/calternal-server/src/integrations.rs:416–417). Sync correctly uses decrypt_integration, but these routes return 500 before contacting the provider.
  2. Old-image-only rollback is unsafe. Legacy credentials are cleared after successful migration. calternal-db/src/migrations.rs:167–185 checks only known versions; it does not reject unknown newer versions. Thus the old binary can pass schema startup and health while Mail/Calendar sync cannot authenticate. deploy/deploy-cloud.sh:41–50 has no restore or downgrade guard. Startup does create a pre-migration Index snapshot (wire.rs:1135–1142); rollback must restore the correct snapshot or refuse the old binary before it opens the upgraded Index.

Tests are building: exact cache snapshots for 4,000 messages and 18 repeated message IDs, idempotent rerun, credential preservation after re-wrap, and a fault injected after Mail ciphertext is cleared inside the transaction. No fixes to production code are made by this review.

Independent #407 review: two blocking findings at ffb73a099. 1. Migrated Mail accounts cannot change read state or download upstream attachments. `crates/plugins/mail/src/routes.rs:1532–1535` and `1635–1638` still decrypt `account.encrypted_credential`. The account migration explicitly clears that ciphertext (`crates/calternal-server/src/integrations.rs:416–417`). Sync correctly uses `decrypt_integration`, but these routes return 500 before contacting the provider. 2. Old-image-only rollback is unsafe. Legacy credentials are cleared after successful migration. `calternal-db/src/migrations.rs:167–185` checks only known versions; it does not reject unknown newer versions. Thus the old binary can pass schema startup and health while Mail/Calendar sync cannot authenticate. `deploy/deploy-cloud.sh:41–50` has no restore or downgrade guard. Startup does create a pre-migration Index snapshot (`wire.rs:1135–1142`); rollback must restore the correct snapshot or refuse the old binary before it opens the upgraded Index. Tests are building: exact cache snapshots for 4,000 messages and 18 repeated message IDs, idempotent rerun, credential preservation after re-wrap, and a fault injected after Mail ciphertext is cleared inside the transaction. No fixes to production code are made by this review.
Author
Owner

Additional #407 finding: legacy create APIs remain active after the one-time migration.

POST /api/v1/mail/accounts (mail/src/routes.rs:814–836) and POST /api/v1/calendar/accounts (calendar/src/routes.rs:805–838) still store standalone service accounts. integrations.rs:180–186 returns immediately whenever the global marker is complete. Later service rows will not appear in Connected Accounts, including after a restart. A diagnostic test seeds a second legacy account after completion and checks that another migration call skips it. Fix by retiring or delegating legacy create writers, or by safely reconciling new rows. This is a control-state consistency gap, not a claim that existing cached messages are deleted.

Additional #407 finding: legacy create APIs remain active after the one-time migration. `POST /api/v1/mail/accounts` (`mail/src/routes.rs:814–836`) and `POST /api/v1/calendar/accounts` (`calendar/src/routes.rs:805–838`) still store standalone service accounts. `integrations.rs:180–186` returns immediately whenever the global marker is complete. Later service rows will not appear in Connected Accounts, including after a restart. A diagnostic test seeds a second legacy account after completion and checks that another migration call skips it. Fix by retiring or delegating legacy create writers, or by safely reconciling new rows. This is a control-state consistency gap, not a claim that existing cached messages are deleted.
Author
Owner

#626 compatibility finding: after Mail migration 0009 removes UNIQUE(folder_id,generation,message_id), the reviewed binary still uses that conflict target in mail/src/cache/store.rs:988–991. SQLite rejects the membership INSERT with “ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint”. Ship #626's store adapter change together with its SQL; the Connected Accounts migration preserving cache rows does not itself provide runtime compatibility with Mail 0009. This is covered by the production-shaped fixture diagnostic. Fetched origin/dev still has Mail 1–8; this finding concerns the pending #626 production shape.

#626 compatibility finding: after Mail migration 0009 removes UNIQUE(folder_id,generation,message_id), the reviewed binary still uses that conflict target in `mail/src/cache/store.rs:988–991`. SQLite rejects the membership INSERT with “ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint”. Ship #626's store adapter change together with its SQL; the Connected Accounts migration preserving cache rows does not itself provide runtime compatibility with Mail 0009. This is covered by the production-shaped fixture diagnostic. Fetched origin/dev still has Mail 1–8; this finding concerns the pending #626 production shape.
Author
Owner

Independent #407 diagnostic test patch against ffb73a099. Test-only commit: 8274c17e8. No production fixes. Four diagnostics passed at the review target; observed 500s are evidence of defects, not acceptance expectations for the eventual fixes. The SQL fixture is the exact pending #626 migration from 98b627f45. All credential strings are inert test fixtures. The server test build requires a production web build for RustEmbed.

diff --git a/crates/calternal-server/src/integrations.rs b/crates/calternal-server/src/integrations.rs
index 794abf5c8..b9a0bee16 100644
--- a/crates/calternal-server/src/integrations.rs
+++ b/crates/calternal-server/src/integrations.rs
@@ -2441,4 +2441,6 @@ mod tests {
             true
         );
     }
+    // Independent #407 review evidence; this module changes tests only.
+    include!("integrations_review.rs");
 }
diff --git a/crates/calternal-server/src/integrations_review.rs b/crates/calternal-server/src/integrations_review.rs
new file mode 100644
index 000000000..2b6b5096b
--- /dev/null
+++ b/crates/calternal-server/src/integrations_review.rs
@@ -0,0 +1,358 @@
+/// Independent data-integrity evidence for #407 at ffb73a099. This module uses
+/// inert credentials and the exact #626 SQL from 98b627f45, which was not on
+/// origin/dev at review time. It does not change server behaviour.
+mod independent_review {
+    use super::*;
+
+    /// Read every column in stable order, including BLOBs, for exact cache comparison.
+    /// Table names and column names come only from these test-owned schema constants.
+    async fn snapshot(db: &Db, table: &str) -> Vec<String> {
+        let pragma = format!("PRAGMA table_info({table})");
+        let columns = sqlx::query(sqlx::AssertSqlSafe(pragma.as_str()))
+            .fetch_all(db.reader_pool())
+            .await
+            .unwrap();
+        let quoted = columns
+            .iter()
+            .map(|row| {
+                let name: String = row.get("name");
+                format!("quote(\"{name}\")")
+            })
+            .collect::<Vec<_>>()
+            .join(",");
+        let order = quoted.clone();
+        let sql = format!("SELECT json_array({quoted}) FROM {table} ORDER BY {order}");
+        sqlx::query_scalar(sqlx::AssertSqlSafe(sql.as_str()))
+            .fetch_all(db.reader_pool())
+            .await
+            .unwrap()
+    }
+
+    /// Print a reproducible FNV-1a checksum without logging message or credential values.
+    fn checksum(rows: &[String]) -> u64 {
+        rows.iter()
+            .flat_map(|row| row.bytes().chain([0]))
+            .fold(0xcbf29ce484222325, |hash, byte| {
+                (hash ^ u64::from(byte)).wrapping_mul(0x100000001b3)
+            })
+    }
+
+    /// Build the production-shaped Fastmail account using existing legacy fixture helpers.
+    async fn fastmail(db: &Db) {
+        seed_legacy_mail_account(
+            db,
+            LegacyMailAccountSeed {
+                id: ACCOUNT,
+                email: "reader@fastmail.test",
+                provider: "fastmail",
+                imap_host: "imap.fastmail.com",
+                username: "reader@fastmail.test",
+                app_password: "fixture-imap",
+                smtp_username: "smtp@fastmail.test",
+                smtp_app_password: "fixture-smtp",
+                created_ms: 1000,
+            },
+        )
+        .await;
+        seed_legacy_mail_cache(
+            db,
+            ACCOUNT,
+            "51000000-0000-4000-8000-000000000011",
+            "51000000-0000-4000-8000-000000000021",
+            777,
+            1,
+        )
+        .await;
+    }
+
+    /// Apply the reviewed upgrade after seeding an old database; #626 stays in its own namespace.
+    async fn upgrade(db: &Db) {
+        db.apply_migration_sets(&[
+            built_in_migrations(),
+            calternal_plugin_mail::migrations(),
+            calternal_plugin_calendar::migrations(),
+        ])
+        .await
+        .unwrap();
+    }
+
+    /// Preserve every cache column for 4,000 messages and 18 repeated message IDs,
+    /// then prove idempotence, shared password recovery, and legacy decrypt failure (#407).
+    #[tokio::test]
+    async fn production_shape_preserves_cache_but_breaks_legacy_decrypt() {
+        let (_directory, db) = setup_pre_upgrade_schema().await;
+        fastmail(&db).await;
+        let mail_namespace = calternal_plugin_mail::migrations().namespace;
+        db.apply_migration_sets(&[calternal_db::MigrationSet::new(
+            mail_namespace,
+            vec![calternal_db::Migration::new(
+                9,
+                "review fixture: #626 duplicate UIDs",
+                include_str!("../tests/review/0009_duplicate_uid_memberships.sql"),
+            )],
+        )])
+        .await
+        .unwrap();
+        sqlx::raw_sql("WITH RECURSIVE n(i) AS (VALUES(2) UNION ALL SELECT i+1 FROM n WHERE i<4000)
+            INSERT INTO mail_messages (id, owner_id, account_id, rfc_message_id, subject,
+                from_json, to_json, cc_json, bcc_json, received_ms, preview, body_text, created_ms)
+            SELECT printf('51000000-0000-4000-8000-%012d', i+100),
+                (SELECT owner_id FROM mail_accounts LIMIT 1),
+                (SELECT id FROM mail_accounts LIMIT 1), printf('<fixture-%d@example.test>',i),
+                'Cached', '[]','[]','[]','[]', 1700000000000+i, 'preview', 'body', 1000 FROM n;
+            WITH RECURSIVE n(i) AS (VALUES(2) UNION ALL SELECT i+1 FROM n WHERE i<4018)
+            INSERT INTO mail_memberships (folder_id,generation,message_id,uid_validity,uid,flags_json,labels_json)
+            SELECT '51000000-0000-4000-8000-000000000011',1,
+                printf('51000000-0000-4000-8000-%012d',CASE WHEN i<=4000 THEN i+100 ELSE i-4000+101 END),
+                777,i,CASE WHEN i%2=0 THEN json_array(char(92)||'Seen') ELSE '[]' END,'[]' FROM n;")
+            .execute(db.writer_pool()).await.unwrap();
+        sqlx::raw_sql("UPDATE mail_folders SET uid_next=4020;
+            UPDATE mail_sync_generations SET uid_next=4019,backfill_top_uid=4018,
+                low_water_uid=1,delta_cursor=4018 WHERE generation=1;
+            UPDATE mail_sync_generations SET uid_next=4020,backfill_top_uid=4019 WHERE generation=2;")
+            .execute(db.writer_pool()).await.unwrap();
+        let duplicates: i64 = sqlx::query_scalar(
+            "SELECT COUNT(*)-COUNT(DISTINCT message_id) FROM mail_memberships WHERE generation=1",
+        )
+        .fetch_one(db.reader_pool())
+        .await
+        .unwrap();
+        assert_eq!(duplicates, 18);
+        seed_legacy_calendar_account(&db, "51000000-0000-4000-8000-000000000031").await;
+        let tables = [
+            "mail_messages",
+            "mail_memberships",
+            "mail_folders",
+            "mail_sync_generations",
+            "calendar_calendars",
+            "calendar_events",
+        ];
+        let mut before = Vec::new();
+        for table in tables {
+            before.push(snapshot(&db, table).await);
+        }
+        assert_eq!(before[0].len(), 4000);
+        assert_eq!(before[1].len(), 4018);
+        // This is the reviewed store_window membership statement. #626 removes
+        // its second conflict target, so the old binary cannot write this schema.
+        let conflict = sqlx::query(
+            "INSERT INTO mail_memberships
+            (folder_id,generation,message_id,uid_validity,uid,flags_json,labels_json)
+            VALUES ('51000000-0000-4000-8000-000000000011',1,
+                '51000000-0000-4000-8000-000000000021',777,9000,'[]','[]')
+            ON CONFLICT(folder_id,generation,uid) DO UPDATE SET flags_json=excluded.flags_json
+            ON CONFLICT(folder_id,generation,message_id) DO NOTHING",
+        )
+        .execute(db.writer_pool())
+        .await
+        .unwrap_err();
+        assert!(
+            conflict
+                .as_database_error()
+                .unwrap()
+                .message()
+                .contains("ON CONFLICT clause does not match")
+        );
+        println!("review #626 compatibility: old membership conflict target is rejected");
+        let old: (Vec<u8>, Vec<u8>) = sqlx::query_as(
+            "SELECT credential_nonce,credential_ciphertext FROM mail_accounts WHERE id=?",
+        )
+        .bind(ACCOUNT)
+        .fetch_one(db.reader_pool())
+        .await
+        .unwrap();
+        upgrade(&db).await;
+        let start = std::time::Instant::now();
+        migrate_legacy_accounts(&db, [31; 32]).await.unwrap();
+        println!(
+            "review local migration elapsed_us={}",
+            start.elapsed().as_micros()
+        );
+        for (table, expected) in tables.iter().zip(&before) {
+            let after = snapshot(&db, table).await;
+            assert_eq!(&after, expected, "{table}");
+            println!(
+                "review {table}: rows={} before={:016x} after={:016x}",
+                expected.len(),
+                checksum(expected),
+                checksum(&after)
+            );
+        }
+        let shared = calternal_db::get_integration_account(&db, OWNER, ACCOUNT)
+            .await
+            .unwrap()
+            .unwrap();
+        assert_ne!(shared.credential.nonce, old.0);
+        assert_ne!(shared.credential.ciphertext, old.1);
+        let clear = IntegrationKey::new([31; 32])
+            .unwrap()
+            .decrypt(OWNER, ACCOUNT, &shared.credential)
+            .unwrap();
+        assert_eq!(clear.app_password(), "fixture-imap");
+        assert_eq!(clear.smtp_app_password(), "fixture-smtp");
+        let empty: (Vec<u8>, Vec<u8>) = sqlx::query_as(
+            "SELECT credential_nonce,credential_ciphertext FROM mail_accounts WHERE id=?",
+        )
+        .bind(ACCOUNT)
+        .fetch_one(db.reader_pool())
+        .await
+        .unwrap();
+        assert!(
+            calternal_plugin_mail::InstanceKey::new([31; 32])
+                .unwrap()
+                .decrypt(
+                    OWNER,
+                    ACCOUNT,
+                    &calternal_plugin_mail::EncryptedCredential {
+                        nonce: empty.0,
+                        ciphertext: empty.1
+                    }
+                )
+                .is_err()
+        );
+        let state = snapshot(&db, "integration_accounts").await;
+        let marker = snapshot(&db, "integration_migration_status").await;
+        upgrade(&db).await;
+        migrate_legacy_accounts(&db, [31; 32]).await.unwrap();
+        assert_eq!(snapshot(&db, "integration_accounts").await, state);
+        assert_eq!(snapshot(&db, "integration_migration_status").await, marker);
+        for (table, expected) in tables.iter().zip(&before) {
+            assert_eq!(&snapshot(&db, table).await, expected);
+        }
+        // An old runner ignores newer migration versions, so it does not refuse downgrade.
+        let mut old_core = built_in_migrations();
+        old_core.migrations.truncate(6);
+        let mut old_calendar = calternal_plugin_calendar::migrations();
+        old_calendar.migrations.truncate(4);
+        db.apply_migration_sets(&[old_core, calternal_plugin_mail::migrations(), old_calendar])
+            .await
+            .unwrap();
+    }
+
+    /// Fail after the Mail credential has been cleared inside the transaction.
+    /// Rollback must restore that ciphertext, and removing the fault must permit retry (#407).
+    #[tokio::test]
+    async fn late_statement_failure_rolls_back_then_retries() {
+        let (_directory, db) = setup_pre_upgrade_schema().await;
+        fastmail(&db).await;
+        seed_legacy_calendar_account(&db, "51000000-0000-4000-8000-000000000031").await;
+        upgrade(&db).await;
+        let mail = snapshot(&db, "mail_accounts").await;
+        let calendar = snapshot(&db, "calendar_accounts").await;
+        sqlx::raw_sql("CREATE TRIGGER review_fail BEFORE UPDATE ON calendar_accounts BEGIN SELECT RAISE(ABORT,'review injected fault'); END;")
+            .execute(db.writer_pool()).await.unwrap();
+        assert!(matches!(
+            migrate_legacy_accounts(&db, [31; 32]).await,
+            Err(LegacyMigrationErrorCode::Database)
+        ));
+        assert_eq!(snapshot(&db, "mail_accounts").await, mail);
+        assert_eq!(snapshot(&db, "calendar_accounts").await, calendar);
+        assert!(snapshot(&db, "integration_accounts").await.is_empty());
+        sqlx::raw_sql("DROP TRIGGER review_fail")
+            .execute(db.writer_pool())
+            .await
+            .unwrap();
+        migrate_legacy_accounts(&db, [31; 32]).await.unwrap();
+        assert!(!snapshot(&db, "integration_accounts").await.is_empty());
+    }
+    /// Observe the two missed credential consumers on a real loopback server.
+    /// Expected 500s record the reviewed defect; they are diagnostic evidence,
+    /// not the acceptance behaviour for its eventual fix (#407).
+    #[tokio::test]
+    async fn migrated_mail_actions_return_500_before_provider_io() {
+        let (directory, db) = setup_pre_upgrade_schema().await;
+        fastmail(&db).await;
+        let message_id = "51000000-0000-4000-8000-000000000021";
+        sqlx::query(
+            "INSERT INTO mail_message_attachments
+            (owner_id,message_id,section_id,filename,content_type,transfer_encoding,size_bytes)
+            VALUES (?,?,'2','fixture.txt','text/plain','base64',100)",
+        )
+        .bind(OWNER)
+        .bind(message_id)
+        .execute(db.writer_pool())
+        .await
+        .unwrap();
+        upgrade(&db).await;
+        migrate_legacy_accounts(&db, [31; 32]).await.unwrap();
+        calternal_plugin_mail::configure_instance_secret_key([31; 32]).unwrap();
+        let plugin = calternal_plugin::CORE_PLUGINS
+            .iter()
+            .map(|factory| factory())
+            .find(|plugin| plugin.manifest().id == "mail")
+            .unwrap();
+        let app = plugin
+            .router(&calternal_plugin::PluginContext {
+                instance_name: "Review".into(),
+                live_instance_name: None,
+                data: Some(calternal_plugin::PluginData {
+                    root: calternal_fs::Root::open(directory.path(), false).unwrap(),
+                    db,
+                }),
+            })
+            .layer(Extension(context(OWNER)));
+        let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
+        let address = listener.local_addr().unwrap();
+        let server = tokio::spawn(async move {
+            axum::serve(listener, app).await.unwrap();
+        });
+        let client = reqwest::Client::new();
+        let read = client
+            .post(format!("http://{address}/messages/{message_id}/read-state"))
+            .header("content-type", "application/json")
+            .body(r#"{"read":false}"#)
+            .send()
+            .await
+            .unwrap();
+        let attachment = client
+            .get(format!(
+                "http://{address}/messages/{message_id}/attachments/2"
+            ))
+            .send()
+            .await
+            .unwrap();
+        server.abort();
+        assert_eq!(read.status(), StatusCode::INTERNAL_SERVER_ERROR);
+        assert_eq!(attachment.status(), StatusCode::INTERNAL_SERVER_ERROR);
+        println!("review real loopback: read-state=500 attachment=500 (no provider IO)");
+    }
+    /// Legacy create APIs still write service rows after the one-time marker.
+    /// A later boot must be shown to skip those rows so #407 can close this gap.
+    #[tokio::test]
+    async fn completed_marker_skips_later_legacy_accounts() {
+        let (_directory, db) = setup_pre_upgrade_schema().await;
+        fastmail(&db).await;
+        upgrade(&db).await;
+        migrate_legacy_accounts(&db, [31; 32]).await.unwrap();
+        let later = "51000000-0000-4000-8000-000000000099";
+        seed_legacy_mail_account(
+            &db,
+            LegacyMailAccountSeed {
+                id: later,
+                email: "later@fastmail.test",
+                provider: "fastmail",
+                imap_host: "imap.fastmail.com",
+                username: "later@fastmail.test",
+                app_password: "fixture-imap",
+                smtp_username: "later@fastmail.test",
+                smtp_app_password: "fixture-smtp",
+                created_ms: 2000,
+            },
+        )
+        .await;
+        migrate_legacy_accounts(&db, [31; 32]).await.unwrap();
+        assert!(
+            calternal_db::get_integration_account(&db, OWNER, later)
+                .await
+                .unwrap()
+                .is_none()
+        );
+        assert_eq!(
+            list_integration_accounts(&db, OWNER).await.unwrap().len(),
+            1
+        );
+        println!(
+            "review completed marker: later legacy account remains outside Connected Accounts"
+        );
+    }
+}
diff --git a/crates/calternal-server/tests/review/0009_duplicate_uid_memberships.sql b/crates/calternal-server/tests/review/0009_duplicate_uid_memberships.sql
new file mode 100644
index 000000000..e3519547f
--- /dev/null
+++ b/crates/calternal-server/tests/review/0009_duplicate_uid_memberships.sql
@@ -0,0 +1,24 @@
+-- Issue #626: keep each provider UID even when several copies share one Mail message.
+-- SQLite cannot drop this table constraint in place, so rebuild the projection table.
+CREATE TABLE mail_memberships_new (
+    folder_id TEXT NOT NULL REFERENCES mail_folders(id) ON DELETE CASCADE,
+    generation INTEGER NOT NULL CHECK (generation >= 1),
+    message_id TEXT NOT NULL REFERENCES mail_messages(id) ON DELETE CASCADE,
+    uid_validity INTEGER NOT NULL,
+    uid INTEGER NOT NULL CHECK (uid BETWEEN 1 AND 4294967295),
+    flags_json TEXT NOT NULL DEFAULT '[]',
+    labels_json TEXT NOT NULL DEFAULT '[]',
+    PRIMARY KEY(folder_id, generation, uid)
+);
+
+INSERT INTO mail_memberships_new
+    (folder_id, generation, message_id, uid_validity, uid, flags_json, labels_json)
+SELECT folder_id, generation, message_id, uid_validity, uid, flags_json, labels_json
+FROM mail_memberships;
+
+DROP TABLE mail_memberships;
+ALTER TABLE mail_memberships_new RENAME TO mail_memberships;
+
+CREATE INDEX mail_memberships_message ON mail_memberships(message_id, folder_id);
+CREATE INDEX mail_memberships_folder_message
+    ON mail_memberships(folder_id, generation, message_id, uid);
Independent #407 diagnostic test patch against ffb73a099. Test-only commit: 8274c17e8. No production fixes. Four diagnostics passed at the review target; observed 500s are evidence of defects, not acceptance expectations for the eventual fixes. The SQL fixture is the exact pending #626 migration from 98b627f45. All credential strings are inert test fixtures. The server test build requires a production web build for RustEmbed. ```diff diff --git a/crates/calternal-server/src/integrations.rs b/crates/calternal-server/src/integrations.rs index 794abf5c8..b9a0bee16 100644 --- a/crates/calternal-server/src/integrations.rs +++ b/crates/calternal-server/src/integrations.rs @@ -2441,4 +2441,6 @@ mod tests { true ); } + // Independent #407 review evidence; this module changes tests only. + include!("integrations_review.rs"); } diff --git a/crates/calternal-server/src/integrations_review.rs b/crates/calternal-server/src/integrations_review.rs new file mode 100644 index 000000000..2b6b5096b --- /dev/null +++ b/crates/calternal-server/src/integrations_review.rs @@ -0,0 +1,358 @@ +/// Independent data-integrity evidence for #407 at ffb73a099. This module uses +/// inert credentials and the exact #626 SQL from 98b627f45, which was not on +/// origin/dev at review time. It does not change server behaviour. +mod independent_review { + use super::*; + + /// Read every column in stable order, including BLOBs, for exact cache comparison. + /// Table names and column names come only from these test-owned schema constants. + async fn snapshot(db: &Db, table: &str) -> Vec<String> { + let pragma = format!("PRAGMA table_info({table})"); + let columns = sqlx::query(sqlx::AssertSqlSafe(pragma.as_str())) + .fetch_all(db.reader_pool()) + .await + .unwrap(); + let quoted = columns + .iter() + .map(|row| { + let name: String = row.get("name"); + format!("quote(\"{name}\")") + }) + .collect::<Vec<_>>() + .join(","); + let order = quoted.clone(); + let sql = format!("SELECT json_array({quoted}) FROM {table} ORDER BY {order}"); + sqlx::query_scalar(sqlx::AssertSqlSafe(sql.as_str())) + .fetch_all(db.reader_pool()) + .await + .unwrap() + } + + /// Print a reproducible FNV-1a checksum without logging message or credential values. + fn checksum(rows: &[String]) -> u64 { + rows.iter() + .flat_map(|row| row.bytes().chain([0])) + .fold(0xcbf29ce484222325, |hash, byte| { + (hash ^ u64::from(byte)).wrapping_mul(0x100000001b3) + }) + } + + /// Build the production-shaped Fastmail account using existing legacy fixture helpers. + async fn fastmail(db: &Db) { + seed_legacy_mail_account( + db, + LegacyMailAccountSeed { + id: ACCOUNT, + email: "reader@fastmail.test", + provider: "fastmail", + imap_host: "imap.fastmail.com", + username: "reader@fastmail.test", + app_password: "fixture-imap", + smtp_username: "smtp@fastmail.test", + smtp_app_password: "fixture-smtp", + created_ms: 1000, + }, + ) + .await; + seed_legacy_mail_cache( + db, + ACCOUNT, + "51000000-0000-4000-8000-000000000011", + "51000000-0000-4000-8000-000000000021", + 777, + 1, + ) + .await; + } + + /// Apply the reviewed upgrade after seeding an old database; #626 stays in its own namespace. + async fn upgrade(db: &Db) { + db.apply_migration_sets(&[ + built_in_migrations(), + calternal_plugin_mail::migrations(), + calternal_plugin_calendar::migrations(), + ]) + .await + .unwrap(); + } + + /// Preserve every cache column for 4,000 messages and 18 repeated message IDs, + /// then prove idempotence, shared password recovery, and legacy decrypt failure (#407). + #[tokio::test] + async fn production_shape_preserves_cache_but_breaks_legacy_decrypt() { + let (_directory, db) = setup_pre_upgrade_schema().await; + fastmail(&db).await; + let mail_namespace = calternal_plugin_mail::migrations().namespace; + db.apply_migration_sets(&[calternal_db::MigrationSet::new( + mail_namespace, + vec![calternal_db::Migration::new( + 9, + "review fixture: #626 duplicate UIDs", + include_str!("../tests/review/0009_duplicate_uid_memberships.sql"), + )], + )]) + .await + .unwrap(); + sqlx::raw_sql("WITH RECURSIVE n(i) AS (VALUES(2) UNION ALL SELECT i+1 FROM n WHERE i<4000) + INSERT INTO mail_messages (id, owner_id, account_id, rfc_message_id, subject, + from_json, to_json, cc_json, bcc_json, received_ms, preview, body_text, created_ms) + SELECT printf('51000000-0000-4000-8000-%012d', i+100), + (SELECT owner_id FROM mail_accounts LIMIT 1), + (SELECT id FROM mail_accounts LIMIT 1), printf('<fixture-%d@example.test>',i), + 'Cached', '[]','[]','[]','[]', 1700000000000+i, 'preview', 'body', 1000 FROM n; + WITH RECURSIVE n(i) AS (VALUES(2) UNION ALL SELECT i+1 FROM n WHERE i<4018) + INSERT INTO mail_memberships (folder_id,generation,message_id,uid_validity,uid,flags_json,labels_json) + SELECT '51000000-0000-4000-8000-000000000011',1, + printf('51000000-0000-4000-8000-%012d',CASE WHEN i<=4000 THEN i+100 ELSE i-4000+101 END), + 777,i,CASE WHEN i%2=0 THEN json_array(char(92)||'Seen') ELSE '[]' END,'[]' FROM n;") + .execute(db.writer_pool()).await.unwrap(); + sqlx::raw_sql("UPDATE mail_folders SET uid_next=4020; + UPDATE mail_sync_generations SET uid_next=4019,backfill_top_uid=4018, + low_water_uid=1,delta_cursor=4018 WHERE generation=1; + UPDATE mail_sync_generations SET uid_next=4020,backfill_top_uid=4019 WHERE generation=2;") + .execute(db.writer_pool()).await.unwrap(); + let duplicates: i64 = sqlx::query_scalar( + "SELECT COUNT(*)-COUNT(DISTINCT message_id) FROM mail_memberships WHERE generation=1", + ) + .fetch_one(db.reader_pool()) + .await + .unwrap(); + assert_eq!(duplicates, 18); + seed_legacy_calendar_account(&db, "51000000-0000-4000-8000-000000000031").await; + let tables = [ + "mail_messages", + "mail_memberships", + "mail_folders", + "mail_sync_generations", + "calendar_calendars", + "calendar_events", + ]; + let mut before = Vec::new(); + for table in tables { + before.push(snapshot(&db, table).await); + } + assert_eq!(before[0].len(), 4000); + assert_eq!(before[1].len(), 4018); + // This is the reviewed store_window membership statement. #626 removes + // its second conflict target, so the old binary cannot write this schema. + let conflict = sqlx::query( + "INSERT INTO mail_memberships + (folder_id,generation,message_id,uid_validity,uid,flags_json,labels_json) + VALUES ('51000000-0000-4000-8000-000000000011',1, + '51000000-0000-4000-8000-000000000021',777,9000,'[]','[]') + ON CONFLICT(folder_id,generation,uid) DO UPDATE SET flags_json=excluded.flags_json + ON CONFLICT(folder_id,generation,message_id) DO NOTHING", + ) + .execute(db.writer_pool()) + .await + .unwrap_err(); + assert!( + conflict + .as_database_error() + .unwrap() + .message() + .contains("ON CONFLICT clause does not match") + ); + println!("review #626 compatibility: old membership conflict target is rejected"); + let old: (Vec<u8>, Vec<u8>) = sqlx::query_as( + "SELECT credential_nonce,credential_ciphertext FROM mail_accounts WHERE id=?", + ) + .bind(ACCOUNT) + .fetch_one(db.reader_pool()) + .await + .unwrap(); + upgrade(&db).await; + let start = std::time::Instant::now(); + migrate_legacy_accounts(&db, [31; 32]).await.unwrap(); + println!( + "review local migration elapsed_us={}", + start.elapsed().as_micros() + ); + for (table, expected) in tables.iter().zip(&before) { + let after = snapshot(&db, table).await; + assert_eq!(&after, expected, "{table}"); + println!( + "review {table}: rows={} before={:016x} after={:016x}", + expected.len(), + checksum(expected), + checksum(&after) + ); + } + let shared = calternal_db::get_integration_account(&db, OWNER, ACCOUNT) + .await + .unwrap() + .unwrap(); + assert_ne!(shared.credential.nonce, old.0); + assert_ne!(shared.credential.ciphertext, old.1); + let clear = IntegrationKey::new([31; 32]) + .unwrap() + .decrypt(OWNER, ACCOUNT, &shared.credential) + .unwrap(); + assert_eq!(clear.app_password(), "fixture-imap"); + assert_eq!(clear.smtp_app_password(), "fixture-smtp"); + let empty: (Vec<u8>, Vec<u8>) = sqlx::query_as( + "SELECT credential_nonce,credential_ciphertext FROM mail_accounts WHERE id=?", + ) + .bind(ACCOUNT) + .fetch_one(db.reader_pool()) + .await + .unwrap(); + assert!( + calternal_plugin_mail::InstanceKey::new([31; 32]) + .unwrap() + .decrypt( + OWNER, + ACCOUNT, + &calternal_plugin_mail::EncryptedCredential { + nonce: empty.0, + ciphertext: empty.1 + } + ) + .is_err() + ); + let state = snapshot(&db, "integration_accounts").await; + let marker = snapshot(&db, "integration_migration_status").await; + upgrade(&db).await; + migrate_legacy_accounts(&db, [31; 32]).await.unwrap(); + assert_eq!(snapshot(&db, "integration_accounts").await, state); + assert_eq!(snapshot(&db, "integration_migration_status").await, marker); + for (table, expected) in tables.iter().zip(&before) { + assert_eq!(&snapshot(&db, table).await, expected); + } + // An old runner ignores newer migration versions, so it does not refuse downgrade. + let mut old_core = built_in_migrations(); + old_core.migrations.truncate(6); + let mut old_calendar = calternal_plugin_calendar::migrations(); + old_calendar.migrations.truncate(4); + db.apply_migration_sets(&[old_core, calternal_plugin_mail::migrations(), old_calendar]) + .await + .unwrap(); + } + + /// Fail after the Mail credential has been cleared inside the transaction. + /// Rollback must restore that ciphertext, and removing the fault must permit retry (#407). + #[tokio::test] + async fn late_statement_failure_rolls_back_then_retries() { + let (_directory, db) = setup_pre_upgrade_schema().await; + fastmail(&db).await; + seed_legacy_calendar_account(&db, "51000000-0000-4000-8000-000000000031").await; + upgrade(&db).await; + let mail = snapshot(&db, "mail_accounts").await; + let calendar = snapshot(&db, "calendar_accounts").await; + sqlx::raw_sql("CREATE TRIGGER review_fail BEFORE UPDATE ON calendar_accounts BEGIN SELECT RAISE(ABORT,'review injected fault'); END;") + .execute(db.writer_pool()).await.unwrap(); + assert!(matches!( + migrate_legacy_accounts(&db, [31; 32]).await, + Err(LegacyMigrationErrorCode::Database) + )); + assert_eq!(snapshot(&db, "mail_accounts").await, mail); + assert_eq!(snapshot(&db, "calendar_accounts").await, calendar); + assert!(snapshot(&db, "integration_accounts").await.is_empty()); + sqlx::raw_sql("DROP TRIGGER review_fail") + .execute(db.writer_pool()) + .await + .unwrap(); + migrate_legacy_accounts(&db, [31; 32]).await.unwrap(); + assert!(!snapshot(&db, "integration_accounts").await.is_empty()); + } + /// Observe the two missed credential consumers on a real loopback server. + /// Expected 500s record the reviewed defect; they are diagnostic evidence, + /// not the acceptance behaviour for its eventual fix (#407). + #[tokio::test] + async fn migrated_mail_actions_return_500_before_provider_io() { + let (directory, db) = setup_pre_upgrade_schema().await; + fastmail(&db).await; + let message_id = "51000000-0000-4000-8000-000000000021"; + sqlx::query( + "INSERT INTO mail_message_attachments + (owner_id,message_id,section_id,filename,content_type,transfer_encoding,size_bytes) + VALUES (?,?,'2','fixture.txt','text/plain','base64',100)", + ) + .bind(OWNER) + .bind(message_id) + .execute(db.writer_pool()) + .await + .unwrap(); + upgrade(&db).await; + migrate_legacy_accounts(&db, [31; 32]).await.unwrap(); + calternal_plugin_mail::configure_instance_secret_key([31; 32]).unwrap(); + let plugin = calternal_plugin::CORE_PLUGINS + .iter() + .map(|factory| factory()) + .find(|plugin| plugin.manifest().id == "mail") + .unwrap(); + let app = plugin + .router(&calternal_plugin::PluginContext { + instance_name: "Review".into(), + live_instance_name: None, + data: Some(calternal_plugin::PluginData { + root: calternal_fs::Root::open(directory.path(), false).unwrap(), + db, + }), + }) + .layer(Extension(context(OWNER))); + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let address = listener.local_addr().unwrap(); + let server = tokio::spawn(async move { + axum::serve(listener, app).await.unwrap(); + }); + let client = reqwest::Client::new(); + let read = client + .post(format!("http://{address}/messages/{message_id}/read-state")) + .header("content-type", "application/json") + .body(r#"{"read":false}"#) + .send() + .await + .unwrap(); + let attachment = client + .get(format!( + "http://{address}/messages/{message_id}/attachments/2" + )) + .send() + .await + .unwrap(); + server.abort(); + assert_eq!(read.status(), StatusCode::INTERNAL_SERVER_ERROR); + assert_eq!(attachment.status(), StatusCode::INTERNAL_SERVER_ERROR); + println!("review real loopback: read-state=500 attachment=500 (no provider IO)"); + } + /// Legacy create APIs still write service rows after the one-time marker. + /// A later boot must be shown to skip those rows so #407 can close this gap. + #[tokio::test] + async fn completed_marker_skips_later_legacy_accounts() { + let (_directory, db) = setup_pre_upgrade_schema().await; + fastmail(&db).await; + upgrade(&db).await; + migrate_legacy_accounts(&db, [31; 32]).await.unwrap(); + let later = "51000000-0000-4000-8000-000000000099"; + seed_legacy_mail_account( + &db, + LegacyMailAccountSeed { + id: later, + email: "later@fastmail.test", + provider: "fastmail", + imap_host: "imap.fastmail.com", + username: "later@fastmail.test", + app_password: "fixture-imap", + smtp_username: "later@fastmail.test", + smtp_app_password: "fixture-smtp", + created_ms: 2000, + }, + ) + .await; + migrate_legacy_accounts(&db, [31; 32]).await.unwrap(); + assert!( + calternal_db::get_integration_account(&db, OWNER, later) + .await + .unwrap() + .is_none() + ); + assert_eq!( + list_integration_accounts(&db, OWNER).await.unwrap().len(), + 1 + ); + println!( + "review completed marker: later legacy account remains outside Connected Accounts" + ); + } +} diff --git a/crates/calternal-server/tests/review/0009_duplicate_uid_memberships.sql b/crates/calternal-server/tests/review/0009_duplicate_uid_memberships.sql new file mode 100644 index 000000000..e3519547f --- /dev/null +++ b/crates/calternal-server/tests/review/0009_duplicate_uid_memberships.sql @@ -0,0 +1,24 @@ +-- Issue #626: keep each provider UID even when several copies share one Mail message. +-- SQLite cannot drop this table constraint in place, so rebuild the projection table. +CREATE TABLE mail_memberships_new ( + folder_id TEXT NOT NULL REFERENCES mail_folders(id) ON DELETE CASCADE, + generation INTEGER NOT NULL CHECK (generation >= 1), + message_id TEXT NOT NULL REFERENCES mail_messages(id) ON DELETE CASCADE, + uid_validity INTEGER NOT NULL, + uid INTEGER NOT NULL CHECK (uid BETWEEN 1 AND 4294967295), + flags_json TEXT NOT NULL DEFAULT '[]', + labels_json TEXT NOT NULL DEFAULT '[]', + PRIMARY KEY(folder_id, generation, uid) +); + +INSERT INTO mail_memberships_new + (folder_id, generation, message_id, uid_validity, uid, flags_json, labels_json) +SELECT folder_id, generation, message_id, uid_validity, uid, flags_json, labels_json +FROM mail_memberships; + +DROP TABLE mail_memberships; +ALTER TABLE mail_memberships_new RENAME TO mail_memberships; + +CREATE INDEX mail_memberships_message ON mail_memberships(message_id, folder_id); +CREATE INDEX mail_memberships_folder_message + ON mail_memberships(folder_id, generation, message_id, uid); ```
Author
Owner

Final review head: ad7e25c6392e75cd8360c82b9e716c8011b7fca1. Full final gate output follows verbatim; dependency build lines are retained.

Final gate transcript

Gated code head: af6616f4dc. All commands exited 0.

cargo fmt --check (exit 0):

stdout and stderr were empty.

cargo clippy -p calternal-server --all-targets -- -D warnings (exit 0):

   Compiling unicode-ident v1.0.26
    Checking cfg-if v1.0.5
    Checking libc v0.2.189
   Compiling proc-macro2 v1.0.107
    Checking serde_core v1.0.229
   Compiling quote v1.0.47
    Checking memchr v2.8.3
   Compiling jobserver v0.1.35
   Compiling syn v3.0.6
   Compiling syn v2.0.119
   Compiling cc v1.4.7
    Checking typenum v1.20.1
    Checking zeroize v1.9.0
    Checking log v0.4.34
    Checking itoa v1.0.18
    Checking pin-project-lite v0.2.17
    Checking once_cell v1.21.4
    Checking libm v0.2.16
    Checking smallvec v1.16.1
    Checking subtle v2.6.1
   Compiling serde_derive v1.0.229
   Compiling synstructure v0.14.0
    Checking num-traits v0.2.19
    Checking generic-array v0.14.9
   Compiling zerofrom-derive v0.1.8
   Compiling yoke-derive v0.8.3
    Checking serde v1.0.229
   Compiling displaydoc v0.2.7
    Checking bytes v1.12.1
    Checking const-oid v0.9.6
    Checking futures-core v0.3.34
    Checking crypto-common v0.1.6
   Compiling zerovec-derive v0.11.6
    Checking scopeguard v1.2.0
    Checking stable_deref_trait v1.2.1
    Checking block-buffer v0.10.4
   Compiling tracing-attributes v0.1.31
    Checking digest v0.10.7
    Checking rand_core v0.10.1
    Checking futures-sink v0.3.34
    Checking lock_api v0.4.14
    Checking getrandom v0.4.3
    Checking tracing-core v0.1.36
    Checking mio v1.2.3
    Checking bitflags v2.13.2
    Checking errno v0.3.14
   Compiling tokio-macros v2.7.2
    Checking socket2 v0.6.5
    Checking signal-hook-registry v1.4.8
    Checking tracing v0.1.44
   Compiling thiserror-impl v2.0.21
    Checking cmov v0.5.4
    Checking tokio v1.53.1
    Checking slab v0.4.12
    Checking equivalent v1.0.2
    Checking ctutils v0.4.2
    Checking futures-channel v0.3.34
    Checking zerofrom v0.1.8
    Checking hybrid-array v0.4.15
   Compiling futures-macro v0.3.34
    Checking futures-io v0.3.34
    Checking futures-task v0.3.34
    Checking yoke v0.8.3
    Checking zmij v1.0.23
    Checking serde_json v1.0.151
    Checking getrandom v0.2.17
    Checking futures-util v0.3.34
    Checking zerovec v0.11.8
   Compiling zerocopy-derive v0.8.58
    Checking percent-encoding v2.3.2
    Checking cpufeatures v0.2.17
    Checking thiserror v2.0.21
    Checking crypto-common v0.2.2
    Checking hashbrown v0.17.1
    Checking zerocopy v0.8.58
    Checking indexmap v2.14.2
   Compiling siphasher v1.0.3
    Checking tinystr v0.8.4
    Checking litemap v0.8.3
    Checking cpufeatures v0.3.1
    Checking writeable v0.6.4
    Checking base64 v0.22.1
    Checking icu_locale_core v2.3.0
    Checking potential_utf v0.1.6
    Checking zerotrie v0.2.5
    Checking utf8_iter v1.0.4
    Checking icu_collections v2.3.0
    Checking http v1.5.0
    Checking icu_provider v2.3.1
    Checking block-buffer v0.12.1
    Checking icu_normalizer_data v2.3.0
    Checking icu_properties_data v2.3.0
    Checking iana-time-zone v0.1.65
    Checking icu_normalizer v2.3.0
    Checking chrono v0.4.45
    Checking icu_properties v2.3.0
   Compiling ppv-lite86 v0.2.21
    Checking form_urlencoded v1.2.2
   Compiling rand_core v0.6.4
    Checking crossbeam-utils v0.8.23
   Compiling rand_chacha v0.3.1
    Checking idna_adapter v1.2.2
    Checking idna v1.1.0
   Compiling rand v0.8.8
    Checking parking_lot_core v0.9.12
    Checking tokio-util v0.7.19
    Checking fnv v1.0.7
    Checking url v2.5.8
    Checking spin v0.9.9
    Checking http-body v1.1.0
    Checking sha2 v0.10.9
    Checking minimal-lexical v0.2.1
    Checking tower-service v0.3.3
    Checking httparse v1.10.1
    Checking getrandom v0.3.4
    Checking nom v7.1.3
    Checking parking_lot v0.12.5
    Checking inout v0.2.2
    Checking httpdate v1.0.3
   Compiling phf_shared v0.11.3
    Checking try-lock v0.2.5
    Checking cipher v0.5.2
    Checking want v0.3.1
   Compiling phf_generator v0.11.3
    Checking base64ct v1.8.3
    Checking either v1.18.0
    Checking arrayvec v0.7.8
   Compiling strsim v0.11.1
    Checking http-body-util v0.1.5
   Compiling openssl-macros v0.1.1
   Compiling cmake v0.1.58
    Checking atomic-waker v1.1.2
    Checking tinyvec v1.13.3
    Checking regex-syntax v0.8.11
    Checking ryu v1.0.23
   Compiling aws-lc-sys v0.45.0
    Checking unicode-normalization v0.1.25
    Checking h2 v0.4.19
    Checking pem-rfc7468 v0.7.0
   Compiling openssl-src v300.6.1+3.6.3
   Compiling openssl-sys v0.9.117
    Checking der v0.7.10
    Checking rand_core v0.9.5
    Checking num-integer v0.1.47
    Checking ipnet v2.12.2
    Checking allocator-api2 v0.2.21
    Checking hyper v1.11.1
    Checking constant_time_eq v0.4.2
    Checking byteorder v1.5.0
    Checking foldhash v0.2.0
    Checking parking v2.2.1
    Checking hashbrown v0.16.1
    Checking event-listener v5.4.2
    Checking hyper-util v0.1.20
    Checking rand_chacha v0.9.0
    Checking spki v0.7.3
    Checking universal-hash v0.6.1
    Checking uuid v1.26.1
    Checking sync_wrapper v1.0.2
   Compiling thiserror-impl v1.0.69
   Compiling ring v0.17.14
    Checking aho-corasick v1.1.5
   Compiling num-conv v0.2.2
    Checking new_debug_unreachable v1.0.6
    Checking tower-layer v0.3.3
   Compiling time-core v0.1.9
    Checking thiserror v1.0.69
    Checking regex-automata v0.4.18
   Compiling time-macros v0.2.32
    Checking rand v0.9.5
    Checking pkcs8 v0.10.2
   Compiling phf_macros v0.11.3
    Checking rustls-pki-types v1.15.1
   Compiling blake3 v1.8.7
    Checking deranged v0.5.8
    Checking powerfmt v0.2.0
    Checking data-encoding v2.11.1
    Checking time v0.3.55
    Checking phf v0.11.3
    Checking tower v0.5.3
    Checking phf_shared v0.12.1
    Checking futures-executor v0.3.34
   Compiling libsqlite3-sys v0.37.0
   Compiling crc-catalog v2.5.0
    Checking untrusted v0.9.0
   Compiling crc v3.4.0
    Checking phf v0.12.1
   Compiling tokio-stream v0.1.19
   Compiling crossbeam-queue v0.3.14
   Compiling futures-intrusive v0.5.0
   Compiling hashlink v0.11.1
    Checking serde_urlencoded v0.7.1
    Checking chacha20 v0.10.2
    Checking aead v0.6.1
    Checking lazy_static v1.5.0
    Checking sha1 v0.10.7
    Checking mime v0.3.17
    Checking linux-raw-sys v0.12.1
    Checking precomputed-hash v0.1.1
   Compiling siphasher v0.3.11
   Compiling sqlx-core v0.9.0
    Checking rustix v1.1.5
   Compiling phf_shared v0.10.0
   Compiling flume v0.12.0
   Compiling atoi v2.0.0
   Compiling aws-lc-rs v1.18.1
   Compiling rustls v0.23.45
    Checking chrono-tz v0.10.4
    Checking rustls-webpki v0.103.15
   Compiling multiversion-macros v0.9.0
    Checking hmac v0.12.1
    Checking calternal-path v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-path)
    Checking unicode-properties v0.1.4
    Checking multiversion v0.9.0
   Compiling sqlx-sqlite v0.9.0
   Compiling syn v1.0.109
   Compiling phf_generator v0.10.0
    Checking regex v1.13.1
   Compiling darling_core v0.24.1
    Checking signature v2.2.0
   Compiling async-trait v0.1.92
    Checking serde_path_to_error v0.1.20
    Checking simdutf8 v0.1.5
   Compiling hex v0.4.3
    Checking foreign-types-shared v0.1.1
    Checking core_detect v1.0.0
   Compiling unicase v2.9.0
   Compiling sqlx-macros-core v0.9.0
    Checking encoding_rs v0.8.41
   Compiling mime_guess v2.0.5
   Compiling darling_macro v0.24.1
    Checking foreign-types v0.3.2
   Compiling openssl v0.10.81
   Compiling phf_codegen v0.10.0
    Checking hkdf v0.12.4
    Checking tungstenite v0.29.0
    Checking ff v0.13.1
    Checking same-file v1.0.6
    Checking base16ct v0.2.0
    Checking walkdir v2.5.0
    Checking sec1 v0.7.3
    Checking tokio-tungstenite v0.29.0
    Checking group v0.13.0
   Compiling utoipa-gen v6.0.1
   Compiling sqlx-macros v0.9.0
    Checking unicode-joining-type v1.0.0
   Compiling darling v0.24.1
    Checking tokio-rustls v0.26.6
    Checking axum-core v0.5.6
    Checking webpki-roots v1.0.9
    Checking poly1305 v0.9.1
    Checking crypto-bigint v0.5.5
   Compiling axum-macros v0.5.1
    Checking dtoa v1.0.11
    Checking matchit v0.8.4
    Checking winnow v0.7.15
    Checking unicode-casefold v0.2.0
    Checking axum v0.8.9
    Checking utoipa v6.0.0
    Checking calternal-fs v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-fs)
    Checking elliptic-curve v0.13.8
    Checking cron v0.17.0
    Checking dtoa-short v0.3.5
    Checking chacha20poly1305 v0.11.0
    Checking sqlx v0.9.0
    Checking ahash v0.8.12
    Checking inotify-sys v0.1.8
   Compiling synstructure v0.13.2
    Checking unsafe-libyaml v0.2.11
    Checking simd-adler32 v0.3.10
    Checking serde_yaml v0.9.34+deprecated
   Compiling asn1-rs-derive v0.5.1
    Checking inotify v0.11.5
    Checking calternal-db v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-db)
    Checking crc32fast v1.5.2
   Compiling linkme-impl v0.3.37
    Checking hyper-rustls v0.27.10
    Checking rfc6979 v0.4.0
    Checking tower-http v0.6.11
   Compiling string_cache_codegen v0.5.4
    Checking rusticata-macros v4.1.0
    Checking notify-types v2.1.0
   Compiling asn1-rs-impl v0.2.0
    Checking base64 v0.21.7
   Compiling winnow v1.0.4
    Checking mac v0.1.1
    Checking adler2 v2.0.1
    Checking openssl-probe v0.2.1
    Checking futf v0.1.5
    Checking asn1-rs v0.6.2
    Checking notify v8.2.0
   Compiling markup5ever v0.11.0
    Checking linkme v0.3.37
    Checking ecdsa v0.16.9
   Compiling toml_parser v1.1.3+spec-1.1.0
    Checking calternal-notes-core v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-notes-core)
    Checking phf v0.10.1
    Checking calternal-api v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-api)
    Checking num-iter v0.1.46
    Checking dyn-clone v1.0.20
    Checking utf-8 v0.7.6
    Checking base64urlsafedata v0.5.5
    Checking calternal-plugin v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-plugin)
    Checking tendril v0.4.3
   Compiling toml_edit v0.25.15+spec-1.1.0
    Checking num-bigint-dig v0.8.6
    Checking miniz_oxide v0.9.1
    Checking primeorder v0.13.6
   Compiling selectors v0.25.0
   Compiling html5ever v0.26.0
    Checking string_cache v0.8.9
    Checking pkcs1 v0.7.5
    Checking num-bigint v0.4.8
   Compiling hashify v0.2.9
   Compiling cssparser-macros v0.6.1
    Checking const-oid v0.10.2
    Checking utf8parse v0.2.2
   Compiling webauthn-attestation-ca v0.5.5
    Checking cssparser v0.31.2
    Checking der-parser v9.0.0
    Checking anstyle-parse v1.0.0
    Checking mail-parser v0.11.9
    Checking rsa v0.9.10
    Checking flate2 v1.1.10
   Compiling proc-macro-crate v3.5.0
    Checking oid-registry v0.7.1
    Checking reqwest v0.12.28
    Checking fxhash v0.2.1
    Checking half v2.7.1
    Checking servo_arc v0.3.0
   Compiling derive_more v0.99.20
    Checking weezl v0.1.12
    Checking anstyle v1.0.14
    Checking anstyle-query v1.1.5
    Checking unicode-width v0.2.2
    Checking htmlescape v0.3.1
    Checking base64 v0.23.1
    Checking xml v1.4.0
    Checking is_terminal_polyfill v1.70.2
    Checking colorchoice v1.0.5
    Checking getopts v0.2.24
    Checking anstream v1.0.0
   Compiling webauthn-rs-core v0.5.5
    Checking serde_cbor_2 v0.13.0
    Checking x509-parser v0.16.0
   Compiling num_enum_derive v0.7.6
    Checking p256 v0.13.2
    Checking p384 v0.13.1
    Checking webauthn-rs-proto v0.5.5
   Compiling xmp_toolkit v1.12.1
    Checking headers-core v0.3.0
   Compiling bounded-static-derive v0.8.0
   Compiling curve25519-dalek-derive v0.1.1
    Checking quick-xml v0.42.0
    Checking clap_lex v1.1.1
    Checking bounded-static v0.8.0
    Checking ego-tree v0.6.3
    Checking clap_builder v4.6.7
    Checking imap-types v2.0.0-alpha.7
    Checking scraper v0.18.1
    Checking curve25519-dalek v4.1.3
    Checking headers v0.4.2
    Checking num_enum v0.7.6
    Checking xmltree v0.12.0
    Checking xml-rs v1.0.0
    Checking rustls-native-certs v0.8.4
    Checking miniz_oxide v0.8.9
    Checking fdeflate v0.3.7
   Compiling serde_with_macros v3.23.0
    Checking ed25519 v2.2.3
   Compiling clap_derive v4.6.7
    Checking hex-conservative v0.2.3
    Checking abnf-core v0.6.0
    Checking ordered-float v2.10.1
   Compiling derive-where v1.7.0
    Checking nom v8.0.0
    Checking color_quant v1.1.0
    Checking pxfm v0.1.30
    Checking zune-core v0.5.3
    Checking pulldown-cmark-escape v0.11.0
    Checking mail-builder v1.0.0
    Checking quick-error v2.0.1
    Checking byteorder-lite v0.1.0
   Compiling pem-rfc7468 v1.0.0
    Checking image-webp v0.2.4
    Checking calcard v0.3.14
   Compiling native-tls v0.2.18
    Checking moxcms v0.8.1
    Checking pulldown-cmark v0.13.4
    Checking zune-jpeg v0.5.15
    Checking gif v0.14.2
    Checking dav-server v0.11.0
   Compiling darling_core v0.20.11
    Checking clap v4.6.7
    Checking serde-value v0.7.0
    Checking imap-codec v2.0.0-alpha.9
    Checking serde_with v3.23.0
    Checking bitcoin_hashes v0.14.101
    Checking ed25519-dalek v2.2.0
    Checking png v0.18.1
    Checking rustls-platform-verifier v0.7.0
    Checking crossbeam-epoch v0.9.21
    Checking oauth2 v5.0.0
    Checking digest v0.11.3
    Checking itertools v0.10.5
    Checking password-hash v0.5.0
   Compiling phf_shared v0.14.0
    Checking blake2 v0.10.6
    Checking serde_plain v1.0.2
   Compiling zstd-sys v2.1.0+zstd.1.5.7
    Checking bytemuck v1.25.2
    Checking similar v3.2.0
    Checking base64 v0.13.1
    Checking image v0.25.10
   Compiling socks v0.3.4
    Checking calternal-imap v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-imap)
   Compiling phf_generator v0.14.0
   Compiling ureq-proto v0.6.4
    Checking argon2 v0.5.3
    Checking openidconnect v4.0.1
   Compiling webpki-root-certs v1.0.9
    Checking crossbeam-deque v0.8.8
    Checking reqwest v0.13.5
    Checking bip39 v3.0.0
   Compiling darling_macro v0.20.11
    Checking calternal-dav v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-dav)
    Checking readability-rust v0.1.0
   Compiling der v0.8.2
    Checking webauthn-rs v0.5.5
    Checking plist v1.10.1
    Checking calternal-location v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-location)
    Checking itertools v0.14.0
    Checking geo-types v0.7.20
    Checking block-padding v0.3.3
   Compiling async-stream-impl v0.3.6
    Checking cpubits v0.1.1
    Checking html2md-rs v0.12.2
    Checking async-stream v0.3.6
   Compiling ureq v3.4.2
    Checking iso6709parse v0.1.2
    Checking inout v0.1.4
    Checking calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-auth)
   Compiling darling v0.20.11
    Checking rayon-core v1.13.0
    Checking typeid v1.0.3
   Compiling scroll_derive v0.13.2
    Checking unicode-segmentation v1.13.3
   Compiling ort-sys v2.0.0-rc.13
   Compiling zstd-safe v7.3.0
    Checking rayon v1.12.0
   Compiling derive_builder_core v0.20.2
    Checking nom-exif v3.8.0
    Checking cipher v0.4.4
   Compiling phf_codegen v0.14.0
   Compiling string_cache_codegen v0.11.2
    Checking zip v5.1.1
   Compiling crunchy v0.2.4
    Checking ownedbytes v0.9.0
    Checking rawpointer v0.2.1
    Checking bit-vec v0.8.0
    Checking tantivy-common v0.11.0
    Checking matrixmultiply v0.3.11
    Checking bit-set v0.8.0
    Checking bitpacking v0.9.3
   Compiling tiny-keccak v2.0.2
    Checking spki v0.8.0
   Compiling web_atoms v0.3.0
   Compiling derive_builder_macro v0.20.2
    Checking erased-serde v0.4.10
    Checking polyval v0.7.3
    Checking aes v0.9.3
    Checking event-listener-strategy v0.5.4
    Checking castaway v0.2.4
    Checking num-complex v0.4.6
   Compiling monostate-impl v0.1.18
   Compiling sqlite-vec v0.1.9
    Checking keccak v0.2.2
    Checking utf8-ranges v1.0.5
    Checking sponge-cursor v0.1.0
    Checking static_assertions v1.1.0
    Checking fastrand v2.5.0
    Checking hashbrown v0.14.5
    Checking compact_str v0.9.1
    Checking macro_rules_attribute v0.2.3
    Checking shake v0.1.0
    Checking tantivy-fst v0.5.0
    Checking ndarray v0.17.2
    Checking monostate v0.1.18
    Checking ghash v0.6.0
    Checking zstd v0.13.3
    Checking derive_builder v0.20.2
   Compiling const-random-macro v0.1.16
    Checking pkcs8 v0.11.0
    Checking tantivy-bitpacker v0.10.0
    Checking fancy-regex v0.17.0
   Compiling prettyplease v0.3.0
    Checking esaxx-rs v0.1.10
    Checking string_cache v0.11.0
    Checking phf v0.14.0
    Checking rayon-cond v0.4.0
   Compiling scroll v0.13.0
    Checking spm_precompiled v0.1.4
   Compiling synstructure v0.12.6
    Checking signature v3.0.0
    Checking rand v0.10.3
    Checking ctr v0.10.1
    Checking arc-swap v1.9.2
    Checking http v0.2.12
    Checking concurrent-queue v2.5.0
    Checking module-lattice v0.2.3
    Checking dary_heap v0.3.9
    Checking unicode-normalization-alignments v0.1.12
    Checking murmurhash32 v0.3.1
    Checking pom v1.1.0
    Checking unicode-bidi v0.3.18
    Checking unicode_categories v0.1.1
    Checking daachorse v3.0.3
    Checking stringprep v0.1.5
    Checking tantivy-stacker v0.7.0
    Checking http-body v0.4.6
    Checking tokenizers v0.23.2
    Checking ml-dsa v0.1.1
    Checking aes-gcm v0.11.1
   Compiling der_derive v0.4.1
   Compiling utz_common v0.4.0+2026c
   Compiling bon-macros v3.10.1
    Checking ort v2.0.0-rc.13
    Checking tantivy-sstable v0.7.0
    Checking const-random v0.1.18
    Checking aes-keywrap v0.9.0
    Checking ecb v0.1.2
    Checking aes v0.8.4
    Checking cbc v0.1.2
    Checking futures v0.3.34
    Checking tendril v0.5.1
    Checking md-5 v0.10.6
    Checking calternal-tags v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-tags)
    Checking hmac-sha512 v1.1.12
    Checking hmac-sha256 v1.1.14
    Checking ordered-float v5.5.0
   Compiling typetag-impl v0.2.23
    Checking socket2 v0.5.10
    Checking downcast-rs v2.0.2
    Checking inventory v0.3.24
    Checking fastdivide v0.4.2
    Checking calternal-plugin-notes v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/notes)
    Checking rangemap v1.8.0
    Checking ct-codecs v1.1.7
    Checking event-listener v2.5.3
    Checking const-oid v0.6.2
    Checking ttf-parser v0.25.1
   Compiling sha2 v0.11.0
   Compiling convert_case v0.10.0
    Checking lopdf v0.42.0
    Checking der v0.4.5
    Checking async-channel v1.9.0
    Checking ed25519-compact v2.4.2
    Checking tantivy-columnar v0.7.0
    Checking typetag v0.2.23
    Checking hyper v0.14.32
    Checking tantivy-query-grammar v0.26.0
    Checking superboring v0.1.14
    Checking markup5ever v0.40.0
    Checking calternal-plugin-files v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/files)
    Checking tokio-native-tls v0.3.1
    Checking calternal-embed v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-embed)
    Checking dlv-list v0.5.2
    Checking bon v3.10.1
   Compiling utz_data_balanced v0.4.0+2026c
    Checking anyhow v1.0.104
    Checking type1-encoding-parser v0.1.1
    Checking adobe-cmap-parser v0.4.1
    Checking tempfile v3.27.0
    Checking pem v0.8.3
    Checking k256 v0.13.4
    Checking fs4 v0.13.1
    Checking lru v0.16.4
    Checking blake2b_simd v1.0.5
    Checking crossbeam-channel v0.5.17
    Checking rust-stemmers v1.2.0
    Checking tantivy-tokenizer-api v0.7.0
    Checking sketches-ddsketch v0.4.1
    Checking euclid v0.20.14
   Compiling pin-project-internal v1.1.13
   Compiling ref-cast-impl v1.0.27
   Compiling serde_repr v0.1.21
   Compiling serde_derive_internals v0.30.0
    Checking measure_time v0.9.0
    Checking serde_spanned v1.1.1
    Checking toml_datetime v1.1.1+spec-1.1.0
    Checking coarsetime v0.1.37
    Checking memmap2 v0.9.11
    Checking postscript v0.14.1
    Checking cff-parser v0.2.0
    Checking datasketches v0.2.0
    Checking oneshot v0.1.13
    Checking hmac-sha1-compact v1.1.7
    Checking levenshtein_automata v0.2.1
    Checking rustc-hash v2.1.3
    Checking census v0.4.2
    Checking lz4_flex v0.13.1
    Checking binstring v0.1.7
    Checking toml_writer v1.1.2+spec-1.1.0
    Checking calternal-plugin-calendar v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/calendar)
    Checking tantivy v0.26.2
    Checking jwt-simple v0.12.17
    Checking toml v1.1.6+spec-1.1.0
    Checking pdf-extract v0.12.1
   Compiling schemars_derive v1.2.2
    Checking bollard-stubs v1.53.1-rc.29.3.1
    Checking ref-cast v1.0.27
    Checking pin-project v1.1.13
    Checking sec1_decode v0.1.0
    Checking ordered-multimap v0.7.3
    Checking hyper-tls v0.5.0
    Checking html5ever v0.40.1
    Checking stop-token v0.7.0
   Compiling derive_more-impl v2.1.1
   Compiling rust-embed-utils v8.12.0
    Checking async-channel v2.5.0
    Checking dashmap v6.2.1
    Checking async-lock v3.4.2
    Checking hyperlocal v0.9.1
    Checking ece v2.4.2
    Checking cssparser v0.38.0
    Checking imap-proto v0.16.7
    Checking pem v3.0.6
    Checking smallstr v0.3.1
    Checking pin-utils v0.1.0
    Checking ucd-trie v0.1.7
    Checking maplit v1.0.2
    Checking arraydeque v0.5.1
    Checking self_cell v1.3.0
    Checking alloc-no-stdlib v2.0.4
    Checking yaml-rust2 v0.11.1
    Checking brotli-decompressor v5.0.3
    Checking ron v0.12.2
    Checking async-imap v0.11.3 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/mail/vendor/async-imap)
    Checking ammonia v4.2.0
    Checking json5 v1.3.1
    Checking yrs v0.28.0
    Checking web-push v0.11.0
    Checking calternal-search v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-search)
    Checking derive_more v2.1.1
    Checking bollard v0.21.1
   Compiling rust-embed-impl v8.12.0
    Checking rust-ini v0.21.3
    Checking schemars v1.2.2
    Checking serde-untagged v0.1.9
    Checking convert_case v0.6.0
   Compiling rmcp-macros v3.5.0
    Checking calternal-money v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-money)
    Checking sharded-slab v0.1.7
    Checking matchers v0.2.0
    Checking sse-stream v0.2.6
    Checking tracing-log v0.2.0
    Checking thread_local v1.1.10
   Compiling calternal-server v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-server)
    Checking nu-ansi-term v0.50.3
    Checking thumbhash v0.1.0
    Checking pathdiff v0.2.3
    Checking include_bytes_aligned v0.2.0
    Checking calternal-plugin-photos v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/photos)
    Checking calternal-plugin-ai v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/ai)
    Checking tracing-subscriber v0.3.23
    Checking utz v0.4.1+2026c
    Checking config v0.15.26
   Compiling webauthn-authenticator-rs v0.5.5
    Checking rmcp v3.5.0
    Checking calternal-plugin-money v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/money)
    Checking calternal-collab v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-collab)
    Checking rust-embed v8.12.0
    Checking calternal-plugin-notifications v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/notifications)
    Checking calternal-plugin-mail v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/mail)
    Checking calternal-plugin-analytics v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/analytics)
    Checking calternal-plugin-video v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/video)
   Compiling num-derive v0.4.2
    Checking serde_bytes v0.11.19
    Checking bitflags v1.3.2
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 45s

cargo test -p calternal-server --quiet -- --test-threads=1 (exit 0):


running 121 tests
....................................................................................... 87/121
......................ii......i...
test result: ok. 118 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 26.34s

cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings (exit 0):

   Compiling syn v2.0.119
   Compiling displaydoc v0.2.7
    Checking log v0.4.34
    Checking smallvec v1.16.1
   Compiling generic-array v0.14.9
    Checking stable_deref_trait v1.2.1
   Compiling crossbeam-utils v0.8.23
    Checking yoke v0.8.3
   Compiling num-traits v0.2.19
    Checking mio v1.2.3
    Checking zerovec v0.11.8
    Checking futures-sink v0.3.34
   Compiling serde_json v1.0.151
   Compiling tinystr v0.8.4
    Checking tokio v1.53.1
   Compiling zerotrie v0.2.5
   Compiling icu_locale_core v2.3.0
    Checking futures-channel v0.3.34
   Compiling getrandom v0.4.3
   Compiling tracing-attributes v0.1.31
   Compiling icu_provider v2.3.1
   Compiling icu_collections v2.3.0
    Checking potential_utf v0.1.6
    Checking parking_lot_core v0.9.12
   Compiling typenum v1.20.1
    Checking parking_lot v0.12.5
    Checking hybrid-array v0.4.15
    Checking slab v0.4.12
   Compiling icu_properties v2.3.0
    Checking futures-util v0.3.34
   Compiling icu_normalizer v2.3.0
    Checking tracing-core v0.1.36
    Checking tracing v0.1.44
   Compiling idna_adapter v1.2.2
   Compiling crypto-common v0.1.6
   Compiling block-buffer v0.10.4
   Compiling digest v0.10.7
   Compiling idna v1.1.0
    Checking crypto-common v0.2.2
   Compiling crossbeam-queue v0.3.14
   Compiling sha2 v0.10.9
   Compiling url v2.5.8
    Checking bitflags v2.13.2
   Compiling rand_core v0.6.4
   Compiling sqlx-core v0.9.0
   Compiling rand v0.8.8
    Checking chrono v0.4.45
   Compiling atoi v2.0.0
    Checking futures-executor v0.3.34
    Checking inout v0.2.2
   Compiling phf_shared v0.11.3
   Compiling phf_generator v0.11.3
    Checking block-buffer v0.12.1
    Checking tokio-stream v0.1.19
    Checking futures-intrusive v0.5.0
    Checking either v1.18.0
   Compiling rustix v1.1.5
    Checking string_cache v0.11.0
    Checking flume v0.12.0
    Checking cipher v0.5.2
   Compiling phf_macros v0.11.3
    Checking universal-hash v0.6.1
    Checking concurrent-queue v2.5.0
    Checking linux-raw-sys v0.12.1
    Checking sync_wrapper v1.0.2
    Checking hyper v1.11.1
    Checking sqlx-sqlite v0.9.0
    Checking phf v0.11.3
    Checking poly1305 v0.9.1
    Checking web_atoms v0.3.0
    Checking chacha20 v0.10.2
    Checking aead v0.6.1
   Compiling utoipa-gen v6.0.1
   Compiling rustls v0.23.45
    Checking rustls-webpki v0.103.15
    Checking async-channel v1.9.0
    Checking chacha20poly1305 v0.11.0
    Checking cron v0.17.0
    Checking axum-core v0.5.6
    Checking markup5ever v0.40.0
   Compiling sqlx-macros-core v0.9.0
    Checking inotify v0.11.5
    Checking chrono-tz v0.10.4
    Checking hyper-util v0.1.20
    Checking tower v0.5.3
    Checking notify-types v2.1.0
   Compiling sqlx-macros v0.9.0
    Checking utoipa v6.0.0
    Checking uuid v1.26.1
   Compiling pin-project-internal v1.1.13
   Compiling thiserror-impl v1.0.69
    Checking subtle v2.6.1
    Checking calternal-fs v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-fs)
    Checking axum v0.8.9
    Checking sqlx v0.9.0
    Checking calternal-db v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-db)
    Checking calternal-api v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-api)
    Checking thiserror v1.0.69
    Checking pin-project v1.1.13
    Checking async-channel v2.5.0
    Checking notify v8.2.0
    Checking html5ever v0.40.1
    Checking cssparser v0.38.0
    Checking stop-token v0.7.0
    Checking futures v0.3.34
   Compiling hashify v0.2.9
    Checking ammonia v4.2.0
    Checking async-imap v0.11.3 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/mail/vendor/async-imap)
    Checking tokio-rustls v0.26.6
    Checking calternal-plugin v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-plugin)
    Checking fastrand v2.5.0
    Checking mail-parser v0.11.9
    Checking tempfile v3.27.0
    Checking calternal-plugin-mail v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/mail)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 59.99s

cargo test -p calternal-plugin-mail --quiet -- --test-threads=1 (exit 0):


running 40 tests
................................i..i....
test result: ok. 38 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 3.87s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Final review head: `ad7e25c6392e75cd8360c82b9e716c8011b7fca1`. Full final gate output follows verbatim; dependency build lines are retained. # Final gate transcript Gated code head: af6616f4dc1fff6ed3c13a6bdf17dd018dfee0a0. All commands exited 0. `cargo fmt --check` (exit 0): stdout and stderr were empty. `cargo clippy -p calternal-server --all-targets -- -D warnings` (exit 0): ```text Compiling unicode-ident v1.0.26 Checking cfg-if v1.0.5 Checking libc v0.2.189 Compiling proc-macro2 v1.0.107 Checking serde_core v1.0.229 Compiling quote v1.0.47 Checking memchr v2.8.3 Compiling jobserver v0.1.35 Compiling syn v3.0.6 Compiling syn v2.0.119 Compiling cc v1.4.7 Checking typenum v1.20.1 Checking zeroize v1.9.0 Checking log v0.4.34 Checking itoa v1.0.18 Checking pin-project-lite v0.2.17 Checking once_cell v1.21.4 Checking libm v0.2.16 Checking smallvec v1.16.1 Checking subtle v2.6.1 Compiling serde_derive v1.0.229 Compiling synstructure v0.14.0 Checking num-traits v0.2.19 Checking generic-array v0.14.9 Compiling zerofrom-derive v0.1.8 Compiling yoke-derive v0.8.3 Checking serde v1.0.229 Compiling displaydoc v0.2.7 Checking bytes v1.12.1 Checking const-oid v0.9.6 Checking futures-core v0.3.34 Checking crypto-common v0.1.6 Compiling zerovec-derive v0.11.6 Checking scopeguard v1.2.0 Checking stable_deref_trait v1.2.1 Checking block-buffer v0.10.4 Compiling tracing-attributes v0.1.31 Checking digest v0.10.7 Checking rand_core v0.10.1 Checking futures-sink v0.3.34 Checking lock_api v0.4.14 Checking getrandom v0.4.3 Checking tracing-core v0.1.36 Checking mio v1.2.3 Checking bitflags v2.13.2 Checking errno v0.3.14 Compiling tokio-macros v2.7.2 Checking socket2 v0.6.5 Checking signal-hook-registry v1.4.8 Checking tracing v0.1.44 Compiling thiserror-impl v2.0.21 Checking cmov v0.5.4 Checking tokio v1.53.1 Checking slab v0.4.12 Checking equivalent v1.0.2 Checking ctutils v0.4.2 Checking futures-channel v0.3.34 Checking zerofrom v0.1.8 Checking hybrid-array v0.4.15 Compiling futures-macro v0.3.34 Checking futures-io v0.3.34 Checking futures-task v0.3.34 Checking yoke v0.8.3 Checking zmij v1.0.23 Checking serde_json v1.0.151 Checking getrandom v0.2.17 Checking futures-util v0.3.34 Checking zerovec v0.11.8 Compiling zerocopy-derive v0.8.58 Checking percent-encoding v2.3.2 Checking cpufeatures v0.2.17 Checking thiserror v2.0.21 Checking crypto-common v0.2.2 Checking hashbrown v0.17.1 Checking zerocopy v0.8.58 Checking indexmap v2.14.2 Compiling siphasher v1.0.3 Checking tinystr v0.8.4 Checking litemap v0.8.3 Checking cpufeatures v0.3.1 Checking writeable v0.6.4 Checking base64 v0.22.1 Checking icu_locale_core v2.3.0 Checking potential_utf v0.1.6 Checking zerotrie v0.2.5 Checking utf8_iter v1.0.4 Checking icu_collections v2.3.0 Checking http v1.5.0 Checking icu_provider v2.3.1 Checking block-buffer v0.12.1 Checking icu_normalizer_data v2.3.0 Checking icu_properties_data v2.3.0 Checking iana-time-zone v0.1.65 Checking icu_normalizer v2.3.0 Checking chrono v0.4.45 Checking icu_properties v2.3.0 Compiling ppv-lite86 v0.2.21 Checking form_urlencoded v1.2.2 Compiling rand_core v0.6.4 Checking crossbeam-utils v0.8.23 Compiling rand_chacha v0.3.1 Checking idna_adapter v1.2.2 Checking idna v1.1.0 Compiling rand v0.8.8 Checking parking_lot_core v0.9.12 Checking tokio-util v0.7.19 Checking fnv v1.0.7 Checking url v2.5.8 Checking spin v0.9.9 Checking http-body v1.1.0 Checking sha2 v0.10.9 Checking minimal-lexical v0.2.1 Checking tower-service v0.3.3 Checking httparse v1.10.1 Checking getrandom v0.3.4 Checking nom v7.1.3 Checking parking_lot v0.12.5 Checking inout v0.2.2 Checking httpdate v1.0.3 Compiling phf_shared v0.11.3 Checking try-lock v0.2.5 Checking cipher v0.5.2 Checking want v0.3.1 Compiling phf_generator v0.11.3 Checking base64ct v1.8.3 Checking either v1.18.0 Checking arrayvec v0.7.8 Compiling strsim v0.11.1 Checking http-body-util v0.1.5 Compiling openssl-macros v0.1.1 Compiling cmake v0.1.58 Checking atomic-waker v1.1.2 Checking tinyvec v1.13.3 Checking regex-syntax v0.8.11 Checking ryu v1.0.23 Compiling aws-lc-sys v0.45.0 Checking unicode-normalization v0.1.25 Checking h2 v0.4.19 Checking pem-rfc7468 v0.7.0 Compiling openssl-src v300.6.1+3.6.3 Compiling openssl-sys v0.9.117 Checking der v0.7.10 Checking rand_core v0.9.5 Checking num-integer v0.1.47 Checking ipnet v2.12.2 Checking allocator-api2 v0.2.21 Checking hyper v1.11.1 Checking constant_time_eq v0.4.2 Checking byteorder v1.5.0 Checking foldhash v0.2.0 Checking parking v2.2.1 Checking hashbrown v0.16.1 Checking event-listener v5.4.2 Checking hyper-util v0.1.20 Checking rand_chacha v0.9.0 Checking spki v0.7.3 Checking universal-hash v0.6.1 Checking uuid v1.26.1 Checking sync_wrapper v1.0.2 Compiling thiserror-impl v1.0.69 Compiling ring v0.17.14 Checking aho-corasick v1.1.5 Compiling num-conv v0.2.2 Checking new_debug_unreachable v1.0.6 Checking tower-layer v0.3.3 Compiling time-core v0.1.9 Checking thiserror v1.0.69 Checking regex-automata v0.4.18 Compiling time-macros v0.2.32 Checking rand v0.9.5 Checking pkcs8 v0.10.2 Compiling phf_macros v0.11.3 Checking rustls-pki-types v1.15.1 Compiling blake3 v1.8.7 Checking deranged v0.5.8 Checking powerfmt v0.2.0 Checking data-encoding v2.11.1 Checking time v0.3.55 Checking phf v0.11.3 Checking tower v0.5.3 Checking phf_shared v0.12.1 Checking futures-executor v0.3.34 Compiling libsqlite3-sys v0.37.0 Compiling crc-catalog v2.5.0 Checking untrusted v0.9.0 Compiling crc v3.4.0 Checking phf v0.12.1 Compiling tokio-stream v0.1.19 Compiling crossbeam-queue v0.3.14 Compiling futures-intrusive v0.5.0 Compiling hashlink v0.11.1 Checking serde_urlencoded v0.7.1 Checking chacha20 v0.10.2 Checking aead v0.6.1 Checking lazy_static v1.5.0 Checking sha1 v0.10.7 Checking mime v0.3.17 Checking linux-raw-sys v0.12.1 Checking precomputed-hash v0.1.1 Compiling siphasher v0.3.11 Compiling sqlx-core v0.9.0 Checking rustix v1.1.5 Compiling phf_shared v0.10.0 Compiling flume v0.12.0 Compiling atoi v2.0.0 Compiling aws-lc-rs v1.18.1 Compiling rustls v0.23.45 Checking chrono-tz v0.10.4 Checking rustls-webpki v0.103.15 Compiling multiversion-macros v0.9.0 Checking hmac v0.12.1 Checking calternal-path v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-path) Checking unicode-properties v0.1.4 Checking multiversion v0.9.0 Compiling sqlx-sqlite v0.9.0 Compiling syn v1.0.109 Compiling phf_generator v0.10.0 Checking regex v1.13.1 Compiling darling_core v0.24.1 Checking signature v2.2.0 Compiling async-trait v0.1.92 Checking serde_path_to_error v0.1.20 Checking simdutf8 v0.1.5 Compiling hex v0.4.3 Checking foreign-types-shared v0.1.1 Checking core_detect v1.0.0 Compiling unicase v2.9.0 Compiling sqlx-macros-core v0.9.0 Checking encoding_rs v0.8.41 Compiling mime_guess v2.0.5 Compiling darling_macro v0.24.1 Checking foreign-types v0.3.2 Compiling openssl v0.10.81 Compiling phf_codegen v0.10.0 Checking hkdf v0.12.4 Checking tungstenite v0.29.0 Checking ff v0.13.1 Checking same-file v1.0.6 Checking base16ct v0.2.0 Checking walkdir v2.5.0 Checking sec1 v0.7.3 Checking tokio-tungstenite v0.29.0 Checking group v0.13.0 Compiling utoipa-gen v6.0.1 Compiling sqlx-macros v0.9.0 Checking unicode-joining-type v1.0.0 Compiling darling v0.24.1 Checking tokio-rustls v0.26.6 Checking axum-core v0.5.6 Checking webpki-roots v1.0.9 Checking poly1305 v0.9.1 Checking crypto-bigint v0.5.5 Compiling axum-macros v0.5.1 Checking dtoa v1.0.11 Checking matchit v0.8.4 Checking winnow v0.7.15 Checking unicode-casefold v0.2.0 Checking axum v0.8.9 Checking utoipa v6.0.0 Checking calternal-fs v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-fs) Checking elliptic-curve v0.13.8 Checking cron v0.17.0 Checking dtoa-short v0.3.5 Checking chacha20poly1305 v0.11.0 Checking sqlx v0.9.0 Checking ahash v0.8.12 Checking inotify-sys v0.1.8 Compiling synstructure v0.13.2 Checking unsafe-libyaml v0.2.11 Checking simd-adler32 v0.3.10 Checking serde_yaml v0.9.34+deprecated Compiling asn1-rs-derive v0.5.1 Checking inotify v0.11.5 Checking calternal-db v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-db) Checking crc32fast v1.5.2 Compiling linkme-impl v0.3.37 Checking hyper-rustls v0.27.10 Checking rfc6979 v0.4.0 Checking tower-http v0.6.11 Compiling string_cache_codegen v0.5.4 Checking rusticata-macros v4.1.0 Checking notify-types v2.1.0 Compiling asn1-rs-impl v0.2.0 Checking base64 v0.21.7 Compiling winnow v1.0.4 Checking mac v0.1.1 Checking adler2 v2.0.1 Checking openssl-probe v0.2.1 Checking futf v0.1.5 Checking asn1-rs v0.6.2 Checking notify v8.2.0 Compiling markup5ever v0.11.0 Checking linkme v0.3.37 Checking ecdsa v0.16.9 Compiling toml_parser v1.1.3+spec-1.1.0 Checking calternal-notes-core v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-notes-core) Checking phf v0.10.1 Checking calternal-api v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-api) Checking num-iter v0.1.46 Checking dyn-clone v1.0.20 Checking utf-8 v0.7.6 Checking base64urlsafedata v0.5.5 Checking calternal-plugin v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-plugin) Checking tendril v0.4.3 Compiling toml_edit v0.25.15+spec-1.1.0 Checking num-bigint-dig v0.8.6 Checking miniz_oxide v0.9.1 Checking primeorder v0.13.6 Compiling selectors v0.25.0 Compiling html5ever v0.26.0 Checking string_cache v0.8.9 Checking pkcs1 v0.7.5 Checking num-bigint v0.4.8 Compiling hashify v0.2.9 Compiling cssparser-macros v0.6.1 Checking const-oid v0.10.2 Checking utf8parse v0.2.2 Compiling webauthn-attestation-ca v0.5.5 Checking cssparser v0.31.2 Checking der-parser v9.0.0 Checking anstyle-parse v1.0.0 Checking mail-parser v0.11.9 Checking rsa v0.9.10 Checking flate2 v1.1.10 Compiling proc-macro-crate v3.5.0 Checking oid-registry v0.7.1 Checking reqwest v0.12.28 Checking fxhash v0.2.1 Checking half v2.7.1 Checking servo_arc v0.3.0 Compiling derive_more v0.99.20 Checking weezl v0.1.12 Checking anstyle v1.0.14 Checking anstyle-query v1.1.5 Checking unicode-width v0.2.2 Checking htmlescape v0.3.1 Checking base64 v0.23.1 Checking xml v1.4.0 Checking is_terminal_polyfill v1.70.2 Checking colorchoice v1.0.5 Checking getopts v0.2.24 Checking anstream v1.0.0 Compiling webauthn-rs-core v0.5.5 Checking serde_cbor_2 v0.13.0 Checking x509-parser v0.16.0 Compiling num_enum_derive v0.7.6 Checking p256 v0.13.2 Checking p384 v0.13.1 Checking webauthn-rs-proto v0.5.5 Compiling xmp_toolkit v1.12.1 Checking headers-core v0.3.0 Compiling bounded-static-derive v0.8.0 Compiling curve25519-dalek-derive v0.1.1 Checking quick-xml v0.42.0 Checking clap_lex v1.1.1 Checking bounded-static v0.8.0 Checking ego-tree v0.6.3 Checking clap_builder v4.6.7 Checking imap-types v2.0.0-alpha.7 Checking scraper v0.18.1 Checking curve25519-dalek v4.1.3 Checking headers v0.4.2 Checking num_enum v0.7.6 Checking xmltree v0.12.0 Checking xml-rs v1.0.0 Checking rustls-native-certs v0.8.4 Checking miniz_oxide v0.8.9 Checking fdeflate v0.3.7 Compiling serde_with_macros v3.23.0 Checking ed25519 v2.2.3 Compiling clap_derive v4.6.7 Checking hex-conservative v0.2.3 Checking abnf-core v0.6.0 Checking ordered-float v2.10.1 Compiling derive-where v1.7.0 Checking nom v8.0.0 Checking color_quant v1.1.0 Checking pxfm v0.1.30 Checking zune-core v0.5.3 Checking pulldown-cmark-escape v0.11.0 Checking mail-builder v1.0.0 Checking quick-error v2.0.1 Checking byteorder-lite v0.1.0 Compiling pem-rfc7468 v1.0.0 Checking image-webp v0.2.4 Checking calcard v0.3.14 Compiling native-tls v0.2.18 Checking moxcms v0.8.1 Checking pulldown-cmark v0.13.4 Checking zune-jpeg v0.5.15 Checking gif v0.14.2 Checking dav-server v0.11.0 Compiling darling_core v0.20.11 Checking clap v4.6.7 Checking serde-value v0.7.0 Checking imap-codec v2.0.0-alpha.9 Checking serde_with v3.23.0 Checking bitcoin_hashes v0.14.101 Checking ed25519-dalek v2.2.0 Checking png v0.18.1 Checking rustls-platform-verifier v0.7.0 Checking crossbeam-epoch v0.9.21 Checking oauth2 v5.0.0 Checking digest v0.11.3 Checking itertools v0.10.5 Checking password-hash v0.5.0 Compiling phf_shared v0.14.0 Checking blake2 v0.10.6 Checking serde_plain v1.0.2 Compiling zstd-sys v2.1.0+zstd.1.5.7 Checking bytemuck v1.25.2 Checking similar v3.2.0 Checking base64 v0.13.1 Checking image v0.25.10 Compiling socks v0.3.4 Checking calternal-imap v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-imap) Compiling phf_generator v0.14.0 Compiling ureq-proto v0.6.4 Checking argon2 v0.5.3 Checking openidconnect v4.0.1 Compiling webpki-root-certs v1.0.9 Checking crossbeam-deque v0.8.8 Checking reqwest v0.13.5 Checking bip39 v3.0.0 Compiling darling_macro v0.20.11 Checking calternal-dav v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-dav) Checking readability-rust v0.1.0 Compiling der v0.8.2 Checking webauthn-rs v0.5.5 Checking plist v1.10.1 Checking calternal-location v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-location) Checking itertools v0.14.0 Checking geo-types v0.7.20 Checking block-padding v0.3.3 Compiling async-stream-impl v0.3.6 Checking cpubits v0.1.1 Checking html2md-rs v0.12.2 Checking async-stream v0.3.6 Compiling ureq v3.4.2 Checking iso6709parse v0.1.2 Checking inout v0.1.4 Checking calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-auth) Compiling darling v0.20.11 Checking rayon-core v1.13.0 Checking typeid v1.0.3 Compiling scroll_derive v0.13.2 Checking unicode-segmentation v1.13.3 Compiling ort-sys v2.0.0-rc.13 Compiling zstd-safe v7.3.0 Checking rayon v1.12.0 Compiling derive_builder_core v0.20.2 Checking nom-exif v3.8.0 Checking cipher v0.4.4 Compiling phf_codegen v0.14.0 Compiling string_cache_codegen v0.11.2 Checking zip v5.1.1 Compiling crunchy v0.2.4 Checking ownedbytes v0.9.0 Checking rawpointer v0.2.1 Checking bit-vec v0.8.0 Checking tantivy-common v0.11.0 Checking matrixmultiply v0.3.11 Checking bit-set v0.8.0 Checking bitpacking v0.9.3 Compiling tiny-keccak v2.0.2 Checking spki v0.8.0 Compiling web_atoms v0.3.0 Compiling derive_builder_macro v0.20.2 Checking erased-serde v0.4.10 Checking polyval v0.7.3 Checking aes v0.9.3 Checking event-listener-strategy v0.5.4 Checking castaway v0.2.4 Checking num-complex v0.4.6 Compiling monostate-impl v0.1.18 Compiling sqlite-vec v0.1.9 Checking keccak v0.2.2 Checking utf8-ranges v1.0.5 Checking sponge-cursor v0.1.0 Checking static_assertions v1.1.0 Checking fastrand v2.5.0 Checking hashbrown v0.14.5 Checking compact_str v0.9.1 Checking macro_rules_attribute v0.2.3 Checking shake v0.1.0 Checking tantivy-fst v0.5.0 Checking ndarray v0.17.2 Checking monostate v0.1.18 Checking ghash v0.6.0 Checking zstd v0.13.3 Checking derive_builder v0.20.2 Compiling const-random-macro v0.1.16 Checking pkcs8 v0.11.0 Checking tantivy-bitpacker v0.10.0 Checking fancy-regex v0.17.0 Compiling prettyplease v0.3.0 Checking esaxx-rs v0.1.10 Checking string_cache v0.11.0 Checking phf v0.14.0 Checking rayon-cond v0.4.0 Compiling scroll v0.13.0 Checking spm_precompiled v0.1.4 Compiling synstructure v0.12.6 Checking signature v3.0.0 Checking rand v0.10.3 Checking ctr v0.10.1 Checking arc-swap v1.9.2 Checking http v0.2.12 Checking concurrent-queue v2.5.0 Checking module-lattice v0.2.3 Checking dary_heap v0.3.9 Checking unicode-normalization-alignments v0.1.12 Checking murmurhash32 v0.3.1 Checking pom v1.1.0 Checking unicode-bidi v0.3.18 Checking unicode_categories v0.1.1 Checking daachorse v3.0.3 Checking stringprep v0.1.5 Checking tantivy-stacker v0.7.0 Checking http-body v0.4.6 Checking tokenizers v0.23.2 Checking ml-dsa v0.1.1 Checking aes-gcm v0.11.1 Compiling der_derive v0.4.1 Compiling utz_common v0.4.0+2026c Compiling bon-macros v3.10.1 Checking ort v2.0.0-rc.13 Checking tantivy-sstable v0.7.0 Checking const-random v0.1.18 Checking aes-keywrap v0.9.0 Checking ecb v0.1.2 Checking aes v0.8.4 Checking cbc v0.1.2 Checking futures v0.3.34 Checking tendril v0.5.1 Checking md-5 v0.10.6 Checking calternal-tags v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-tags) Checking hmac-sha512 v1.1.12 Checking hmac-sha256 v1.1.14 Checking ordered-float v5.5.0 Compiling typetag-impl v0.2.23 Checking socket2 v0.5.10 Checking downcast-rs v2.0.2 Checking inventory v0.3.24 Checking fastdivide v0.4.2 Checking calternal-plugin-notes v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/notes) Checking rangemap v1.8.0 Checking ct-codecs v1.1.7 Checking event-listener v2.5.3 Checking const-oid v0.6.2 Checking ttf-parser v0.25.1 Compiling sha2 v0.11.0 Compiling convert_case v0.10.0 Checking lopdf v0.42.0 Checking der v0.4.5 Checking async-channel v1.9.0 Checking ed25519-compact v2.4.2 Checking tantivy-columnar v0.7.0 Checking typetag v0.2.23 Checking hyper v0.14.32 Checking tantivy-query-grammar v0.26.0 Checking superboring v0.1.14 Checking markup5ever v0.40.0 Checking calternal-plugin-files v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/files) Checking tokio-native-tls v0.3.1 Checking calternal-embed v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-embed) Checking dlv-list v0.5.2 Checking bon v3.10.1 Compiling utz_data_balanced v0.4.0+2026c Checking anyhow v1.0.104 Checking type1-encoding-parser v0.1.1 Checking adobe-cmap-parser v0.4.1 Checking tempfile v3.27.0 Checking pem v0.8.3 Checking k256 v0.13.4 Checking fs4 v0.13.1 Checking lru v0.16.4 Checking blake2b_simd v1.0.5 Checking crossbeam-channel v0.5.17 Checking rust-stemmers v1.2.0 Checking tantivy-tokenizer-api v0.7.0 Checking sketches-ddsketch v0.4.1 Checking euclid v0.20.14 Compiling pin-project-internal v1.1.13 Compiling ref-cast-impl v1.0.27 Compiling serde_repr v0.1.21 Compiling serde_derive_internals v0.30.0 Checking measure_time v0.9.0 Checking serde_spanned v1.1.1 Checking toml_datetime v1.1.1+spec-1.1.0 Checking coarsetime v0.1.37 Checking memmap2 v0.9.11 Checking postscript v0.14.1 Checking cff-parser v0.2.0 Checking datasketches v0.2.0 Checking oneshot v0.1.13 Checking hmac-sha1-compact v1.1.7 Checking levenshtein_automata v0.2.1 Checking rustc-hash v2.1.3 Checking census v0.4.2 Checking lz4_flex v0.13.1 Checking binstring v0.1.7 Checking toml_writer v1.1.2+spec-1.1.0 Checking calternal-plugin-calendar v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/calendar) Checking tantivy v0.26.2 Checking jwt-simple v0.12.17 Checking toml v1.1.6+spec-1.1.0 Checking pdf-extract v0.12.1 Compiling schemars_derive v1.2.2 Checking bollard-stubs v1.53.1-rc.29.3.1 Checking ref-cast v1.0.27 Checking pin-project v1.1.13 Checking sec1_decode v0.1.0 Checking ordered-multimap v0.7.3 Checking hyper-tls v0.5.0 Checking html5ever v0.40.1 Checking stop-token v0.7.0 Compiling derive_more-impl v2.1.1 Compiling rust-embed-utils v8.12.0 Checking async-channel v2.5.0 Checking dashmap v6.2.1 Checking async-lock v3.4.2 Checking hyperlocal v0.9.1 Checking ece v2.4.2 Checking cssparser v0.38.0 Checking imap-proto v0.16.7 Checking pem v3.0.6 Checking smallstr v0.3.1 Checking pin-utils v0.1.0 Checking ucd-trie v0.1.7 Checking maplit v1.0.2 Checking arraydeque v0.5.1 Checking self_cell v1.3.0 Checking alloc-no-stdlib v2.0.4 Checking yaml-rust2 v0.11.1 Checking brotli-decompressor v5.0.3 Checking ron v0.12.2 Checking async-imap v0.11.3 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/mail/vendor/async-imap) Checking ammonia v4.2.0 Checking json5 v1.3.1 Checking yrs v0.28.0 Checking web-push v0.11.0 Checking calternal-search v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-search) Checking derive_more v2.1.1 Checking bollard v0.21.1 Compiling rust-embed-impl v8.12.0 Checking rust-ini v0.21.3 Checking schemars v1.2.2 Checking serde-untagged v0.1.9 Checking convert_case v0.6.0 Compiling rmcp-macros v3.5.0 Checking calternal-money v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-money) Checking sharded-slab v0.1.7 Checking matchers v0.2.0 Checking sse-stream v0.2.6 Checking tracing-log v0.2.0 Checking thread_local v1.1.10 Compiling calternal-server v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-server) Checking nu-ansi-term v0.50.3 Checking thumbhash v0.1.0 Checking pathdiff v0.2.3 Checking include_bytes_aligned v0.2.0 Checking calternal-plugin-photos v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/photos) Checking calternal-plugin-ai v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/ai) Checking tracing-subscriber v0.3.23 Checking utz v0.4.1+2026c Checking config v0.15.26 Compiling webauthn-authenticator-rs v0.5.5 Checking rmcp v3.5.0 Checking calternal-plugin-money v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/money) Checking calternal-collab v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-collab) Checking rust-embed v8.12.0 Checking calternal-plugin-notifications v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/notifications) Checking calternal-plugin-mail v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/mail) Checking calternal-plugin-analytics v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/analytics) Checking calternal-plugin-video v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/video) Compiling num-derive v0.4.2 Checking serde_bytes v0.11.19 Checking bitflags v1.3.2 Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 45s ``` `cargo test -p calternal-server --quiet -- --test-threads=1` (exit 0): ```text running 121 tests ....................................................................................... 87/121 ......................ii......i... test result: ok. 118 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 26.34s ``` `cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings` (exit 0): ```text Compiling syn v2.0.119 Compiling displaydoc v0.2.7 Checking log v0.4.34 Checking smallvec v1.16.1 Compiling generic-array v0.14.9 Checking stable_deref_trait v1.2.1 Compiling crossbeam-utils v0.8.23 Checking yoke v0.8.3 Compiling num-traits v0.2.19 Checking mio v1.2.3 Checking zerovec v0.11.8 Checking futures-sink v0.3.34 Compiling serde_json v1.0.151 Compiling tinystr v0.8.4 Checking tokio v1.53.1 Compiling zerotrie v0.2.5 Compiling icu_locale_core v2.3.0 Checking futures-channel v0.3.34 Compiling getrandom v0.4.3 Compiling tracing-attributes v0.1.31 Compiling icu_provider v2.3.1 Compiling icu_collections v2.3.0 Checking potential_utf v0.1.6 Checking parking_lot_core v0.9.12 Compiling typenum v1.20.1 Checking parking_lot v0.12.5 Checking hybrid-array v0.4.15 Checking slab v0.4.12 Compiling icu_properties v2.3.0 Checking futures-util v0.3.34 Compiling icu_normalizer v2.3.0 Checking tracing-core v0.1.36 Checking tracing v0.1.44 Compiling idna_adapter v1.2.2 Compiling crypto-common v0.1.6 Compiling block-buffer v0.10.4 Compiling digest v0.10.7 Compiling idna v1.1.0 Checking crypto-common v0.2.2 Compiling crossbeam-queue v0.3.14 Compiling sha2 v0.10.9 Compiling url v2.5.8 Checking bitflags v2.13.2 Compiling rand_core v0.6.4 Compiling sqlx-core v0.9.0 Compiling rand v0.8.8 Checking chrono v0.4.45 Compiling atoi v2.0.0 Checking futures-executor v0.3.34 Checking inout v0.2.2 Compiling phf_shared v0.11.3 Compiling phf_generator v0.11.3 Checking block-buffer v0.12.1 Checking tokio-stream v0.1.19 Checking futures-intrusive v0.5.0 Checking either v1.18.0 Compiling rustix v1.1.5 Checking string_cache v0.11.0 Checking flume v0.12.0 Checking cipher v0.5.2 Compiling phf_macros v0.11.3 Checking universal-hash v0.6.1 Checking concurrent-queue v2.5.0 Checking linux-raw-sys v0.12.1 Checking sync_wrapper v1.0.2 Checking hyper v1.11.1 Checking sqlx-sqlite v0.9.0 Checking phf v0.11.3 Checking poly1305 v0.9.1 Checking web_atoms v0.3.0 Checking chacha20 v0.10.2 Checking aead v0.6.1 Compiling utoipa-gen v6.0.1 Compiling rustls v0.23.45 Checking rustls-webpki v0.103.15 Checking async-channel v1.9.0 Checking chacha20poly1305 v0.11.0 Checking cron v0.17.0 Checking axum-core v0.5.6 Checking markup5ever v0.40.0 Compiling sqlx-macros-core v0.9.0 Checking inotify v0.11.5 Checking chrono-tz v0.10.4 Checking hyper-util v0.1.20 Checking tower v0.5.3 Checking notify-types v2.1.0 Compiling sqlx-macros v0.9.0 Checking utoipa v6.0.0 Checking uuid v1.26.1 Compiling pin-project-internal v1.1.13 Compiling thiserror-impl v1.0.69 Checking subtle v2.6.1 Checking calternal-fs v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-fs) Checking axum v0.8.9 Checking sqlx v0.9.0 Checking calternal-db v0.1.0 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-db) Checking calternal-api v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-api) Checking thiserror v1.0.69 Checking pin-project v1.1.13 Checking async-channel v2.5.0 Checking notify v8.2.0 Checking html5ever v0.40.1 Checking cssparser v0.38.0 Checking stop-token v0.7.0 Checking futures v0.3.34 Compiling hashify v0.2.9 Checking ammonia v4.2.0 Checking async-imap v0.11.3 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/mail/vendor/async-imap) Checking tokio-rustls v0.26.6 Checking calternal-plugin v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/calternal-plugin) Checking fastrand v2.5.0 Checking mail-parser v0.11.9 Checking tempfile v3.27.0 Checking calternal-plugin-mail v0.0.1 (/home/kayg/Developer/calternal-wt/integrations-review/crates/plugins/mail) Finished `dev` profile [unoptimized + debuginfo] target(s) in 59.99s ``` `cargo test -p calternal-plugin-mail --quiet -- --test-threads=1` (exit 0): ```text running 40 tests ................................i..i.... test result: ok. 38 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 3.87s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ```
Author
Owner

Independent #407 review finished. Verdict: NO-GO.

Final review head: ad7e25c6392e75cd8360c82b9e716c8011b7fca1 on job/integrations-review. Assessed implementation: ffb73a099ad521cca3d854507a2ad02f198c27e8. Gated code head after the required origin/dev merge: af6616f4dc1fff6ed3c13a6bdf17dd018dfee0a0. Test-only patch commit: 8274c17e8, posted above. No production fixes, push, deploy or issue close. Worktree is clean.

Connected Accounts migration review — #407

Review target: ffb73a099a.
Verdict: NO-GO.

Review branch: job/integrations-review. No production fixes are authored. Final gates run after the required merge of origin/dev.
Fetched origin/dev: 687ff70313.

Findings in progress

  • Account move: one SQLx transaction holds inserts, credential clears, Calendar links and completion marker (integrations.rs:163–465). Each schema migration has a separate transaction (migrations.rs:189–208). This is not one transaction across the full schema upgrade.
  • Credentials: legacy ciphertext and nonce are NOT unchanged. Both adapters decrypt and re-encrypt with a new AAD domain and fresh nonce. The same Instance key is used; no KDF was added. This agrees with DESIGN §49 I6's re-wrap exception.
  • Downgrade concern: migration clears legacy ciphertext. The old migration runner checks registered versions only; unknown newer versions do not block startup. Old sync cannot decrypt cleared credentials. Deployment script checks health only and has no database restore or downgrade guard.
  • Mail actions concern: download_attachment and change_read_state still call legacy InstanceKey::decrypt (mail/src/routes.rs:1532–1535, 1635–1638), unlike sync's decrypt_integration branch. Migrated accounts therefore return 500 for provider attachment fetch and changed read state.
  • Ordering: origin/dev has core 1–6, Calendar 1–4, Mail 1–8. No number clash at that SHA. #626 migration 9 is on origin/job/maildup-626 at 98b627f45e, not on origin/dev. Test fixture uses that exact SQL and labels it as a pending branch dependency.

Claim-by-claim evidence

  1. Transaction and rerun: the account move uses one transaction. The completion marker commits with the moved accounts. Later boots return before re-wrap. A failed attempt writes only a safe status after rollback. Schema versions commit individually, not as one whole upgrade. Test: late_statement_failure_rolls_back_then_retries. Pending: abrupt process termination was not injected at every statement.
  2. Mail preservation: migration updates only account credential columns. It does not write messages, memberships, folders, generations or jobs. Mail account IDs remain the Connected Account IDs. Existing sync jobs still use the same owner/account IDs. Sync obtains the shared password (mail/src/sync.rs:283–313) and uses the saved folders/generations. Literal ciphertext/nonce preservation is refuted: the old Mail AAD (mail/src/crypto.rs:190–192) differs from shared AAD (calternal-db/src/integrations.rs, associated_data). Re-wrap retains IMAP and separate SMTP passwords. Server supplies the same key to both adapters and the migration (wire.rs:1094–1098, 1223). No password entry is required for the new sync path. Read-state and attachment routes remain broken.
  3. Calendar identities: Calendar migration 5 adds a nullable link only. The account move preserves Calendar account ID, endpoint, principal href and home href. Calendar/calendar event tables are not written. The adapter joins the shared credential through the new link, and cache queries retain the old account ID (calendar/src/cache/store.rs:159–190). Existing preservation test also covers a merged account with distinct Mail and Calendar passwords and a legacy OAuth envelope (integrations.rs:2059–2290). A real CalDAV client was not run; database href, UID, etag and iCalendar equality is the evidence for stable identities.
  4. Isolation: the literal “no query reads accounts without an owner filter” claim is false for the trusted startup migration, which scans all legacy Users (integrations.rs:194–198, 262–266). Matching requires account.owner_id == owner_id (310–312), inserted rows retain owner_id, and updates bind both owner and account ID. Request account reads are scoped. Mail joins require both i.id = a.id and equal owners (mail/src/cache/store.rs:420–456). Calendar joins require both link/ID and equal owners (calendar/src/cache/store.rs:159–190). The new legacy-status query is instance-wide and returns only state/error code, not account counts or identities.
  5. Downgrade: refuted as a safe fallback. The old schema runner accepts newer unknown versions. The old binary has no shared decrypt path. It can start but then cannot use the cleared legacy sign-ins. Startup snapshot helps only if the operator restores it. Old-image-only fallback must be blocked or coupled with a correct pre-upgrade Index restore. A successful new boot followed by old writes and a new boot is also unsafe: the global “complete” marker skips new legacy rows created by the old image.
  6. Production shape: PASS for cache preservation. Four diagnostic tests pass at the pinned review target. Fixture has 4,000 message rows and 4,018 UID memberships, including 18 duplicate message IDs within one folder. This distinction is necessary: provider UIDs and cached message identities are different things. #626's exact migration 9 permits all those memberships.

New route classification

All five operations are under /api/v1/system/integrations. They are User/data-scope routes, not admin-only routes. principal rejects no context/no User with 401, rejects no data scope/invalid User ID with 403, and permits a valid User with data scope (integrations.rs:744–756). No role check restricts these operations to admins. Data-scoped App Passwords or agents with a User identity meet this local guard; account-only scope does not.

Method and suffix Classification Owner boundary
GET /accounts User read list_integration_accounts filters owner_id; API omits credentials
POST /accounts User Security state write plus provider network setup owner_id comes from principal, never request body; transaction commits central row and projections
PATCH /accounts/{id} User Security state write owner-scoped lookup; all three UPDATEs filter owner_id
DELETE /accounts/{id} User Security state and cache delete all DELETEs filter owner_id; transaction rolls back on missing central row
GET /legacy-migration User read of instance-wide status authenticated data scope; returns only state and fixed error code

Existing route test: account_list_and_mutations_are_scoped_to_the_authenticated_user checks anonymous, wrong scope and foreign-owner list/PATCH/DELETE. Code references above cover POST's principal binding and the status route.

Migration ordering and dev drift

Core 7–10 and Calendar 5 have no collision against fetched origin/dev (core 1–6, Calendar 1–4). Mail 9 belongs to another namespace, so it does not collide with core 9. The pending #626 SQL rebuilds only mail_memberships and does not touch account credentials. It can run before or after the account move. The fixture uses #626 first. Without #626, the reviewed branch still has UNIQUE(folder_id,generation,message_id), so the production shape cannot be represented in its unmodified schema.

origin/dev includes #613 first-sync code. Compared with origin/dev, the reviewed branch has the old short-window assertion. It includes the duplicate-skip hotfix, but lacks 687ff7031’s change that keeps a short window instead of rolling it back. Those independent fixes must survive integration; they are not evidence of migration data loss. Tests never change existing assertions to make failures pass.

Decisions and scope

  • Keep the review independent. Do not fix production code. Supply diagnostic tests as a patch on this review branch.
  • Use exact pending #626 SQL for the requested duplicate-UID fixture. Do not describe that migration as already on dev.
  • Use complete ordered row equality as the integrity assertion. Print deterministic FNV-1a checksums for compact evidence; these checksums are not cryptographic security checks.
  • No UI or user-facing feature was built. No new performance profile is required. Record local account-move time as context only; it is not a latency benchmark or a gate.

Additional finding: legacy create routes remain active

POST /api/v1/mail/accounts (mail/src/routes.rs:814–836) and POST /api/v1/calendar/accounts (calendar/src/routes.rs:805–838) still write standalone legacy account rows. After the global completion marker, the migration returns before scanning those rows (integrations.rs:180–186). Thus current legacy API clients can create accounts that never appear in Connected Accounts, even across a restart. The Settings screen loses the central account controls for those rows. Retire or delegate those create routes to the central writer, or safely handle new legacy rows. Test: completed_marker_skips_later_legacy_accounts uses the same legacy storage shape and proves the skip without provider access. This also explains why an old-image-only downgrade followed by a re-upgrade is unsafe.

#626 compatibility finding

Once Mail migration 9 has been applied, this reviewed binary's store_window statement is invalid. It still has ON CONFLICT(folder_id,generation,message_id) DO NOTHING (mail/src/cache/store.rs:988–991). Migration 9 removes that UNIQUE constraint, and SQLite rejects that conflict target before it inserts any membership. #626's store adapter change must ship with its migration; copying only the SQL does not make this binary compatible. The production-shaped test reproduces the precise conflict-target error with the reviewed INSERT shape. No cache rows are changed by that rejected statement. This is also another reason that an old binary must not open a database migrated by #626.

Required fixes before GO

  1. Resolve shared credentials in Mail attachment and read-state routes. The real loopback test observes 500 for both operations before provider I/O.
  2. Add a safe downgrade contract. Reject an old binary against a migrated Index, or restore the matching pre-upgrade snapshot before it starts. Re-deploying only the old image is unsafe.
  3. Retire or delegate legacy account create writers, or safely reconcile later legacy rows. The completed marker test proves that later rows remain outside Connected Accounts.
  4. Ship #626's SQL and store adapter together. Do not run the reviewed membership INSERT against the migration-9 schema. Keep origin/dev's short-window fix when integrating this branch.

Measured preservation evidence

These are complete ordered row comparisons, not selected fields. Each before/after FNV-1a checksum is equal. Password values are checked in memory and are not logged. Re-wrap changes nonce and ciphertext as required by the new AEAD domain.

Table Rows Before checksum After checksum
mail_messages 4000 e2781e1486c45bc0 e2781e1486c45bc0
mail_memberships 4018 19c85a1d271200c3 19c85a1d271200c3
mail_folders 1 16b355c2a095d4ec 16b355c2a095d4ec
mail_sync_generations 2 3030700ccc2850ff 3030700ccc2850ff
calendar_calendars 1 92289d809d596cc7 92289d809d596cc7
calendar_events 1 c74fd5924eb5ec92 c74fd5924eb5ec92

Local account-move duration in the pinned-target run: 3,173 microseconds. No matching account-migration profile exists in docs/perf/baseline.json. This single local timing is not p50/p95, CPU or RSS evidence and does not support a performance claim. This review adds no production hot path or user-facing feature.

Pinned-target diagnostic output, verbatim:

review completed marker: later legacy account remains outside Connected Accounts
review real loopback: read-state=500 attachment=500 (no provider IO)
review #626 compatibility: old membership conflict target is rejected
review local migration elapsed_us=3173
review mail_messages: rows=4000 before=e2781e1486c45bc0 after=e2781e1486c45bc0
review mail_memberships: rows=4018 before=19c85a1d271200c3 after=19c85a1d271200c3
review mail_folders: rows=1 before=16b355c2a095d4ec after=16b355c2a095d4ec
review mail_sync_generations: rows=2 before=3030700ccc2850ff after=3030700ccc2850ff
review calendar_calendars: rows=1 before=92289d809d596cc7 after=92289d809d596cc7
review calendar_events: rows=1 before=c74fd5924eb5ec92 after=c74fd5924eb5ec92
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 117 filtered out; finished in 1.46s

Files and patch

  • review-findings.md: verdict, precise references, route classification and evidence.
  • crates/calternal-server/src/integrations_review.rs: four diagnostic tests; no acceptance expectations are changed.
  • crates/calternal-server/src/integrations.rs: test-only include (two lines).
  • crates/calternal-server/tests/review/0009_duplicate_uid_memberships.sql: exact pending #626 SQL fixture from 98b627f45.
  • artifacts/integrations-review-tests.patch: test patch against ffb73a099. Diagnostic tests intentionally assert the observed defects; do not treat their 500 assertions as acceptance requirements for a fix.

Test commit: 8274c17e8. The merge of origin/dev was automatic and preserved dev's short-window fix. No manual merge resolution changed any existing assertion. The patch omits inherited production changes and review prose.

Known gaps

  • No production Index or real credentials were accessed.
  • No old image was launched. The downgrade finding is proven by the old migration-set acceptance test, the empty legacy ciphertext/decrypt failure, and the old credential consumer code.
  • No real IMAP provider or CalDAV client was run. Cache identity preservation is tested; full provider/client continuity remains an acceptance check for the implementation job.
  • A late SQL abort is injected and retry is tested. SIGKILL or power loss was not injected at every statement. Transaction boundaries are reviewed precisely.
  • The one loopback diagnostic round tests the two blocking Mail failures. It is not a full hostile-input audit. Non-SLOW findings are filed on #407; production fixes are outside this read-only review.
  • Mail migration 9 is still absent from fetched origin/dev. Pending branch compatibility is tested with its exact SQL fixture.
  • No UI source changes or visual review artifacts are part of this review.

Final gates

Gated code head: af6616f4dc. Final report commits change documentation only.

All commands use CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4 and the worktree target/tmp as TMPDIR. CARGO_TARGET_DIR is the preset job directory.

cargo fmt --check (exit 0):

stdout and stderr were empty.

cargo clippy -p calternal-server --all-targets -- -D warnings (exit 0), terminal summary verbatim:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 45s

cargo test -p calternal-server --quiet -- --test-threads=1 (exit 0):


running 121 tests
....................................................................................... 87/121
......................ii......i...
test result: ok. 118 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 26.34s

cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings (exit 0), terminal summary verbatim:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 59.99s

cargo test -p calternal-plugin-mail --quiet -- --test-threads=1 (exit 0):


running 40 tests
................................i..i....
test result: ok. 38 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 3.87s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Full output is saved in artifacts/gate-transcript.md and posted verbatim on #407. The three ignored Server tests run through live_apps_run_in_separate_processes. The two ignored Mail tests require the isolated TLS provider and the large-history performance profile. No existing expectation was edited by this review.

The production web build succeeded to provide the RustEmbed input. No web source changed. Module and function comments in all touched test files were re-read before this report.

Cleanup

Cargo build output and web build output were removed. Cargo cleanup output, verbatim:

     Removed 15157 files, 6.4GiB total
Independent #407 review finished. Verdict: **NO-GO**. Final review head: `ad7e25c6392e75cd8360c82b9e716c8011b7fca1` on `job/integrations-review`. Assessed implementation: `ffb73a099ad521cca3d854507a2ad02f198c27e8`. Gated code head after the required origin/dev merge: `af6616f4dc1fff6ed3c13a6bdf17dd018dfee0a0`. Test-only patch commit: `8274c17e8`, posted above. No production fixes, push, deploy or issue close. Worktree is clean. # Connected Accounts migration review — #407 Review target: ffb73a099ad521cca3d854507a2ad02f198c27e8. Verdict: **NO-GO**. Review branch: job/integrations-review. No production fixes are authored. Final gates run after the required merge of origin/dev. Fetched origin/dev: 687ff703136e71e89f8dfba139e93cd0788b25c1. ## Findings in progress - Account move: one SQLx transaction holds inserts, credential clears, Calendar links and completion marker (`integrations.rs:163–465`). Each schema migration has a separate transaction (`migrations.rs:189–208`). This is not one transaction across the full schema upgrade. - Credentials: legacy ciphertext and nonce are NOT unchanged. Both adapters decrypt and re-encrypt with a new AAD domain and fresh nonce. The same Instance key is used; no KDF was added. This agrees with DESIGN §49 I6's re-wrap exception. - Downgrade concern: migration clears legacy ciphertext. The old migration runner checks registered versions only; unknown newer versions do not block startup. Old sync cannot decrypt cleared credentials. Deployment script checks health only and has no database restore or downgrade guard. - Mail actions concern: `download_attachment` and `change_read_state` still call legacy `InstanceKey::decrypt` (`mail/src/routes.rs:1532–1535`, `1635–1638`), unlike sync's `decrypt_integration` branch. Migrated accounts therefore return 500 for provider attachment fetch and changed read state. - Ordering: origin/dev has core 1–6, Calendar 1–4, Mail 1–8. No number clash at that SHA. #626 migration 9 is on origin/job/maildup-626 at 98b627f45ee596c35b09b896b4283d4cf0733e3f, not on origin/dev. Test fixture uses that exact SQL and labels it as a pending branch dependency. ## Claim-by-claim evidence 1. Transaction and rerun: the account move uses one transaction. The completion marker commits with the moved accounts. Later boots return before re-wrap. A failed attempt writes only a safe status after rollback. Schema versions commit individually, not as one whole upgrade. Test: `late_statement_failure_rolls_back_then_retries`. Pending: abrupt process termination was not injected at every statement. 2. Mail preservation: migration updates only account credential columns. It does not write messages, memberships, folders, generations or jobs. Mail account IDs remain the Connected Account IDs. Existing sync jobs still use the same owner/account IDs. Sync obtains the shared password (`mail/src/sync.rs:283–313`) and uses the saved folders/generations. Literal ciphertext/nonce preservation is refuted: the old Mail AAD (`mail/src/crypto.rs:190–192`) differs from shared AAD (`calternal-db/src/integrations.rs`, `associated_data`). Re-wrap retains IMAP and separate SMTP passwords. Server supplies the same key to both adapters and the migration (`wire.rs:1094–1098`, `1223`). No password entry is required for the new sync path. Read-state and attachment routes remain broken. 3. Calendar identities: Calendar migration 5 adds a nullable link only. The account move preserves Calendar account ID, endpoint, principal href and home href. Calendar/calendar event tables are not written. The adapter joins the shared credential through the new link, and cache queries retain the old account ID (`calendar/src/cache/store.rs:159–190`). Existing preservation test also covers a merged account with distinct Mail and Calendar passwords and a legacy OAuth envelope (`integrations.rs:2059–2290`). A real CalDAV client was not run; database href, UID, etag and iCalendar equality is the evidence for stable identities. 4. Isolation: the literal “no query reads accounts without an owner filter” claim is false for the trusted startup migration, which scans all legacy Users (`integrations.rs:194–198`, `262–266`). Matching requires `account.owner_id == owner_id` (`310–312`), inserted rows retain owner_id, and updates bind both owner and account ID. Request account reads are scoped. Mail joins require both `i.id = a.id` and equal owners (`mail/src/cache/store.rs:420–456`). Calendar joins require both link/ID and equal owners (`calendar/src/cache/store.rs:159–190`). The new legacy-status query is instance-wide and returns only state/error code, not account counts or identities. 5. Downgrade: refuted as a safe fallback. The old schema runner accepts newer unknown versions. The old binary has no shared decrypt path. It can start but then cannot use the cleared legacy sign-ins. Startup snapshot helps only if the operator restores it. Old-image-only fallback must be blocked or coupled with a correct pre-upgrade Index restore. A successful new boot followed by old writes and a new boot is also unsafe: the global “complete” marker skips new legacy rows created by the old image. 6. Production shape: **PASS for cache preservation**. Four diagnostic tests pass at the pinned review target. Fixture has 4,000 message rows and 4,018 UID memberships, including 18 duplicate message IDs within one folder. This distinction is necessary: provider UIDs and cached message identities are different things. #626's exact migration 9 permits all those memberships. ## New route classification All five operations are under `/api/v1/system/integrations`. They are User/data-scope routes, not admin-only routes. `principal` rejects no context/no User with 401, rejects no data scope/invalid User ID with 403, and permits a valid User with data scope (`integrations.rs:744–756`). No role check restricts these operations to admins. Data-scoped App Passwords or agents with a User identity meet this local guard; account-only scope does not. | Method and suffix | Classification | Owner boundary | | --- | --- | --- | | GET `/accounts` | User read | `list_integration_accounts` filters owner_id; API omits credentials | | POST `/accounts` | User Security state write plus provider network setup | owner_id comes from principal, never request body; transaction commits central row and projections | | PATCH `/accounts/{id}` | User Security state write | owner-scoped lookup; all three UPDATEs filter owner_id | | DELETE `/accounts/{id}` | User Security state and cache delete | all DELETEs filter owner_id; transaction rolls back on missing central row | | GET `/legacy-migration` | User read of instance-wide status | authenticated data scope; returns only state and fixed error code | Existing route test: `account_list_and_mutations_are_scoped_to_the_authenticated_user` checks anonymous, wrong scope and foreign-owner list/PATCH/DELETE. Code references above cover POST's principal binding and the status route. ## Migration ordering and dev drift Core 7–10 and Calendar 5 have no collision against fetched origin/dev (core 1–6, Calendar 1–4). Mail 9 belongs to another namespace, so it does not collide with core 9. The pending #626 SQL rebuilds only mail_memberships and does not touch account credentials. It can run before or after the account move. The fixture uses #626 first. Without #626, the reviewed branch still has UNIQUE(folder_id,generation,message_id), so the production shape cannot be represented in its unmodified schema. origin/dev includes #613 first-sync code. Compared with origin/dev, the reviewed branch has the old short-window assertion. It includes the duplicate-skip hotfix, but lacks 687ff7031’s change that keeps a short window instead of rolling it back. Those independent fixes must survive integration; they are not evidence of migration data loss. Tests never change existing assertions to make failures pass. ## Decisions and scope - Keep the review independent. Do not fix production code. Supply diagnostic tests as a patch on this review branch. - Use exact pending #626 SQL for the requested duplicate-UID fixture. Do not describe that migration as already on dev. - Use complete ordered row equality as the integrity assertion. Print deterministic FNV-1a checksums for compact evidence; these checksums are not cryptographic security checks. - No UI or user-facing feature was built. No new performance profile is required. Record local account-move time as context only; it is not a latency benchmark or a gate. ## Additional finding: legacy create routes remain active `POST /api/v1/mail/accounts` (`mail/src/routes.rs:814–836`) and `POST /api/v1/calendar/accounts` (`calendar/src/routes.rs:805–838`) still write standalone legacy account rows. After the global completion marker, the migration returns before scanning those rows (`integrations.rs:180–186`). Thus current legacy API clients can create accounts that never appear in Connected Accounts, even across a restart. The Settings screen loses the central account controls for those rows. Retire or delegate those create routes to the central writer, or safely handle new legacy rows. Test: `completed_marker_skips_later_legacy_accounts` uses the same legacy storage shape and proves the skip without provider access. This also explains why an old-image-only downgrade followed by a re-upgrade is unsafe. ## #626 compatibility finding Once Mail migration 9 has been applied, this reviewed binary's `store_window` statement is invalid. It still has `ON CONFLICT(folder_id,generation,message_id) DO NOTHING` (`mail/src/cache/store.rs:988–991`). Migration 9 removes that UNIQUE constraint, and SQLite rejects that conflict target before it inserts any membership. #626's store adapter change must ship with its migration; copying only the SQL does not make this binary compatible. The production-shaped test reproduces the precise conflict-target error with the reviewed INSERT shape. No cache rows are changed by that rejected statement. This is also another reason that an old binary must not open a database migrated by #626. ## Required fixes before GO 1. Resolve shared credentials in Mail attachment and read-state routes. The real loopback test observes 500 for both operations before provider I/O. 2. Add a safe downgrade contract. Reject an old binary against a migrated Index, or restore the matching pre-upgrade snapshot before it starts. Re-deploying only the old image is unsafe. 3. Retire or delegate legacy account create writers, or safely reconcile later legacy rows. The completed marker test proves that later rows remain outside Connected Accounts. 4. Ship #626's SQL and store adapter together. Do not run the reviewed membership INSERT against the migration-9 schema. Keep origin/dev's short-window fix when integrating this branch. ## Measured preservation evidence These are complete ordered row comparisons, not selected fields. Each before/after FNV-1a checksum is equal. Password values are checked in memory and are not logged. Re-wrap changes nonce and ciphertext as required by the new AEAD domain. | Table | Rows | Before checksum | After checksum | | --- | ---: | --- | --- | | mail_messages | 4000 | e2781e1486c45bc0 | e2781e1486c45bc0 | | mail_memberships | 4018 | 19c85a1d271200c3 | 19c85a1d271200c3 | | mail_folders | 1 | 16b355c2a095d4ec | 16b355c2a095d4ec | | mail_sync_generations | 2 | 3030700ccc2850ff | 3030700ccc2850ff | | calendar_calendars | 1 | 92289d809d596cc7 | 92289d809d596cc7 | | calendar_events | 1 | c74fd5924eb5ec92 | c74fd5924eb5ec92 | Local account-move duration in the pinned-target run: 3,173 microseconds. No matching account-migration profile exists in docs/perf/baseline.json. This single local timing is not p50/p95, CPU or RSS evidence and does not support a performance claim. This review adds no production hot path or user-facing feature. Pinned-target diagnostic output, verbatim: ```text review completed marker: later legacy account remains outside Connected Accounts review real loopback: read-state=500 attachment=500 (no provider IO) review #626 compatibility: old membership conflict target is rejected review local migration elapsed_us=3173 review mail_messages: rows=4000 before=e2781e1486c45bc0 after=e2781e1486c45bc0 review mail_memberships: rows=4018 before=19c85a1d271200c3 after=19c85a1d271200c3 review mail_folders: rows=1 before=16b355c2a095d4ec after=16b355c2a095d4ec review mail_sync_generations: rows=2 before=3030700ccc2850ff after=3030700ccc2850ff review calendar_calendars: rows=1 before=92289d809d596cc7 after=92289d809d596cc7 review calendar_events: rows=1 before=c74fd5924eb5ec92 after=c74fd5924eb5ec92 test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 117 filtered out; finished in 1.46s ``` ## Files and patch - review-findings.md: verdict, precise references, route classification and evidence. - crates/calternal-server/src/integrations_review.rs: four diagnostic tests; no acceptance expectations are changed. - crates/calternal-server/src/integrations.rs: test-only include (two lines). - crates/calternal-server/tests/review/0009_duplicate_uid_memberships.sql: exact pending #626 SQL fixture from 98b627f45. - artifacts/integrations-review-tests.patch: test patch against ffb73a099. Diagnostic tests intentionally assert the observed defects; do not treat their 500 assertions as acceptance requirements for a fix. Test commit: 8274c17e8. The merge of origin/dev was automatic and preserved dev's short-window fix. No manual merge resolution changed any existing assertion. The patch omits inherited production changes and review prose. ## Known gaps - No production Index or real credentials were accessed. - No old image was launched. The downgrade finding is proven by the old migration-set acceptance test, the empty legacy ciphertext/decrypt failure, and the old credential consumer code. - No real IMAP provider or CalDAV client was run. Cache identity preservation is tested; full provider/client continuity remains an acceptance check for the implementation job. - A late SQL abort is injected and retry is tested. SIGKILL or power loss was not injected at every statement. Transaction boundaries are reviewed precisely. - The one loopback diagnostic round tests the two blocking Mail failures. It is not a full hostile-input audit. Non-SLOW findings are filed on #407; production fixes are outside this read-only review. - Mail migration 9 is still absent from fetched origin/dev. Pending branch compatibility is tested with its exact SQL fixture. - No UI source changes or visual review artifacts are part of this review. ## Final gates Gated code head: af6616f4dc1fff6ed3c13a6bdf17dd018dfee0a0. Final report commits change documentation only. All commands use CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4 and the worktree target/tmp as TMPDIR. CARGO_TARGET_DIR is the preset job directory. `cargo fmt --check` (exit 0): stdout and stderr were empty. `cargo clippy -p calternal-server --all-targets -- -D warnings` (exit 0), terminal summary verbatim: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 45s ``` `cargo test -p calternal-server --quiet -- --test-threads=1` (exit 0): ```text running 121 tests ....................................................................................... 87/121 ......................ii......i... test result: ok. 118 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 26.34s ``` `cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings` (exit 0), terminal summary verbatim: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 59.99s ``` `cargo test -p calternal-plugin-mail --quiet -- --test-threads=1` (exit 0): ```text running 40 tests ................................i..i.... test result: ok. 38 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 3.87s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` Full output is saved in artifacts/gate-transcript.md and posted verbatim on #407. The three ignored Server tests run through live_apps_run_in_separate_processes. The two ignored Mail tests require the isolated TLS provider and the large-history performance profile. No existing expectation was edited by this review. The production web build succeeded to provide the RustEmbed input. No web source changed. Module and function comments in all touched test files were re-read before this report. ## Cleanup Cargo build output and web build output were removed. Cargo cleanup output, verbatim: ```text Removed 15157 files, 6.4GiB total ```
Author
Owner

Round 4 started on job/integrations, base/head ffb73a099a. Read CLAUDE.md, CONTEXT.md, DESIGN §33/34/49/50 and the independent NO-GO review. First slice fixes shared credential consumers; next preserves legacy encrypted sign-ins and reconciles unlinked rows on every boot. No push, deploy or integration into dev. Diagnostic defect assertions will change only where #407 explicitly requires the new behavior. #626 SQL will not ship independently of its adapter.

Round 4 started on job/integrations, base/head ffb73a099ad521cca3d854507a2ad02f198c27e8. Read CLAUDE.md, CONTEXT.md, DESIGN §33/34/49/50 and the independent NO-GO review. First slice fixes shared credential consumers; next preserves legacy encrypted sign-ins and reconciles unlinked rows on every boot. No push, deploy or integration into dev. Diagnostic defect assertions will change only where #407 explicitly requires the new behavior. #626 SQL will not ship independently of its adapter.
Author
Owner

Round 4 evidence: imported review tests fail on the reviewed code for exactly the three required changes (3 failed, rollback test passed). Mail read-state/attachment return 500 instead of endpoint validation; migrated legacy decrypt fails; later rows are skipped. Production code now uses one shared Mail decrypt resolver, keeps legacy kind/nonce/ciphertext for rollback, and scans unlinked rows on every boot. A later Calendar row can match the existing shared Mail sign-in inside the writer transaction. Minimal public addition: calternal-db exports its existing account-row decoder so startup does not duplicate provider decoding or read a different transaction snapshot.

UI slice committed as e696e4113. Targeted component tests: 10 passed; svelte-check: 0 errors and 0 warnings. The fill on connected rows came from LocationGroup's global .settings-row.deep-linked style; it now targets only #opt-location. OverlaySurface gets an optional shared header snippet; provider setup uses ModeHeader (PillGroup actions and ProgressiveBlur) once in both presentations. Other uses one server glyph; Google keeps its initial inside the same neutral circle. Updated old icon/title test expectations only because the Round 4 brief explicitly changes them.

Decisions: retain legacy sign-ins now and remove them only with a future explicit downgrade boundary; this does not claim rollback safety across #626's incompatible membership schema. The 4,000-message/4,018-membership fixture uses a test-only schema shape, without registering or shipping the pending #626 migration. No dependency changes are required. Browser plugin is unavailable; use the repo Playwright harness.

Round 4 evidence: imported review tests fail on the reviewed code for exactly the three required changes (3 failed, rollback test passed). Mail read-state/attachment return 500 instead of endpoint validation; migrated legacy decrypt fails; later rows are skipped. Production code now uses one shared Mail decrypt resolver, keeps legacy kind/nonce/ciphertext for rollback, and scans unlinked rows on every boot. A later Calendar row can match the existing shared Mail sign-in inside the writer transaction. Minimal public addition: calternal-db exports its existing account-row decoder so startup does not duplicate provider decoding or read a different transaction snapshot. UI slice committed as e696e4113. Targeted component tests: 10 passed; svelte-check: 0 errors and 0 warnings. The fill on connected rows came from LocationGroup's global `.settings-row.deep-linked` style; it now targets only `#opt-location`. OverlaySurface gets an optional shared header snippet; provider setup uses ModeHeader (PillGroup actions and ProgressiveBlur) once in both presentations. Other uses one server glyph; Google keeps its initial inside the same neutral circle. Updated old icon/title test expectations only because the Round 4 brief explicitly changes them. Decisions: retain legacy sign-ins now and remove them only with a future explicit downgrade boundary; this does not claim rollback safety across #626's incompatible membership schema. The 4,000-message/4,018-membership fixture uses a test-only schema shape, without registering or shipping the pending #626 migration. No dependency changes are required. Browser plugin is unavailable; use the repo Playwright harness.
Author
Owner

Round 4 integrity progress on job/integrations (Mail resolver commit 99eab5ae3; visual surface commit e696e4113).

The imported independent-review regressions now pass: exact full-column comparisons of the 4,000-message / 4,018-membership fixture; legacy Mail IMAP/SMTP and Calendar credential recovery with their original AAD; rollback after a late statement failure; separate migrated attachment and read-state routes; late Mail account reconciliation; late Calendar linking to existing shared Mail; and the real-listener two-User owner matrix. The exact migrated fixture also passed a scripted Mail resume: 4,000 messages, 4,018 memberships, zero repeated UID FETCH commands.

Evidence:

test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured; 110 filtered out; finished in 8.85s
review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 1.83s

The new public DB decoder is small: startup uses the existing account decoder inside its writer transaction. This avoids a separate reader snapshot and duplicate provider parsing. The independent read-only code review found no blocking integrity defect. Full Server checks are running before the migration commit.

The perf VM connection returned No route to host. The new migration profile will use the local host and report this limit. The fixture schema is test-only; this branch does not register pending Mail 0009 SQL. The final origin/dev merge remains to be done once before final gates.

Round 4 integrity progress on `job/integrations` (Mail resolver commit `99eab5ae3`; visual surface commit `e696e4113`). The imported independent-review regressions now pass: exact full-column comparisons of the 4,000-message / 4,018-membership fixture; legacy Mail IMAP/SMTP and Calendar credential recovery with their original AAD; rollback after a late statement failure; separate migrated attachment and read-state routes; late Mail account reconciliation; late Calendar linking to existing shared Mail; and the real-listener two-User owner matrix. The exact migrated fixture also passed a scripted Mail resume: 4,000 messages, 4,018 memberships, zero repeated UID FETCH commands. Evidence: ``` test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured; 110 filtered out; finished in 8.85s review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 1.83s ``` The new public DB decoder is small: startup uses the existing account decoder inside its writer transaction. This avoids a separate reader snapshot and duplicate provider parsing. The independent read-only code review found no blocking integrity defect. Full Server checks are running before the migration commit. The perf VM connection returned `No route to host`. The new migration profile will use the local host and report this limit. The fixture schema is test-only; this branch does not register pending Mail 0009 SQL. The final origin/dev merge remains to be done once before final gates.
Author
Owner

A shared UI follow-up is needed for the 2026-10-01 keyboard-motion override. This is existing code, not a new provider-specific branch: packages/ui/src/motion.ts:72–77 still returns immediate motion when root data-input is keyboard, and packages/ui/src/tokens.css:1475–1502 sets duration tokens to zero and cancels CSS motion in that modality. Provider setup uses the shared helper and does not set instantOpen.

Removing that policy changes every route and the shared motion tests. I have kept Round 4 on its requested account-integrity and visual fixes; this existing global policy needs the shared motion job. Reduced-motion support remains in place. This is a UI behaviour gap, not an account-integrity gate failure.

A shared UI follow-up is needed for the 2026-10-01 keyboard-motion override. This is existing code, not a new provider-specific branch: `packages/ui/src/motion.ts:72–77` still returns immediate motion when root `data-input` is `keyboard`, and `packages/ui/src/tokens.css:1475–1502` sets duration tokens to zero and cancels CSS motion in that modality. Provider setup uses the shared helper and does not set `instantOpen`. Removing that policy changes every route and the shared motion tests. I have kept Round 4 on its requested account-integrity and visual fixes; this existing global policy needs the shared motion job. Reduced-motion support remains in place. This is a UI behaviour gap, not an account-integrity gate failure.
Author
Owner

Round 4 post-merge gates are green. origin/dev was fetched and merged once at 6dfa0706d; fetched dev is 687ff703136e71e89f8dfba139e93cd0788b25c1. It includes the Mail short-window fix and has no #626 migration. Mail ends at 0008; Calendar ends at 0004; core ends at 0006. This branch's core 0007–0010 and Calendar 0005 do not clash. No Mail 0009 SQL was included.

Verbatim Server result:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 00s
test result: ok. 121 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 43.25s

DB, Mail, Calendar and Plugin Clippy/tests passed as well. Web: svelte-check found 0 errors and 0 warnings, 149 files / 1,023 tests passed. Full raw gate logs will accompany the final report. Comments for changed Mail consumers and legacy-AAD helpers were reviewed and completed in 8f0f3c679.

The exact post-merge migrated fixture again passed the Mail handoff:

review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 0.78s

All six full-column cache snapshots remain equal. The migration profile ran once locally (perf VM unreachable): sequential p50/p95 7.218/13.744 ms, three-worker burst 8.300/43.933 ms. Mean/peak sequential worker RSS 61.04/76.94 MiB; mean worker CPU 35.81%. CPU/RSS includes fixture seeding and comparison, unlike migration latency. No matching profile exists in docs/perf/baseline.json, so no threshold regression can be established from this comparison.

The review matrix will now cover 66 screenshots: all prior 60 plus Location in all widths/themes, because the row-fill fix scopes a Location-owned rule. A small public test-harness addition lets the existing passkey helper register an invited User, without duplicating registration/login logic. The bounded local contract check will use both real Owner/member sessions as well as the already-passing trusted-context route tests. Provider sign-in is not attempted by these fixtures.

Round 4 post-merge gates are green. `origin/dev` was fetched and merged once at `6dfa0706d`; fetched dev is `687ff703136e71e89f8dfba139e93cd0788b25c1`. It includes the Mail short-window fix and has no #626 migration. Mail ends at 0008; Calendar ends at 0004; core ends at 0006. This branch's core 0007–0010 and Calendar 0005 do not clash. No Mail 0009 SQL was included. Verbatim Server result: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 00s test result: ok. 121 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 43.25s ``` DB, Mail, Calendar and Plugin Clippy/tests passed as well. Web: `svelte-check found 0 errors and 0 warnings`, 149 files / 1,023 tests passed. Full raw gate logs will accompany the final report. Comments for changed Mail consumers and legacy-AAD helpers were reviewed and completed in `8f0f3c679`. The exact post-merge migrated fixture again passed the Mail handoff: ``` review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 0.78s ``` All six full-column cache snapshots remain equal. The migration profile ran once locally (perf VM unreachable): sequential p50/p95 7.218/13.744 ms, three-worker burst 8.300/43.933 ms. Mean/peak sequential worker RSS 61.04/76.94 MiB; mean worker CPU 35.81%. CPU/RSS includes fixture seeding and comparison, unlike migration latency. No matching profile exists in docs/perf/baseline.json, so no threshold regression can be established from this comparison. The review matrix will now cover 66 screenshots: all prior 60 plus Location in all widths/themes, because the row-fill fix scopes a Location-owned rule. A small public test-harness addition lets the existing passkey helper register an invited User, without duplicating registration/login logic. The bounded local contract check will use both real Owner/member sessions as well as the already-passing trusted-context route tests. Provider sign-in is not attempted by these fixtures.
Author
Owner

The final connected-row alignment check found a width-dependent cause: the status chip wraps below the email on phone, but shares its first flex line on wider screens. The old icon offset added a cap height; removing that term alone did not meet the ±1 px rule at every width (phone 1.5 px, tablet 0.5 px, desktop -2.0 px).

Commit fd259dc17 gives the email a trimmed cap box and puts its status below it at every width. The icon centers on that box with CSS only. Minimal public addition: SettingsRow exposes its existing first-row/normal-row top inset as a CSS hook, with the same defaults. Connected Accounts uses the hook to reserve icon ascent without copying spacing constants. Nested service rows keep their original layout. All 1,023 Web tests, svelte-check and the production build passed.

The initial fresh capture closed its browser late in the desktop dark theme. No app exception was captured, and those stale files were not accepted as evidence. The capture now starts a fresh browser for each width, sequentially, and preserves primary failures during cleanup. Phone and tablet are complete; desktop is running. The final report will include only the completed final matrix and its measurements. No test assertion was relaxed.

The final connected-row alignment check found a width-dependent cause: the status chip wraps below the email on phone, but shares its first flex line on wider screens. The old icon offset added a cap height; removing that term alone did not meet the ±1 px rule at every width (phone 1.5 px, tablet 0.5 px, desktop -2.0 px). Commit `fd259dc17` gives the email a trimmed cap box and puts its status below it at every width. The icon centers on that box with CSS only. Minimal public addition: SettingsRow exposes its existing first-row/normal-row top inset as a CSS hook, with the same defaults. Connected Accounts uses the hook to reserve icon ascent without copying spacing constants. Nested service rows keep their original layout. All 1,023 Web tests, svelte-check and the production build passed. The initial fresh capture closed its browser late in the desktop dark theme. No app exception was captured, and those stale files were not accepted as evidence. The capture now starts a fresh browser for each width, sequentially, and preserves primary failures during cleanup. Phone and tablet are complete; desktop is running. The final report will include only the completed final matrix and its measurements. No test assertion was relaxed.
Author
Owner

Round 4 report: job/integrations, head c81cf1dfccbf6600d1250fdf8e0c8a0e6335eab6. The one final origin/dev merge used 687ff703136e71e89f8dfba139e93cd0788b25c1. No push or deploy. The issue remains open.

Built:

  • Mail attachment, read-state and sync now use one persisted-account credential resolver. Linked accounts read the shared envelope; retained legacy ciphertext is never a fallback for a damaged shared envelope. Calendar already used its shared resolver. This Mail milestone has no SMTP send route; the shared envelope preserves its separate SMTP sign-in.
  • Startup reconciles each unlinked legacy account on every boot. The diagnostic completion marker no longer skips later rows. A later Calendar account can link to its existing shared Mail account inside the same writer transaction. Rollback keeps the original rows after a late statement failure.
  • Original legacy kind, nonce and ciphertext remain readable with their original AAD. DESIGN §49 I6 and module comments defer removal to a later release with an explicit downgrade boundary.
  • Provider setup renders one floating ModeHeader through the shared OverlaySurface. Other uses one server glyph; Google uses the same neutral circle. Provider labels use CSS cap trimming where supported. Connected account names own a trimmed cap box. Status chips stack below it consistently across widths. The shared row exposes its existing top inset so the icon can align without changing standard spacing in other rows. Location selection paint is scoped to Location, so it cannot fill a Connected Accounts row.
  • Imported the independent review regressions and added the production-shaped migration profile by reusing the existing Linux CPU/RSS sampler.

Files (includes the required origin/dev Mail store fix):

  • apps/web/e2e/harness.mjs
  • apps/web/e2e/integrations-review.mjs
  • apps/web/src/routes/settings/account/LocationGroup.svelte
  • apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte
  • apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte.test.ts
  • apps/web/src/routes/settings/parts/SettingsRow.svelte
  • bench/integrations-migration-407.py
  • bench/mail-sync.py
  • crates/calternal-db/src/integrations.rs
  • crates/calternal-db/src/lib.rs
  • crates/calternal-server/src/integrations.rs
  • crates/calternal-server/src/integrations_review.rs
  • crates/calternal-server/tests/review/production_shape.sql
  • crates/plugins/mail/src/cache/store.rs
  • crates/plugins/mail/src/crypto.rs
  • crates/plugins/mail/src/routes.rs
  • crates/plugins/mail/src/sync.rs
  • docs/DESIGN.md
  • packages/ui/src/components/OverlaySurface.svelte
  • tests/adversarial/integrations_api.mjs

Integrity evidence:
The Server suite includes separate migrated attachment/read-state cases, late Mail reconciliation, late Calendar linking, transaction rollback and the real-listener two-User matrix. Foreign list/mutation calls preserve the owner boundary. The exact migrated Index is handed to the Mail resume test. Full-column equality is checked for all six cache tables; checksums are diagnostic summaries.

review local migration elapsed_us=6954
review mail_messages: rows=4000 before=e2781e1486c45bc0 after=e2781e1486c45bc0
review mail_memberships: rows=4018 before=19c85a1d271200c3 after=19c85a1d271200c3
review mail_folders: rows=1 before=96a48d9dfc5e91c9 after=96a48d9dfc5e91c9
review mail_sync_generations: rows=2 before=3030700ccc2850ff after=3030700ccc2850ff
review calendar_calendars: rows=1 before=92289d809d596cc7 after=92289d809d596cc7
review calendar_events: rows=1 before=c74fd5924eb5ec92 after=c74fd5924eb5ec92
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 123 filtered out; finished in 2.56s
test sync::tests::migrated_production_shape_resumes_without_refetch ... review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 0.78s

#626 and migration numbering:
The fetched origin/dev has Mail migrations 0001–0008 and does not contain #626. This branch registers no Mail 0009 SQL. The duplicate-membership fixture is a test-only schema, with no production migration version. Core 0007–0010 and Calendar 0005 do not clash with the fetched origin/dev. #626 SQL must ship with its store adapter. Legacy credential retention does not make rollback across that unrelated incompatible schema safe; use its matching Index snapshot.

Verbatim gate result lines (the full unchanged logs are in the evidence archive):
cargo fmt --check and the explicit included review-module format check: exit 0, no output.

cargo clippy -p calternal-db --all-targets -- -D warnings and cargo test -p calternal-db -- --test-threads=1:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 12.68s
    Finished `test` profile [unoptimized + debuginfo] target(s) in 15.06s
test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.38s
test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 2.25s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings and cargo test -p calternal-plugin-mail -- --test-threads=1:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 24.96s
    Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 14s
test result: ok. 38 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 5.83s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings and cargo test -p calternal-plugin-calendar -- --test-threads=1:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 09s
    Finished `test` profile [unoptimized + debuginfo] target(s) in 4m 50s
test result: ok. 83 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 24.51s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.29s
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.41s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin --all-targets -- -D warnings and cargo test -p calternal-plugin -- --test-threads=1:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 34.16s
    Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 11s
test result: ok. 26 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.05s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-server --all-targets -- -D warnings and cargo test -p calternal-server -- --test-threads=1:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 00s
    Finished `test` profile [unoptimized + debuginfo] target(s) in 7m 05s
test result: ok. 121 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 43.25s

bun run check and bun run test:

svelte-check found 0 errors and 0 warnings
 Test Files  149 passed (149)
      Tests  1023 passed (1023)

Production evidence:
bun run build and cargo build -p calternal-server passed. The app is served by the built Server. The Server capture build embeds fd259dc174; the final head adds only the capture-runner resource fix. Account rows in the screenshot harness are deterministic test fixtures; no fixture rows ship in the UI. The Browser plugin was unavailable, so the repo Playwright harness was used.

PASS Connected Accounts review: 66 screenshots in /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts
PASS bounded local integrations contract: authenticated reads, anonymous 401, schema rejection, empty cross-Plugin state
PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged
Final light 390px: icon stroke y=(357, 376); email cap ink y=(360, 372); center offset=0.5px
Final light 820px: icon stroke y=(441, 460); email cap ink y=(445, 456); center offset=0.0px
Final light 1440px: icon stroke y=(154, 168); email cap ink y=(156, 166); center offset=0.0px
Final dark 390px: icon stroke y=(357, 376); email cap ink y=(360, 372); center offset=0.5px
Final dark 820px: icon stroke y=(441, 460); email cap ink y=(445, 456); center offset=0.0px
Final dark 1440px: icon stroke y=(154, 168); email cap ink y=(156, 166); center offset=0.0px

The capture covers all five provider setups, chooser, connected account, service checklist and Mail/Calendar account links at 390/820/1440 px in light and dark (66 screenshots including Location). The screenshots are attached for the orchestrator visual review.

Performance (local shared host; perf VM returned No route to host):

Profile p50 / p95 ms Mean worker CPU Mean / peak worker RSS MiB Matching baseline
4,000 messages / 4,018 memberships, sequential 7.218 / 13.744 35.81% 61.04 / 76.94 None in docs/perf/baseline.json
same fixture, three-worker burst 8.300 / 43.933 23.93% 60.91 / 76.12 None in docs/perf/baseline.json
Migration latency excludes seeding and comparisons; worker CPU/RSS includes them. Load average before: [27.80517578125, 26.4453125, 25.181640625]; after: [26.9814453125, 26.32568359375, 25.1630859375]. There is no matching migration baseline, so these measurements do not establish a threshold regression.

Existing metadata profile, 250 synthetic account rows and a 24-read burst (local):

{
  "environment": {
    "profile": "local",
    "host": "calternal-dev",
    "platform": "linux",
    "architecture": "x64",
    "load_average_before": [
      20.95,
      27.57,
      32.17
    ],
    "load_average_after": [
      20.79,
      27.42,
      32.1
    ]
  },
  "account_rows": 250,
  "average": {
    "accounts": {
      "p50_ms": 33.4,
      "p95_ms": 90.9,
      "samples": 12
    },
    "migrationStatus": {
      "p50_ms": 12.9,
      "p95_ms": 25.6,
      "samples": 12
    }
  },
  "burst": {
    "accounts": {
      "concurrency": 24,
      "elapsed_ms": 925.92,
      "p50_ms": 277.9,
      "p95_ms": 536,
      "samples": 24
    },
    "migrationStatus": {
      "concurrency": 24,
      "elapsed_ms": 237.36,
      "p50_ms": 129.4,
      "p95_ms": 167,
      "samples": 24
    }
  },
  "resources": {
    "meanRssBytes": 153367481,
    "peakRssBytes": 166547456,
    "meanCpuPercent": 46.64,
    "peakCpuPercent": 136.57,
    "cpuSeconds": 1.19,
    "samples": 43
  }
}

Decisions:

  • Keep the existing diagnostic marker for Settings, but use per-account links as the idempotence boundary. Preserve active shared Mail credentials when a later Calendar account arrives.
  • Keep the reviewed duplicate UID shape inside a test-only fixture. Do not register unmerged #626 SQL.
  • The no-refetch handoff uses a completed live generation with UIDVALIDITY 777, UIDNEXT 4019 and cursor 4018; it retains the inactive second generation. The original rebuilding-cache cases remain in the existing migration tests. This separates saved-cursor continuation from a legitimate rebuild.
  • Extend the shared OverlaySurface with an optional header snippet and reuse ModeHeader, PillGroup and ProgressiveBlur; avoid another provider-specific chrome primitive.
  • Put the connected status chip below the email at every width. Otherwise its wrapping changes the first title line height. Reuse the SettingsRow inset through a small CSS hook; its default first-row and normal-row spacing stays the same.
  • Use local measurements because the perf VM is unreachable. Do not compare unlike profiles to claim a regression.
  • Start a fresh browser for each capture width, sequentially. This frees renderer/font caches after a long-lived browser closed late in the first final matrix. The new run passes every original coverage and layout assertion.

Known gaps:

  • #626 is absent from the fetched origin/dev; its SQL/store pair remains a separate merge dependency.
  • The full hostile-input/protocol/concurrency probe was not run. This round ran bounded local schema/authentication checks plus the migration regressions and both route-context and real-session two-User matrices.
  • No old image or real Fastmail provider was launched. Downgrade credential readability is proved by exact retained bytes and legacy-AAD decrypt; sync continuation uses the local scripted provider over the exact migrated fixture.
  • The existing global #527 keyboard-motion suppression still conflicts with the October 1 override (motion.ts and tokens.css locations were reported separately). Removing that shared policy affects every route and belongs to the shared motion change.
  • Visual quality approval belongs to the orchestrator; screenshots are supplied as evidence.

Attachments:

Cleanup: Cargo and Web build output and test temporary data were removed. The worktree is clean. Review artifacts remain in artifacts/.

     Removed 18904 files, 10.9GiB total
Round 4 report: `job/integrations`, head `c81cf1dfccbf6600d1250fdf8e0c8a0e6335eab6`. The one final `origin/dev` merge used `687ff703136e71e89f8dfba139e93cd0788b25c1`. No push or deploy. The issue remains open. Built: - Mail attachment, read-state and sync now use one persisted-account credential resolver. Linked accounts read the shared envelope; retained legacy ciphertext is never a fallback for a damaged shared envelope. Calendar already used its shared resolver. This Mail milestone has no SMTP send route; the shared envelope preserves its separate SMTP sign-in. - Startup reconciles each unlinked legacy account on every boot. The diagnostic completion marker no longer skips later rows. A later Calendar account can link to its existing shared Mail account inside the same writer transaction. Rollback keeps the original rows after a late statement failure. - Original legacy kind, nonce and ciphertext remain readable with their original AAD. DESIGN §49 I6 and module comments defer removal to a later release with an explicit downgrade boundary. - Provider setup renders one floating ModeHeader through the shared OverlaySurface. Other uses one server glyph; Google uses the same neutral circle. Provider labels use CSS cap trimming where supported. Connected account names own a trimmed cap box. Status chips stack below it consistently across widths. The shared row exposes its existing top inset so the icon can align without changing standard spacing in other rows. Location selection paint is scoped to Location, so it cannot fill a Connected Accounts row. - Imported the independent review regressions and added the production-shaped migration profile by reusing the existing Linux CPU/RSS sampler. Files (includes the required origin/dev Mail store fix): - `apps/web/e2e/harness.mjs` - `apps/web/e2e/integrations-review.mjs` - `apps/web/src/routes/settings/account/LocationGroup.svelte` - `apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte` - `apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte.test.ts` - `apps/web/src/routes/settings/parts/SettingsRow.svelte` - `bench/integrations-migration-407.py` - `bench/mail-sync.py` - `crates/calternal-db/src/integrations.rs` - `crates/calternal-db/src/lib.rs` - `crates/calternal-server/src/integrations.rs` - `crates/calternal-server/src/integrations_review.rs` - `crates/calternal-server/tests/review/production_shape.sql` - `crates/plugins/mail/src/cache/store.rs` - `crates/plugins/mail/src/crypto.rs` - `crates/plugins/mail/src/routes.rs` - `crates/plugins/mail/src/sync.rs` - `docs/DESIGN.md` - `packages/ui/src/components/OverlaySurface.svelte` - `tests/adversarial/integrations_api.mjs` Integrity evidence: The Server suite includes separate migrated attachment/read-state cases, late Mail reconciliation, late Calendar linking, transaction rollback and the real-listener two-User matrix. Foreign list/mutation calls preserve the owner boundary. The exact migrated Index is handed to the Mail resume test. Full-column equality is checked for all six cache tables; checksums are diagnostic summaries. ``` review local migration elapsed_us=6954 review mail_messages: rows=4000 before=e2781e1486c45bc0 after=e2781e1486c45bc0 review mail_memberships: rows=4018 before=19c85a1d271200c3 after=19c85a1d271200c3 review mail_folders: rows=1 before=96a48d9dfc5e91c9 after=96a48d9dfc5e91c9 review mail_sync_generations: rows=2 before=3030700ccc2850ff after=3030700ccc2850ff review calendar_calendars: rows=1 before=92289d809d596cc7 after=92289d809d596cc7 review calendar_events: rows=1 before=c74fd5924eb5ec92 after=c74fd5924eb5ec92 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 123 filtered out; finished in 2.56s test sync::tests::migrated_production_shape_resumes_without_refetch ... review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 0.78s ``` #626 and migration numbering: The fetched origin/dev has Mail migrations 0001–0008 and does not contain #626. This branch registers no Mail 0009 SQL. The duplicate-membership fixture is a test-only schema, with no production migration version. Core 0007–0010 and Calendar 0005 do not clash with the fetched origin/dev. #626 SQL must ship with its store adapter. Legacy credential retention does not make rollback across that unrelated incompatible schema safe; use its matching Index snapshot. Verbatim gate result lines (the full unchanged logs are in the evidence archive): `cargo fmt --check` and the explicit included review-module format check: exit 0, no output. `cargo clippy -p calternal-db --all-targets -- -D warnings` and `cargo test -p calternal-db -- --test-threads=1`: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 12.68s Finished `test` profile [unoptimized + debuginfo] target(s) in 15.06s test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.38s test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 2.25s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings` and `cargo test -p calternal-plugin-mail -- --test-threads=1`: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 24.96s Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 14s test result: ok. 38 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 5.83s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings` and `cargo test -p calternal-plugin-calendar -- --test-threads=1`: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 09s Finished `test` profile [unoptimized + debuginfo] target(s) in 4m 50s test result: ok. 83 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 24.51s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.29s test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.41s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-plugin --all-targets -- -D warnings` and `cargo test -p calternal-plugin -- --test-threads=1`: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 34.16s Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 11s test result: ok. 26 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.05s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-server --all-targets -- -D warnings` and `cargo test -p calternal-server -- --test-threads=1`: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 00s Finished `test` profile [unoptimized + debuginfo] target(s) in 7m 05s test result: ok. 121 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 43.25s ``` `bun run check` and `bun run test`: ``` svelte-check found 0 errors and 0 warnings Test Files 149 passed (149) Tests 1023 passed (1023) ``` Production evidence: `bun run build` and `cargo build -p calternal-server` passed. The app is served by the built Server. The Server capture build embeds fd259dc1747505a21ce80674941f05a02ea7223f; the final head adds only the capture-runner resource fix. Account rows in the screenshot harness are deterministic test fixtures; no fixture rows ship in the UI. The Browser plugin was unavailable, so the repo Playwright harness was used. ``` PASS Connected Accounts review: 66 screenshots in /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts ``` ``` PASS bounded local integrations contract: authenticated reads, anonymous 401, schema rejection, empty cross-Plugin state PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged ``` ``` Final light 390px: icon stroke y=(357, 376); email cap ink y=(360, 372); center offset=0.5px Final light 820px: icon stroke y=(441, 460); email cap ink y=(445, 456); center offset=0.0px Final light 1440px: icon stroke y=(154, 168); email cap ink y=(156, 166); center offset=0.0px Final dark 390px: icon stroke y=(357, 376); email cap ink y=(360, 372); center offset=0.5px Final dark 820px: icon stroke y=(441, 460); email cap ink y=(445, 456); center offset=0.0px Final dark 1440px: icon stroke y=(154, 168); email cap ink y=(156, 166); center offset=0.0px ``` The capture covers all five provider setups, chooser, connected account, service checklist and Mail/Calendar account links at 390/820/1440 px in light and dark (66 screenshots including Location). The screenshots are attached for the orchestrator visual review. Performance (local shared host; perf VM returned `No route to host`): | Profile | p50 / p95 ms | Mean worker CPU | Mean / peak worker RSS MiB | Matching baseline | | --- | --- | --- | --- | --- | | 4,000 messages / 4,018 memberships, sequential | 7.218 / 13.744 | 35.81% | 61.04 / 76.94 | None in docs/perf/baseline.json | | same fixture, three-worker burst | 8.300 / 43.933 | 23.93% | 60.91 / 76.12 | None in docs/perf/baseline.json | Migration latency excludes seeding and comparisons; worker CPU/RSS includes them. Load average before: [27.80517578125, 26.4453125, 25.181640625]; after: [26.9814453125, 26.32568359375, 25.1630859375]. There is no matching migration baseline, so these measurements do not establish a threshold regression. Existing metadata profile, 250 synthetic account rows and a 24-read burst (local): ```json { "environment": { "profile": "local", "host": "calternal-dev", "platform": "linux", "architecture": "x64", "load_average_before": [ 20.95, 27.57, 32.17 ], "load_average_after": [ 20.79, 27.42, 32.1 ] }, "account_rows": 250, "average": { "accounts": { "p50_ms": 33.4, "p95_ms": 90.9, "samples": 12 }, "migrationStatus": { "p50_ms": 12.9, "p95_ms": 25.6, "samples": 12 } }, "burst": { "accounts": { "concurrency": 24, "elapsed_ms": 925.92, "p50_ms": 277.9, "p95_ms": 536, "samples": 24 }, "migrationStatus": { "concurrency": 24, "elapsed_ms": 237.36, "p50_ms": 129.4, "p95_ms": 167, "samples": 24 } }, "resources": { "meanRssBytes": 153367481, "peakRssBytes": 166547456, "meanCpuPercent": 46.64, "peakCpuPercent": 136.57, "cpuSeconds": 1.19, "samples": 43 } } ``` Decisions: - Keep the existing diagnostic marker for Settings, but use per-account links as the idempotence boundary. Preserve active shared Mail credentials when a later Calendar account arrives. - Keep the reviewed duplicate UID shape inside a test-only fixture. Do not register unmerged #626 SQL. - The no-refetch handoff uses a completed live generation with UIDVALIDITY 777, UIDNEXT 4019 and cursor 4018; it retains the inactive second generation. The original rebuilding-cache cases remain in the existing migration tests. This separates saved-cursor continuation from a legitimate rebuild. - Extend the shared OverlaySurface with an optional header snippet and reuse ModeHeader, PillGroup and ProgressiveBlur; avoid another provider-specific chrome primitive. - Put the connected status chip below the email at every width. Otherwise its wrapping changes the first title line height. Reuse the SettingsRow inset through a small CSS hook; its default first-row and normal-row spacing stays the same. - Use local measurements because the perf VM is unreachable. Do not compare unlike profiles to claim a regression. - Start a fresh browser for each capture width, sequentially. This frees renderer/font caches after a long-lived browser closed late in the first final matrix. The new run passes every original coverage and layout assertion. Known gaps: - #626 is absent from the fetched origin/dev; its SQL/store pair remains a separate merge dependency. - The full hostile-input/protocol/concurrency probe was not run. This round ran bounded local schema/authentication checks plus the migration regressions and both route-context and real-session two-User matrices. - No old image or real Fastmail provider was launched. Downgrade credential readability is proved by exact retained bytes and legacy-AAD decrypt; sync continuation uses the local scripted provider over the exact migrated fixture. - The existing global #527 keyboard-motion suppression still conflicts with the October 1 override (motion.ts and tokens.css locations were reported separately). Removing that shared policy affects every route and belongs to the shared motion change. - Visual quality approval belongs to the orchestrator; screenshots are supplied as evidence. Attachments: - [connected-accounts-round4.zip](https://git.kayg.org/attachments/283ffa84-78cf-4db6-ba28-9504955c8aa3) - [integrations-round4-evidence.zip](https://git.kayg.org/attachments/bf0bd620-91a9-4fff-9901-25bde3e45604) - [chooser-light-390.png](https://git.kayg.org/attachments/8c7c1801-fbc2-4c50-9097-a2f3de23ca82) - [chooser-dark-390.png](https://git.kayg.org/attachments/6e6ab339-d449-4d9c-b4a0-fdf540b4d4bd) - [chooser-light-820.png](https://git.kayg.org/attachments/eabf753c-3bc5-47ea-af81-e8943c31cd32) - [chooser-dark-820.png](https://git.kayg.org/attachments/3b8f29e7-6774-4b53-bc0e-9d560b35de3d) - [chooser-light-1440.png](https://git.kayg.org/attachments/92bd09ed-3a57-4788-8304-2c63a1db0e42) - [chooser-dark-1440.png](https://git.kayg.org/attachments/dd8e3117-b465-417e-b747-54e562373dbb) - [provider-fastmail-light-390.png](https://git.kayg.org/attachments/87b03efc-a2d2-4144-ac7f-8eb9f9f13bbd) - [provider-fastmail-dark-390.png](https://git.kayg.org/attachments/b5086717-4fd0-4597-925b-13748a41393e) - [provider-fastmail-light-820.png](https://git.kayg.org/attachments/e048c46d-23c0-4ee3-a7e3-64861661677a) - [provider-fastmail-dark-820.png](https://git.kayg.org/attachments/e25d3d83-5e46-4bd6-a34b-58a28ce581c4) - [provider-fastmail-light-1440.png](https://git.kayg.org/attachments/179a63b9-0190-42ed-bc88-e05cb9213cc8) - [provider-fastmail-dark-1440.png](https://git.kayg.org/attachments/a81b857f-bddb-4660-b0c0-e85128cb843f) - [connected-light-390.png](https://git.kayg.org/attachments/173cfbc8-2520-4119-a679-d82f3e018e66) - [connected-dark-390.png](https://git.kayg.org/attachments/88f0548b-fabb-48a5-8e4f-4f118b9d917b) - [connected-light-820.png](https://git.kayg.org/attachments/e9bc69de-3612-4c16-95fe-6d5d06b83b4d) - [connected-dark-820.png](https://git.kayg.org/attachments/a78b62d2-eb5e-49af-890d-0f7cc9239310) - [connected-light-1440.png](https://git.kayg.org/attachments/778a47ee-89bc-4e34-bb5d-a23e5c53108b) - [connected-dark-1440.png](https://git.kayg.org/attachments/e5bd45bc-5ba6-4761-bf27-7f7b23d3f017) - [location-light-390.png](https://git.kayg.org/attachments/a0bd82b0-c5b5-4b4a-8a73-5e6091bc6028) - [location-dark-390.png](https://git.kayg.org/attachments/cf37704f-4af4-4942-ba77-597ea15cbd2d) - [location-light-820.png](https://git.kayg.org/attachments/f3d8a517-eb9d-4d22-ad66-8f155352e873) - [location-dark-820.png](https://git.kayg.org/attachments/f0f359a6-8249-488b-bfbc-f5a91cb4edd3) - [location-light-1440.png](https://git.kayg.org/attachments/172bd49c-88ca-4dc6-8122-4bf76dfee60d) - [location-dark-1440.png](https://git.kayg.org/attachments/1126b81b-0cf4-469d-b052-7ece913d233a) Cleanup: Cargo and Web build output and test temporary data were removed. The worktree is clean. Review artifacts remain in artifacts/. ``` Removed 18904 files, 10.9GiB total ```
Author
Owner

Independent #407 round-4 re-check started on job/integrations-recheck at c81cf1dfcc. Scope: four required integrity fixes, imported assertion audit, exact #626 migration ordering and diff risk scan. Tests/documentation only; no push or deploy.

Independent #407 round-4 re-check started on job/integrations-recheck at c81cf1dfccbf6600d1250fdf8e0c8a0e6335eab6. Scope: four required integrity fixes, imported assertion audit, exact #626 migration ordering and diff risk scan. Tests/documentation only; no push or deploy.
Author
Owner

Independent round-4 re-check: new blocking reproduction for #407 / DESIGN §49 I6.

Calendar-first then later legacy Mail for the same Fastmail username returns AccountConflict. The Calendar account is already linked, so the unlinked-Calendar query is empty and no existing shared Calendar row is loaded for matching. The later Mail row attempts a new shared INSERT with the same (owner_id, provider, email), which hits the unique constraint. The writer transaction also rolls back an unrelated later Mail account. Both Mail rows remain unlinked on two consecutive boot calls; legacy ciphertext and the prior shared row stay intact. Diagnostic: integrations::tests::independent_review::diagnostic_later_mail_conflicts_with_existing_shared_calendar. Its rejection assertion records the defect; it is not acceptance behavior.

Focused result, verbatim:

review defect: Calendar-first then later Mail = AccountConflict; 2 Mail rows remain unlinked on repeated boot
review #626 ordering: fresh=true mail_first=true passed
review #626 ordering: fresh=true mail_first=false passed
review #626 ordering: fresh=false mail_first=true passed
review #626 ordering: fresh=false mail_first=false passed
review real loopback: attachment=400 (no provider IO)
review real loopback: read-state=400 (no provider IO)
test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 117 filtered out; finished in 10.01s

No product edits. The imported tests retain full-column cache equality, exact retained Mail credential bytes, successful legacy decrypt, and successful later-row checks. The exact #626 SQL is copied from 3286cad72 into a test-only fixture; both fresh/upgraded orders and the dependency's corrected membership conflict target pass. That dependency still must ship SQL and store adapter together. A read-only merge-tree check identifies conflicts in Mail routes/sync; keep the shared credential resolver and #626 UID behavior when resolving them. Full crate gates are running.

Independent round-4 re-check: new blocking reproduction for #407 / DESIGN §49 I6. Calendar-first then later legacy Mail for the same Fastmail username returns AccountConflict. The Calendar account is already linked, so the unlinked-Calendar query is empty and no existing shared Calendar row is loaded for matching. The later Mail row attempts a new shared INSERT with the same (owner_id, provider, email), which hits the unique constraint. The writer transaction also rolls back an unrelated later Mail account. Both Mail rows remain unlinked on two consecutive boot calls; legacy ciphertext and the prior shared row stay intact. Diagnostic: integrations::tests::independent_review::diagnostic_later_mail_conflicts_with_existing_shared_calendar. Its rejection assertion records the defect; it is not acceptance behavior. Focused result, verbatim: ``` review defect: Calendar-first then later Mail = AccountConflict; 2 Mail rows remain unlinked on repeated boot review #626 ordering: fresh=true mail_first=true passed review #626 ordering: fresh=true mail_first=false passed review #626 ordering: fresh=false mail_first=true passed review #626 ordering: fresh=false mail_first=false passed review real loopback: attachment=400 (no provider IO) review real loopback: read-state=400 (no provider IO) test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 117 filtered out; finished in 10.01s ``` No product edits. The imported tests retain full-column cache equality, exact retained Mail credential bytes, successful legacy decrypt, and successful later-row checks. The exact #626 SQL is copied from 3286cad72 into a test-only fixture; both fresh/upgraded orders and the dependency's corrected membership conflict target pass. That dependency still must ship SQL and store adapter together. A read-only merge-tree check identifies conflicts in Mail routes/sync; keep the shared credential resolver and #626 UID behavior when resolving them. Full crate gates are running.
Author
Owner

Independent #407 round-4 re-check finished. Verdict: NO-GO.

Final head: 47f98145758e51fa36c75774ffd55efb45ce0c21. Branch: job/integrations-recheck.

Connected Accounts round-4 re-check — #407

Verdict: NO-GO. Required fix 3 is incomplete.

Review target: c81cf1dfccbf6600d1250fdf8e0c8a0e6335eab6.
Branch: job/integrations-recheck. Gated test head: 17572313299b864c8316bfc228fa0e8482b03fc2.
Fetched origin/dev: 687ff703136e71e89f8dfba139e93cd0788b25c1.
The required fetch and merge returned Already up to date. No product code changed. No push or deploy.

Required fixes

Fix Result Evidence
Shared credentials on Mail routes and sync PASS Attachment and read-state return 400 at endpoint validation even with an unusable legacy copy. Both use decrypt_account, as do sync and legacy PATCH. Calendar uses its shared resolver. The migrated cache resume test passes.
Legacy credentials after migration PASS Exact Mail nonce and ciphertext remain unchanged. The original Mail decrypt domain recovers IMAP and separate SMTP sign-ins. Calendar Basic and OAuth legacy decrypt checks pass.
Per-account reconciliation INCOMPLETE New distinct Mail accounts and later Calendar links pass. Calendar-first then later Mail for the same sign-in fails and also blocks an unrelated late account.
#626 migration dependency Ordering PASS; combined merge still required Exact Mail 0009 SQL at 3286cad72 applies before or after #407 on fresh and upgraded Index schemas. Both version-9 namespaces remain registered. Foreign keys and repeat application pass. The dependency's corrected membership INSERT accepts duplicate UIDs.

Blocking reproduction

  1. Create a legacy Calendar account for a Fastmail sign-in, then migrate it.
  2. Create a legacy Mail account with the same User, provider and login name.
  3. Create an unrelated legacy Mail account.
  4. Run startup reconciliation twice.

Both calls return AccountConflict. Both Mail accounts remain unlinked. The old shared row and all legacy Mail account columns stay unchanged. This is not data loss, but it fails the required late-account migration contract.

The Mail scan only loads rows with no shared ID match (integrations.rs:187). The Calendar scan skips linked rows (:256). It loads existing shared accounts only to accept later Calendar rows, through a Mail join (:261–268). It never matches a later Mail row to the shared Calendar account. The shared INSERT (:434) then violates the unique User/provider/email constraint. The transaction rolls back the unrelated late row too.

Required correction: reconcile later Mail rows against existing shared Calendar sign-ins. Keep each service's cache identity and both sign-ins. Add an acceptance test for this reverse order. The new diagnostic asserts the observed rejection as defect evidence; it is not an acceptance requirement.

Verbatim diagnostic evidence:

review defect: Calendar-first then later Mail = AccountConflict; 2 Mail rows remain unlinked on repeated boot

Imported test audit and diff risks

No imported integrity assertion was removed or relaxed. Full-column equality still covers all six production-shaped cache tables, with 4,000 messages and 4,018 memberships. The old defect assertions became the behavior explicitly required by #407: successful legacy decrypt, later rows included, and endpoint validation after shared decrypt. The route tests deliberately invalidate the legacy copy, so they cannot pass by using it.

The duplicate-membership fixture changed only its comments and migration registration; its SQL shape is unchanged. Another fixture edit sets the production-shaped folder to completed generation 1 rather than active pending generation 2. Thus the no-refetch test covers a completed live cache. The re-check ordering test retains the original pending generation 2 and compares its full cache rows before and after migration. Pending-generation provider resume is not covered.

#626 remains a dependency. The reviewed c81cf1dfc writer still has the removed message-ID conflict target; the imported diagnostic correctly proves that it fails against the new schema. At 3286cad72, Mail 0009 and the corrected store adapter are both present. They must ship together. An old image needs its matching Index snapshot after #626, as DESIGN §49 I6 states.

A read-only git merge-tree found conflicts between the two heads in Mail routes, sync, IMAP, cache exports, Plugin code, Mail Settings tests/UI and the benchmark sampler. It did not change the worktree. Keep the shared credential resolver and #626 UID behavior when resolving them. This review did not build a resolved combined tree.

The remaining round-4 source diff did not expose another account-integrity blocker. Visual quality remains with the orchestrator. The shared keyboard-motion gap was already reported by the author and is outside this integrity re-check.

Built and files

Only tests and this report were added.

  • crates/calternal-server/src/integrations_review.rs: four fresh/upgraded migration-order cases and the reverse late-service diagnostic. Existing helpers and imported assertions are reused.
  • crates/calternal-server/tests/review/mail_626_at_3286cad72.sql: byte-for-byte test fixture from the dependency head. It is not registered in production.
  • review-findings.md: verdict, evidence and gates.

Atomic test commits: 35cce7c46 (ordering) and 175723132 (late Mail diagnostic). Module and function comments in all touched test files were re-read.

Gates

All Cargo commands used CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4 and worktree target/tmp as TMPDIR. The preset CARGO_TARGET_DIR was unchanged.

These commands exited 0 with empty stdout and stderr:

  • cargo fmt --check
  • rustfmt --edition 2024 --check crates/calternal-server/src/integrations_review.rs
  • cargo clippy -p calternal-server --all-targets --quiet -- -D warnings
  • cargo clippy -p calternal-plugin-mail --all-targets --quiet -- -D warnings

cargo test -p calternal-server --quiet -- --test-threads=1, exit 0, complete output verbatim:


running 126 tests
....................................................................................... 87/126
...........................ii......i...
test result: ok. 123 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 21.47s

cargo test -p calternal-plugin-mail --quiet -- --test-threads=1, exit 0, complete output verbatim:


running 41 tests
...............................i.i..i....
test result: ok. 38 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 1.50s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo test -p calternal-plugin-mail --quiet migrated_production_shape_resumes_without_refetch -- --ignored --test-threads=1 --nocapture, exit 0, complete output verbatim:


running 1 test
review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands
.
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 0.05s

The focused review round passed nine tests. Verbatim result:

test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 117 filtered out; finished in 10.01s

The production Web build passed to supply the Server's embedded assets. No Web source was edited, so Web type/test gates were not repeated. Raw logs remain in artifacts/recheck/.

Known gaps and decisions

  • No old image or external provider was launched. Legacy-domain decrypt and exact retained bytes prove credential readability; a scripted provider verifies completed-cache resume.
  • The bounded local review round covers migrated routes, two-User isolation, rollback and migration order. It is not a full hostile-input or load audit.
  • The resolved #407/#626 combined binary still needs gates after conflict resolution.
  • No user-facing feature or hot path changed. No benchmark profile was added or measured.
  • Decisions: use exact pending SQL only in a temporary test Index; test both fresh/upgraded orders; record the defect without editing product behavior. No new product design decision was made.

Cleanup

Cargo and Web build output and test temporary data were removed. Review artifacts remain in artifacts/recheck/. Cargo cleanup output, verbatim:

     Removed 15157 files, 6.4GiB total
Independent #407 round-4 re-check finished. Verdict: **NO-GO**. Final head: `47f98145758e51fa36c75774ffd55efb45ce0c21`. Branch: `job/integrations-recheck`. # Connected Accounts round-4 re-check — #407 Verdict: **NO-GO**. Required fix 3 is incomplete. Review target: `c81cf1dfccbf6600d1250fdf8e0c8a0e6335eab6`. Branch: `job/integrations-recheck`. Gated test head: `17572313299b864c8316bfc228fa0e8482b03fc2`. Fetched `origin/dev`: `687ff703136e71e89f8dfba139e93cd0788b25c1`. The required fetch and merge returned `Already up to date.` No product code changed. No push or deploy. ## Required fixes | Fix | Result | Evidence | | --- | --- | --- | | Shared credentials on Mail routes and sync | PASS | Attachment and read-state return 400 at endpoint validation even with an unusable legacy copy. Both use `decrypt_account`, as do sync and legacy PATCH. Calendar uses its shared resolver. The migrated cache resume test passes. | | Legacy credentials after migration | PASS | Exact Mail nonce and ciphertext remain unchanged. The original Mail decrypt domain recovers IMAP and separate SMTP sign-ins. Calendar Basic and OAuth legacy decrypt checks pass. | | Per-account reconciliation | INCOMPLETE | New distinct Mail accounts and later Calendar links pass. Calendar-first then later Mail for the same sign-in fails and also blocks an unrelated late account. | | #626 migration dependency | Ordering PASS; combined merge still required | Exact Mail 0009 SQL at `3286cad72` applies before or after #407 on fresh and upgraded Index schemas. Both version-9 namespaces remain registered. Foreign keys and repeat application pass. The dependency's corrected membership INSERT accepts duplicate UIDs. | ## Blocking reproduction 1. Create a legacy Calendar account for a Fastmail sign-in, then migrate it. 2. Create a legacy Mail account with the same User, provider and login name. 3. Create an unrelated legacy Mail account. 4. Run startup reconciliation twice. Both calls return `AccountConflict`. Both Mail accounts remain unlinked. The old shared row and all legacy Mail account columns stay unchanged. This is not data loss, but it fails the required late-account migration contract. The Mail scan only loads rows with no shared ID match (`integrations.rs:187`). The Calendar scan skips linked rows (`:256`). It loads existing shared accounts only to accept later Calendar rows, through a Mail join (`:261–268`). It never matches a later Mail row to the shared Calendar account. The shared INSERT (`:434`) then violates the unique User/provider/email constraint. The transaction rolls back the unrelated late row too. Required correction: reconcile later Mail rows against existing shared Calendar sign-ins. Keep each service's cache identity and both sign-ins. Add an acceptance test for this reverse order. The new diagnostic asserts the observed rejection as defect evidence; it is not an acceptance requirement. Verbatim diagnostic evidence: ```text review defect: Calendar-first then later Mail = AccountConflict; 2 Mail rows remain unlinked on repeated boot ``` ## Imported test audit and diff risks No imported integrity assertion was removed or relaxed. Full-column equality still covers all six production-shaped cache tables, with 4,000 messages and 4,018 memberships. The old defect assertions became the behavior explicitly required by #407: successful legacy decrypt, later rows included, and endpoint validation after shared decrypt. The route tests deliberately invalidate the legacy copy, so they cannot pass by using it. The duplicate-membership fixture changed only its comments and migration registration; its SQL shape is unchanged. Another fixture edit sets the production-shaped folder to completed generation 1 rather than active pending generation 2. Thus the no-refetch test covers a completed live cache. The re-check ordering test retains the original pending generation 2 and compares its full cache rows before and after migration. Pending-generation provider resume is not covered. #626 remains a dependency. The reviewed c81cf1dfc writer still has the removed message-ID conflict target; the imported diagnostic correctly proves that it fails against the new schema. At 3286cad72, Mail 0009 and the corrected store adapter are both present. They must ship together. An old image needs its matching Index snapshot after #626, as DESIGN §49 I6 states. A read-only `git merge-tree` found conflicts between the two heads in Mail routes, sync, IMAP, cache exports, Plugin code, Mail Settings tests/UI and the benchmark sampler. It did not change the worktree. Keep the shared credential resolver and #626 UID behavior when resolving them. This review did not build a resolved combined tree. The remaining round-4 source diff did not expose another account-integrity blocker. Visual quality remains with the orchestrator. The shared keyboard-motion gap was already reported by the author and is outside this integrity re-check. ## Built and files Only tests and this report were added. - `crates/calternal-server/src/integrations_review.rs`: four fresh/upgraded migration-order cases and the reverse late-service diagnostic. Existing helpers and imported assertions are reused. - `crates/calternal-server/tests/review/mail_626_at_3286cad72.sql`: byte-for-byte test fixture from the dependency head. It is not registered in production. - `review-findings.md`: verdict, evidence and gates. Atomic test commits: `35cce7c46` (ordering) and `175723132` (late Mail diagnostic). Module and function comments in all touched test files were re-read. ## Gates All Cargo commands used `CARGO_PROFILE_DEV_DEBUG=line-tables-only`, `CARGO_INCREMENTAL=0`, `CARGO_BUILD_JOBS=4` and worktree `target/tmp` as `TMPDIR`. The preset `CARGO_TARGET_DIR` was unchanged. These commands exited 0 with empty stdout and stderr: - `cargo fmt --check` - `rustfmt --edition 2024 --check crates/calternal-server/src/integrations_review.rs` - `cargo clippy -p calternal-server --all-targets --quiet -- -D warnings` - `cargo clippy -p calternal-plugin-mail --all-targets --quiet -- -D warnings` `cargo test -p calternal-server --quiet -- --test-threads=1`, exit 0, complete output verbatim: ```text running 126 tests ....................................................................................... 87/126 ...........................ii......i... test result: ok. 123 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 21.47s ``` `cargo test -p calternal-plugin-mail --quiet -- --test-threads=1`, exit 0, complete output verbatim: ```text running 41 tests ...............................i.i..i.... test result: ok. 38 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 1.50s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo test -p calternal-plugin-mail --quiet migrated_production_shape_resumes_without_refetch -- --ignored --test-threads=1 --nocapture`, exit 0, complete output verbatim: ```text running 1 test review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 0.05s ``` The focused review round passed nine tests. Verbatim result: ```text test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 117 filtered out; finished in 10.01s ``` The production Web build passed to supply the Server's embedded assets. No Web source was edited, so Web type/test gates were not repeated. Raw logs remain in `artifacts/recheck/`. ## Known gaps and decisions - No old image or external provider was launched. Legacy-domain decrypt and exact retained bytes prove credential readability; a scripted provider verifies completed-cache resume. - The bounded local review round covers migrated routes, two-User isolation, rollback and migration order. It is not a full hostile-input or load audit. - The resolved #407/#626 combined binary still needs gates after conflict resolution. - No user-facing feature or hot path changed. No benchmark profile was added or measured. - Decisions: use exact pending SQL only in a temporary test Index; test both fresh/upgraded orders; record the defect without editing product behavior. No new product design decision was made. ## Cleanup Cargo and Web build output and test temporary data were removed. Review artifacts remain in `artifacts/recheck/`. Cargo cleanup output, verbatim: ```text Removed 15157 files, 6.4GiB total ```
Author
Owner

Round 5 started on job/integrations at c81cf1dfcc, base origin/dev 687ff70313. The required fetch and merge returned Already up to date. I will import the re-check tests, preserve both service cache identities for Calendar-first migration, isolate each legacy account transaction, and correct the two reported layout defects. No push or deploy.

Round 5 started on job/integrations at c81cf1dfccbf6600d1250fdf8e0c8a0e6335eab6, base origin/dev 687ff703136e71e89f8dfba139e93cd0788b25c1. The required fetch and merge returned Already up to date. I will import the re-check tests, preserve both service cache identities for Calendar-first migration, isolate each legacy account transaction, and correct the two reported layout defects. No push or deploy.
Author
Owner

Committed the visual fix as 86dedc347 and core migration support as the latest branch commit. Core migration 0011 adds an owner-bound Mail projection map and fixed per-account failure codes without changing any legacy Mail/cache column. cargo fmt --check and calternal-db clippy passed with empty output; calternal-db tests passed (17 unit tests; 16 integration tests, 1 ignored). The reverse-order regression now tests case/whitespace normalization, another User with the same sign-in, retained Calendar and SMTP secrets, shared-AAD Mail decrypt, switches, removal, and reboot idempotence. The old late-statement test expectation is updated only for the explicitly required per-account rollback contract: Mail commits while Calendar rolls back. The perf VM is unreachable (No route to host); measurements will be local.

Committed the visual fix as 86dedc347 and core migration support as the latest branch commit. Core migration 0011 adds an owner-bound Mail projection map and fixed per-account failure codes without changing any legacy Mail/cache column. cargo fmt --check and calternal-db clippy passed with empty output; calternal-db tests passed (17 unit tests; 16 integration tests, 1 ignored). The reverse-order regression now tests case/whitespace normalization, another User with the same sign-in, retained Calendar and SMTP secrets, shared-AAD Mail decrypt, switches, removal, and reboot idempotence. The old late-statement test expectation is updated only for the explicitly required per-account rollback contract: Mail commits while Calendar rolls back. The perf VM is unreachable (No route to host); measurements will be local.
Author
Owner

Round 5 integrity fix committed at e4f13d733. A later Mail sign-in now joins the owner-scoped Connected Account with the same normalized provider sign-in. The original Calendar secret and separate SMTP secret stay in the shared envelope. Mail cache IDs and every legacy account column stay unchanged. Each account commits separately; conflicts retain their rows, report a fixed code with the requesting User's cache ID, and retry on the next boot.

The acceptance test also covers trim/case matching, another User with the same sign-in, unrelated account migration, shared-AAD Mail decrypt with an unusable downgrade copy, service switches, removal, and a byte-identical reboot. Imported tests include the exact #626 SQL in both fresh/upgraded orders. No imported cache-integrity assertion was removed. The rejection diagnostic and whole-pass rollback expectation changed only where Round 5 explicitly requires the opposite behavior.

The two initial failures were new fixture errors: a duplicate address inserted before its owner changed, and a non-UUID User ID. Both fixtures are corrected.

Final Server gate output so far, verbatim:

running 128 tests
....................................................................................... 87/128
.............................ii......i...
test result: ok. 125 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 31.80s

Mail tests, verbatim:

running 41 tests
...............................i.i..i....
test result: ok. 38 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 1.93s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Server and Mail clippy passed with empty output. Calendar gates and the production review build are running. No push or deploy.

Round 5 integrity fix committed at `e4f13d733`. A later Mail sign-in now joins the owner-scoped Connected Account with the same normalized provider sign-in. The original Calendar secret and separate SMTP secret stay in the shared envelope. Mail cache IDs and every legacy account column stay unchanged. Each account commits separately; conflicts retain their rows, report a fixed code with the requesting User's cache ID, and retry on the next boot. The acceptance test also covers trim/case matching, another User with the same sign-in, unrelated account migration, shared-AAD Mail decrypt with an unusable downgrade copy, service switches, removal, and a byte-identical reboot. Imported tests include the exact #626 SQL in both fresh/upgraded orders. No imported cache-integrity assertion was removed. The rejection diagnostic and whole-pass rollback expectation changed only where Round 5 explicitly requires the opposite behavior. The two initial failures were new fixture errors: a duplicate address inserted before its owner changed, and a non-UUID User ID. Both fixtures are corrected. Final Server gate output so far, verbatim: ```text running 128 tests ....................................................................................... 87/128 .............................ii......i... test result: ok. 125 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 31.80s ``` Mail tests, verbatim: ```text running 41 tests ...............................i.i..i.... test result: ok. 38 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 1.93s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` Server and Mail clippy passed with empty output. Calendar gates and the production review build are running. No push or deploy.
Author
Owner

Round 5 validation progress at 3c7f9ce1b.

Full web gates passed before the final parent-header correction: 149 files, 1,025 tests; svelte-check 0 errors and 0 warnings. The final CSS correction hides the parent Settings sheet title as well as the chooser while nested provider setup is open. The first production capture exposed this second source of ghost text; final matrix is being rebuilt and recaptured.

One time-boxed local adversarial round passed:

PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged
Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed

Migrated cache resume proof:


running 1 test
review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands
test sync::tests::migrated_production_shape_resumes_without_refetch ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 3.26s

Performance VM access failed with No route to host. Local shared-host results (load average [25.58154296875, 24.8310546875, 23.39794921875]): Calendar-first average p50/p95 28.004/30.228 ms, three-worker burst 12.505/16.269 ms. No matching migration baseline exists. CPU and RSS plus production-shape workload results are saved for the final evidence attachment.

Generated action metadata was stale and omitted all five Connected Account APIs. Regenerated contracts/actions.json and docs/parity-matrix.md, as required by DESIGN §41: 338 operations, 320 tools, 0 adapter gaps. No new route or authorization policy. calternal-api gates passed (9 tests); Server gates are rerunning because it embeds this metadata.

Decisions: retain distinct legacy Mail cache IDs through a core owner-bound link; report safe failed account IDs per User; hide parent sheet text during nested setup; restore generated adapter parity. No push, deploy or further merge.

Round 5 validation progress at 3c7f9ce1b. Full web gates passed before the final parent-header correction: 149 files, 1,025 tests; svelte-check 0 errors and 0 warnings. The final CSS correction hides the parent Settings sheet title as well as the chooser while nested provider setup is open. The first production capture exposed this second source of ghost text; final matrix is being rebuilt and recaptured. One time-boxed local adversarial round passed: ``` PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed ``` Migrated cache resume proof: ``` running 1 test review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands test sync::tests::migrated_production_shape_resumes_without_refetch ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 3.26s ``` Performance VM access failed with No route to host. Local shared-host results (load average [25.58154296875, 24.8310546875, 23.39794921875]): Calendar-first average p50/p95 28.004/30.228 ms, three-worker burst 12.505/16.269 ms. No matching migration baseline exists. CPU and RSS plus production-shape workload results are saved for the final evidence attachment. Generated action metadata was stale and omitted all five Connected Account APIs. Regenerated contracts/actions.json and docs/parity-matrix.md, as required by DESIGN §41: 338 operations, 320 tools, 0 adapter gaps. No new route or authorization policy. calternal-api gates passed (9 tests); Server gates are rerunning because it embeds this metadata. Decisions: retain distinct legacy Mail cache IDs through a core owner-bound link; report safe failed account IDs per User; hide parent sheet text during nested setup; restore generated adapter parity. No push, deploy or further merge.
Author
Owner

Round 5 completed on job/integrations at 6ad967087b.
Base: c81cf1dfcc. One fetch and merge of origin/dev (687ff70313) completed before final gates: Already up to date. No push or deploy.

Built:

  • Calendar-first reconciliation merges later Mail for the same owner/provider and normalized sign-in into the existing Connected Account. Calendar Basic/OAuth and separate Mail/SMTP secrets remain intact. The Mail cache ID remains unchanged through an owner-bound shared-account link.
  • Each legacy account commits in its own transaction. A conflicting or damaged account leaves unrelated accounts committed. Safe failure IDs/codes are scoped to the User and retried next boot. Successful reconciliation clears its failure; reboot is a no-op.
  • Shared service controls, disconnect, Copy link and manage actions resolve the shared identity; Mail sync retains its cache identity.
  • Connected-row email retains its descenders. Provider setup reserves the shared title gap and hides chooser text and the parent Settings title behind the nested sheet.
  • Imported the independent ordering tests and exact #626 SQL fixture from review head 47f9814575. Tests cover both installation orders on fresh/upgraded Index schemas, exact cache bytes, mixed-case/space sign-ins, different service secrets, unrelated late accounts, two Users, real Mail consumers, conflict retry and no-op reboot.
  • Extended the migration performance profile. Refreshed OpenAPI/client types, generated action metadata and adapter parity.

Files:

  • apps/web/e2e/integrations-review.mjs
  • apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte
  • apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte.test.ts
  • apps/web/src/routes/settings/mail/MailSection.svelte
  • apps/web/src/routes/settings/mail/MailSection.svelte.test.ts
  • bench/integrations-migration-407.py
  • contracts/actions.json
  • contracts/openapi.json
  • crates/calternal-db/src/integrations.rs
  • crates/calternal-db/src/migrations.rs
  • crates/calternal-db/src/migrations/0011_integration_mail_links.sql
  • crates/calternal-server/src/integrations.rs
  • crates/calternal-server/src/integrations_review.rs
  • crates/calternal-server/tests/review/mail_626_at_3286cad72.sql
  • crates/plugins/mail/src/cache/store.rs
  • crates/plugins/mail/src/crypto.rs
  • crates/plugins/mail/src/routes.rs
  • docs/parity-matrix.md
  • packages/api-client/src/generated.ts
  • tests/adversarial/integrations_api.mjs

Gates:
Cargo environment: CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4, TMPDIR=/target/tmp. Preset CARGO_TARGET_DIR retained. Tests ran one crate at a time.
cargo fmt --check and per-crate cargo clippy -p <crate> --all-targets --quiet -- -D warnings for db, server, mail, calendar and api exited 0 with no output. The direct rustfmt check of the included review module also exited 0 with no output. Test output below is verbatim.

cargo test -p calternal-db --quiet -- --test-threads=1


running 17 tests
.................
test result: ok. 17 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.24s


running 17 tests
...i.............
test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 2.21s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo test -p calternal-server --quiet -- --test-threads=1


running 128 tests
....................................................................................... 87/128
.............................ii......i...
test result: ok. 125 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 25.22s

cargo test -p calternal-plugin-mail --quiet -- --test-threads=1


running 41 tests
...............................i.i..i....
test result: ok. 38 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 1.93s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo test -p calternal-plugin-calendar --quiet -- --test-threads=1


running 83 tests
...................................................................................
test result: ok. 83 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 34.37s


running 1 test
.
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.29s


running 3 tests
...
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.57s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo test -p calternal-api --quiet -- --test-threads=1


running 9 tests
.........
test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

bun run check (web), verbatim:

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/integrations/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

bun run test --maxWorkers=1 (web), verbatim summary:

 Test Files  149 passed (149)
      Tests  1025 passed (1025)
   Start at  01:01:44
   Duration  461.94s (transform 32%, environment 23%, import 20%, tests 17%, setup 8%)

API client test output, verbatim summary:

 17 pass
 0 fail
 47 expect() calls
Ran 17 tests across 1 file. [960.00ms]

Registry and parity checks, verbatim:

Action registry: 338 operations, 320 generated tools
Parity matrix: 338 API actions, 126 shortcuts, 2 static commands, 147 menu actions, 37 settings groups, 0 actions with adapter gaps

Production web and Server builds exited 0. Final device/theme evidence, verbatim:

SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-light-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-light-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-light-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-light-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-light-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-light-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-light-390.png
ALIGNMENT connected-light-390: 0.0078125px
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-light-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-light-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-light-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-light-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-dark-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-dark-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-dark-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-dark-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-dark-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-dark-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-dark-390.png
ALIGNMENT connected-dark-390: 0.0078125px
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-dark-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-dark-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-dark-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-dark-390.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-light-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-light-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-light-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-light-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-light-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-light-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-light-820.png
ALIGNMENT connected-light-820: 0.0078125px
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-light-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-light-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-light-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-light-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-dark-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-dark-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-dark-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-dark-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-dark-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-dark-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-dark-820.png
ALIGNMENT connected-dark-820: 0.0078125px
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-dark-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-dark-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-dark-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-dark-820.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-light-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-light-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-light-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-light-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-light-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-light-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-light-1440.png
ALIGNMENT connected-light-1440: 0.015625px
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-light-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-light-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-light-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-light-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-dark-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-dark-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-dark-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-dark-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-dark-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-dark-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-dark-1440.png
ALIGNMENT connected-dark-1440: 0.015625px
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-dark-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-dark-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-dark-1440.png
SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-dark-1440.png
PASS Connected Accounts review: 66 screenshots in /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts

One time-boxed local adversarial round (180-second limit), verbatim:

PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged
Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed

Migrated cache resume proof, verbatim:


running 1 test
review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands
test sync::tests::migrated_production_shape_resumes_without_refetch ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 3.26s

Performance:

Local shared build host. Perf VM: No route to host.
Baseline: docs/perf/baseline.json SHA256 ac8cfb1c38431f5340a51b8b9337602e37a8574b8821ae80f35067e289570bcd. No matching integrations migration or metadata profile; no regression comparison is available.
Migration latency excludes seeding/comparison; worker CPU/RSS includes them.
Workload | p50/p95 ms | mean CPU % | mean/peak RSS MiB
4,000 messages/4,018 memberships | 17.407/169.379 | 30.12 | 58.53/76.88
same fixture, three-worker burst | 11.831/17.318 | 28.65 | 54.92/75.15
Calendar first, two later Mail rows plus another User | 28.004/30.228 | 20.88 | 47.56/70.11
Calendar-first three-worker burst | 12.505/16.269 | 24.54 | 43.58/69.38
250-account metadata average accounts: p50/p95 60.9/161.4 ms
250-account metadata average migrationStatus: p50/p95 27/47.9 ms
250-account metadata burst accounts: p50/p95 502.3/1094.7 ms
250-account metadata burst migrationStatus: p50/p95 359/595.9 ms
Metadata server mean CPU 28.44%; mean/peak RSS 139.10/143.35 MiB. Burst concurrency 24.

Decisions:

  • A core-owned integration_mail_links table retains Mail cache IDs when the Connected Account already has a Calendar ID. Same-ID projections remain compatible. A composite owner-bound foreign key and unique shared service slot prevent cross-User or duplicate links. Migration 11 was free on fetched origin/dev.
  • Matching trims and lowercases the address/login, only within the same User and provider. It does not rewrite stored labels or secrets. A label match with a different login, multiple matches or an occupied service slot is a conflict. Incoming Mail becomes the primary/SMTP envelope fields; existing Calendar fields are preserved explicitly.
  • A separate core failure table exposes only stable account IDs and fixed codes for the requesting User. It does not contain addresses, logins, provider errors or secrets.
  • Nested provider setup hides underlying Settings text while keeping the shared glass surface and header. The title uses the existing header-reserve spacing token.
  • DESIGN §41 requires generated adapters to match the routes. The old registry omitted five existing Connected Account APIs, so regenerated it and the parity matrix. No new route or authorization policy was added.

Known gaps:

  • #626 is not merged into origin/dev. Its exact schema is applied only in test fixtures. Production must ship the matching Mail store adapter with that migration; this job does not register it independently.
  • No live external provider or full old-image downgrade was exercised. Both legacy/shared decryption, exact cache preservation, current Mail consumer routes and cursor resume were exercised locally. DESIGN §49 I6 still requires a matching Index snapshot for incompatible Plugin schema downgrades.
  • The performance VM was unreachable. Measurements are labeled local and have no matching baseline; they cannot establish a regression.
  • Screenshots are production-build captures with test-only account/status fixtures. All 390/820/1440 light/dark states are attached for the orchestrator's visual review; this job does not grant visual approval.
  • The full web suite emitted existing jsdom scrollTo/CSS warnings and passed. No existing test expectation was weakened to accept a regression. The late SQL fault test was updated only for the required per-account transaction semantics.

Comments were re-read in every changed source file; a stale whole-pass rollback comment was corrected. The imported #626 SQL fixture is byte-for-byte identical to the review branch. No review artifacts are committed.

Cleanup output, verbatim:

     Removed 18361 files, 10.5GiB total
Removed apps/web/build
Removed apps/web/.svelte-kit
Removed target/tmp

Evidence attachments:

Round 5 completed on job/integrations at 6ad967087b73b523218caa1edc2b7524ba6aca85. Base: c81cf1dfccbf6600d1250fdf8e0c8a0e6335eab6. One fetch and merge of origin/dev (687ff703136e71e89f8dfba139e93cd0788b25c1) completed before final gates: Already up to date. No push or deploy. Built: - Calendar-first reconciliation merges later Mail for the same owner/provider and normalized sign-in into the existing Connected Account. Calendar Basic/OAuth and separate Mail/SMTP secrets remain intact. The Mail cache ID remains unchanged through an owner-bound shared-account link. - Each legacy account commits in its own transaction. A conflicting or damaged account leaves unrelated accounts committed. Safe failure IDs/codes are scoped to the User and retried next boot. Successful reconciliation clears its failure; reboot is a no-op. - Shared service controls, disconnect, Copy link and manage actions resolve the shared identity; Mail sync retains its cache identity. - Connected-row email retains its descenders. Provider setup reserves the shared title gap and hides chooser text and the parent Settings title behind the nested sheet. - Imported the independent ordering tests and exact #626 SQL fixture from review head 47f98145758e51fa36c75774ffd55efb45ce0c21. Tests cover both installation orders on fresh/upgraded Index schemas, exact cache bytes, mixed-case/space sign-ins, different service secrets, unrelated late accounts, two Users, real Mail consumers, conflict retry and no-op reboot. - Extended the migration performance profile. Refreshed OpenAPI/client types, generated action metadata and adapter parity. Files: - apps/web/e2e/integrations-review.mjs - apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte - apps/web/src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte.test.ts - apps/web/src/routes/settings/mail/MailSection.svelte - apps/web/src/routes/settings/mail/MailSection.svelte.test.ts - bench/integrations-migration-407.py - contracts/actions.json - contracts/openapi.json - crates/calternal-db/src/integrations.rs - crates/calternal-db/src/migrations.rs - crates/calternal-db/src/migrations/0011_integration_mail_links.sql - crates/calternal-server/src/integrations.rs - crates/calternal-server/src/integrations_review.rs - crates/calternal-server/tests/review/mail_626_at_3286cad72.sql - crates/plugins/mail/src/cache/store.rs - crates/plugins/mail/src/crypto.rs - crates/plugins/mail/src/routes.rs - docs/parity-matrix.md - packages/api-client/src/generated.ts - tests/adversarial/integrations_api.mjs Gates: Cargo environment: CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4, TMPDIR=<worktree>/target/tmp. Preset CARGO_TARGET_DIR retained. Tests ran one crate at a time. `cargo fmt --check` and per-crate `cargo clippy -p <crate> --all-targets --quiet -- -D warnings` for db, server, mail, calendar and api exited 0 with no output. The direct rustfmt check of the included review module also exited 0 with no output. Test output below is verbatim. `cargo test -p calternal-db --quiet -- --test-threads=1` ```text running 17 tests ................. test result: ok. 17 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.24s running 17 tests ...i............. test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 2.21s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo test -p calternal-server --quiet -- --test-threads=1` ```text running 128 tests ....................................................................................... 87/128 .............................ii......i... test result: ok. 125 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 25.22s ``` `cargo test -p calternal-plugin-mail --quiet -- --test-threads=1` ```text running 41 tests ...............................i.i..i.... test result: ok. 38 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 1.93s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo test -p calternal-plugin-calendar --quiet -- --test-threads=1` ```text running 83 tests ................................................................................... test result: ok. 83 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 34.37s running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.29s running 3 tests ... test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.57s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo test -p calternal-api --quiet -- --test-threads=1` ```text running 9 tests ......... test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `bun run check` (web), verbatim: ```text $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/integrations/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` `bun run test --maxWorkers=1` (web), verbatim summary: ```text Test Files 149 passed (149) Tests 1025 passed (1025) Start at 01:01:44 Duration 461.94s (transform 32%, environment 23%, import 20%, tests 17%, setup 8%) ``` API client test output, verbatim summary: ```text 17 pass 0 fail 47 expect() calls Ran 17 tests across 1 file. [960.00ms] ``` Registry and parity checks, verbatim: ```text Action registry: 338 operations, 320 generated tools Parity matrix: 338 API actions, 126 shortcuts, 2 static commands, 147 menu actions, 37 settings groups, 0 actions with adapter gaps ``` Production web and Server builds exited 0. Final device/theme evidence, verbatim: ```text SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-light-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-light-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-light-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-light-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-light-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-light-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-light-390.png ALIGNMENT connected-light-390: 0.0078125px SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-light-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-light-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-light-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-light-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-dark-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-dark-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-dark-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-dark-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-dark-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-dark-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-dark-390.png ALIGNMENT connected-dark-390: 0.0078125px SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-dark-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-dark-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-dark-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-dark-390.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-light-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-light-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-light-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-light-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-light-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-light-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-light-820.png ALIGNMENT connected-light-820: 0.0078125px SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-light-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-light-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-light-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-light-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-dark-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-dark-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-dark-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-dark-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-dark-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-dark-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-dark-820.png ALIGNMENT connected-dark-820: 0.0078125px SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-dark-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-dark-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-dark-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-dark-820.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-light-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-light-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-light-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-light-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-light-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-light-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-light-1440.png ALIGNMENT connected-light-1440: 0.015625px SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-light-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-light-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-light-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-light-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/chooser-dark-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-icloud-dark-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-gmail-dark-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-fastmail-dark-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-yahoo-dark-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/provider-other-dark-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/service-checklist-dark-1440.png ALIGNMENT connected-dark-1440: 0.015625px SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/connected-dark-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/mail-connect-dark-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/calendar-add-dark-1440.png SCREENSHOT /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts/location-dark-1440.png PASS Connected Accounts review: 66 screenshots in /home/kayg/Developer/calternal-wt/integrations/artifacts/connected-accounts ``` One time-boxed local adversarial round (180-second limit), verbatim: ```text PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed ``` Migrated cache resume proof, verbatim: ```text running 1 test review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands test sync::tests::migrated_production_shape_resumes_without_refetch ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 3.26s ``` Performance: ```text Local shared build host. Perf VM: No route to host. Baseline: docs/perf/baseline.json SHA256 ac8cfb1c38431f5340a51b8b9337602e37a8574b8821ae80f35067e289570bcd. No matching integrations migration or metadata profile; no regression comparison is available. Migration latency excludes seeding/comparison; worker CPU/RSS includes them. Workload | p50/p95 ms | mean CPU % | mean/peak RSS MiB 4,000 messages/4,018 memberships | 17.407/169.379 | 30.12 | 58.53/76.88 same fixture, three-worker burst | 11.831/17.318 | 28.65 | 54.92/75.15 Calendar first, two later Mail rows plus another User | 28.004/30.228 | 20.88 | 47.56/70.11 Calendar-first three-worker burst | 12.505/16.269 | 24.54 | 43.58/69.38 250-account metadata average accounts: p50/p95 60.9/161.4 ms 250-account metadata average migrationStatus: p50/p95 27/47.9 ms 250-account metadata burst accounts: p50/p95 502.3/1094.7 ms 250-account metadata burst migrationStatus: p50/p95 359/595.9 ms Metadata server mean CPU 28.44%; mean/peak RSS 139.10/143.35 MiB. Burst concurrency 24. ``` Decisions: - A core-owned `integration_mail_links` table retains Mail cache IDs when the Connected Account already has a Calendar ID. Same-ID projections remain compatible. A composite owner-bound foreign key and unique shared service slot prevent cross-User or duplicate links. Migration 11 was free on fetched origin/dev. - Matching trims and lowercases the address/login, only within the same User and provider. It does not rewrite stored labels or secrets. A label match with a different login, multiple matches or an occupied service slot is a conflict. Incoming Mail becomes the primary/SMTP envelope fields; existing Calendar fields are preserved explicitly. - A separate core failure table exposes only stable account IDs and fixed codes for the requesting User. It does not contain addresses, logins, provider errors or secrets. - Nested provider setup hides underlying Settings text while keeping the shared glass surface and header. The title uses the existing header-reserve spacing token. - DESIGN §41 requires generated adapters to match the routes. The old registry omitted five existing Connected Account APIs, so regenerated it and the parity matrix. No new route or authorization policy was added. Known gaps: - #626 is not merged into origin/dev. Its exact schema is applied only in test fixtures. Production must ship the matching Mail store adapter with that migration; this job does not register it independently. - No live external provider or full old-image downgrade was exercised. Both legacy/shared decryption, exact cache preservation, current Mail consumer routes and cursor resume were exercised locally. DESIGN §49 I6 still requires a matching Index snapshot for incompatible Plugin schema downgrades. - The performance VM was unreachable. Measurements are labeled local and have no matching baseline; they cannot establish a regression. - Screenshots are production-build captures with test-only account/status fixtures. All 390/820/1440 light/dark states are attached for the orchestrator's visual review; this job does not grant visual approval. - The full web suite emitted existing jsdom scrollTo/CSS warnings and passed. No existing test expectation was weakened to accept a regression. The late SQL fault test was updated only for the required per-account transaction semantics. Comments were re-read in every changed source file; a stale whole-pass rollback comment was corrected. The imported #626 SQL fixture is byte-for-byte identical to the review branch. No review artifacts are committed. Cleanup output, verbatim: ```text Removed 18361 files, 10.5GiB total Removed apps/web/build Removed apps/web/.svelte-kit Removed target/tmp ``` Evidence attachments: - [screenshots.zip](https://git.kayg.org/attachments/bedcfddb-9ff7-4853-8cb2-67f21f02ee2e) - [gate-evidence.zip](https://git.kayg.org/attachments/f282179f-8f79-44fe-8366-a82d488cc906) - [provider-fastmail-light-390.png](https://git.kayg.org/attachments/9e18a756-b540-42ec-bef5-4823efba39cc) - [provider-fastmail-dark-390.png](https://git.kayg.org/attachments/6db546c8-4d59-49dc-becc-cd6d6b24a09a) - [provider-fastmail-light-820.png](https://git.kayg.org/attachments/2746702f-c978-478b-b62d-90c707814654) - [provider-fastmail-dark-820.png](https://git.kayg.org/attachments/fa2d86da-6daf-4fed-9a96-4663425d1897) - [provider-fastmail-light-1440.png](https://git.kayg.org/attachments/50057175-92da-41c8-88a0-add578187773) - [provider-fastmail-dark-1440.png](https://git.kayg.org/attachments/84d91628-0e8c-4376-9ebe-25ba7fec48a8) - [connected-light-390.png](https://git.kayg.org/attachments/5eeebf0a-d228-487c-aec3-ba1a66765562) - [connected-dark-390.png](https://git.kayg.org/attachments/05dc2b72-af3c-4263-b44b-e0bcfb0e7a40) - [connected-light-820.png](https://git.kayg.org/attachments/da653e50-289c-4734-bfb8-782561cb4256) - [connected-dark-820.png](https://git.kayg.org/attachments/9d29b114-81fe-41fd-b064-5bbafa521175) - [connected-light-1440.png](https://git.kayg.org/attachments/2293f316-f3f6-4d74-9f29-32a1e35f6fed) - [connected-dark-1440.png](https://git.kayg.org/attachments/f259b0ad-55ff-4f84-a4f3-05b79d0ff9cd) - [mail-connect-light-390.png](https://git.kayg.org/attachments/b8f83306-6124-4589-8db8-3d129bfc7d25) - [mail-connect-dark-390.png](https://git.kayg.org/attachments/1757fe16-69a6-4aaf-95b8-c696392b5a2e) - [mail-connect-light-820.png](https://git.kayg.org/attachments/8d0452e1-8231-4383-a106-ed0d4a34070f) - [mail-connect-dark-820.png](https://git.kayg.org/attachments/42c4d2c7-73f5-4d40-863e-5fc74809c90e) - [mail-connect-light-1440.png](https://git.kayg.org/attachments/4b0078b1-57fe-421f-adff-cde6325d2f82) - [mail-connect-dark-1440.png](https://git.kayg.org/attachments/152fb5af-fee0-4f4a-ab3c-6c5a2d09bdc7)
Author
Owner

Second independent re-check started for #407. Branch: job/integrations-review-round5. Base/reviewed author head: 6ad967087b. One fetch and merge of origin/dev completed: Already up to date. Tests only; verify imported assertions, Calendar-first merge, per-account rollback/retry, reboot, shared credential consumers, downgrade bytes and exact #626 ordering. No push or deploy.

Second independent re-check started for #407. Branch: job/integrations-review-round5. Base/reviewed author head: 6ad967087b73b523218caa1edc2b7524ba6aca85. One fetch and merge of origin/dev completed: Already up to date. Tests only; verify imported assertions, Calendar-first merge, per-account rollback/retry, reboot, shared credential consumers, downgrade bytes and exact #626 ordering. No push or deploy.
Author
Owner

Independent Round 5 finding: the original Fastmail Calendar-first merge is fixed, but the new matcher rejects unrelated Other Mail accounts that share a local login name.

Reproduction in diagnostic_distinct_other_servers_with_same_login_conflict: seed two valid legacy Mail rows for one User, email reader@alpha.example at imap.alpha.example and email reader@beta.example at imap.beta.example, both with local login reader, distinct IDs and creation times. Reconcile twice. Both calls return AccountConflict. Only one Connected Account exists; the second Mail row remains unlinked and has a fixed account_conflict failure entry. All legacy Mail columns remain unchanged.

Evidence: cargo test -p calternal-server --quiet -- --test-threads=1 exited 0: test result: ok. 127 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 40.05s. The diagnostic asserts the observed defect, not desired acceptance behavior. No existing test expectation changed in this review.

Cause: integrations.rs:320-340 loads all shared rows for the User/provider and treats normalized username equality as a match without comparing custom server identity. The Mail service-slot occupancy check then rejects the second unrelated account. Round 4 inserted separate Mail rows and did not apply that matcher to incoming Mail. This violates the required unrelated-account migration contract. Tests-only review: product behavior is unchanged. Final gates and loopback round are still in progress.

Independent Round 5 finding: the original Fastmail Calendar-first merge is fixed, but the new matcher rejects unrelated Other Mail accounts that share a local login name. Reproduction in `diagnostic_distinct_other_servers_with_same_login_conflict`: seed two valid legacy Mail rows for one User, email `reader@alpha.example` at `imap.alpha.example` and email `reader@beta.example` at `imap.beta.example`, both with local login `reader`, distinct IDs and creation times. Reconcile twice. Both calls return AccountConflict. Only one Connected Account exists; the second Mail row remains unlinked and has a fixed account_conflict failure entry. All legacy Mail columns remain unchanged. Evidence: `cargo test -p calternal-server --quiet -- --test-threads=1` exited 0: `test result: ok. 127 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 40.05s`. The diagnostic asserts the observed defect, not desired acceptance behavior. No existing test expectation changed in this review. Cause: integrations.rs:320-340 loads all shared rows for the User/provider and treats normalized username equality as a match without comparing custom server identity. The Mail service-slot occupancy check then rejects the second unrelated account. Round 4 inserted separate Mail rows and did not apply that matcher to incoming Mail. This violates the required unrelated-account migration contract. Tests-only review: product behavior is unchanged. Final gates and loopback round are still in progress.
Author
Owner

Independent second re-check finished. Verdict: NO-GO.

Final head: cd79e2a660f88ea98c90b52222e9323f5cb92268. Working tree clean. Test changes: 48167e0ec3e912535540244e2160aa7c50e52d39; report commit: cd79e2a660f88ea98c90b52222e9323f5cb92268. No push or deploy.

#407 second re-check: NO-GO

The original Calendar-first Fastmail defect is fixed. A new matching defect blocks an unrelated Other account. Product code was not changed.

Reviewed author head: 6ad967087b73b523218caa1edc2b7524ba6aca85.
Gated test head: 48167e0ec3e912535540244e2160aa7c50e52d39.
Branch: job/integrations-review-round5.
The single required fetch and merge used origin/dev at 687ff703136e71e89f8dfba139e93cd0788b25c1. Output: Already up to date. No push or deploy.

Results

Requirement Result Evidence
Calendar first, then Mail with the same sign-in PASS One shared row has Mail and Calendar, all three Mail/SMTP/Calendar passwords, stable cache IDs, and another User stays separate.
An unrelated account in the same pass migrates PASS for the original Fastmail case; FAIL for Other The original acceptance test passes. Two Other Mail servers with the same local login leave the second account unlinked.
Failure isolation and retry PASS Injected Calendar statement failure keeps Mail committed. Damaged Mail keeps Calendar committed. Repairing Mail clears the failure without rewriting Calendar.
Reboot is a no-op PASS Shared rows, links and status stay unchanged. The added test closes both pools, reopens the Index and checks all six account/link/status tables.
Shared credential consumers PASS Attachment and read-state reach endpoint validation with an unusable legacy copy. Mail routes and sync use decrypt_account; its AAD uses the shared ID.
Legacy credentials for downgrade PASS Original Mail and SMTP secrets decrypt from exact retained bytes. Calendar Basic and OAuth checks still pass.
#626 order PASS within the test fixture Exact SQL applies in both orders on fresh and upgraded Index schemas. Namespace versions, foreign keys, cache bytes and repeated application pass.

Required fix

crates/calternal-server/src/integrations.rs:320–340 matches every shared account for the User/provider by normalized login. It does not use the custom server to distinguish Other sign-ins. The service-slot check then rejects the second Mail account.

The new diagnostic creates valid legacy accounts:

  • reader@alpha.example, server imap.alpha.example, login reader.
  • reader@beta.example, server imap.beta.example, login reader.

Reconciliation twice returns AccountConflict. Only one Connected Account exists. The second account remains unlinked and has an account_conflict entry. Every legacy Mail column remains unchanged. Round 4 did not apply this shared-account matcher to incoming Mail, so this is new in Round 5.

Keep distinct Other server sign-ins separate. Retain the named-provider merge, each service's cache identity and every credential. After the fix, change this diagnostic to require both accounts to migrate and an unchanged reboot. Its current assertions record the defect; they do not define accepted behavior.

Verbatim evidence:

review new defect: distinct Other servers with local login reader = AccountConflict; second unrelated Mail account stays unlinked on repeated boot
review Round 5: damaged Mail isolated, Calendar committed, repair retried, failures cleared, reboot unchanged

Imported test audit

Compared independent head 47f98145758e51fa36c75774ffd55efb45ce0c21, import 1d8d1d6dc, and the reviewed author head. The exact #626 SQL and production-shape SQL fixtures are byte-identical. Full-column equality still covers six cache tables with 4,000 messages and 4,018 memberships. The shared/legacy secret assertions remain.

The old reverse-order rejection diagnostic was replaced with later_mail_merges_with_existing_shared_calendar. Its acceptance checks are stronger. The old whole-pass rollback assertion changed to one committed Mail account because Round 5 explicitly requires per-account isolation. No imported cache-integrity assertion was weakened. This review changed no existing expectation.

The source scan checked owner-bound Mail links, shared AAD resolution, toggles, disconnect, sync queue IDs, status failure IDs and UI references to the shared ID. No other new integrity blocker was found. This job adds no migration; fetched origin/dev has no conflicting core 0011.

Built and files

  • crates/calternal-server/src/integrations_review.rs: two independent tests for repaired credential retry, reopened-Index idempotence, and the distinct-server diagnostic. Reuses existing fixture and snapshot helpers.
  • review-findings.md: this report.

Module and function doc comments were re-read. No dependencies or versions changed.

Gates

All Cargo commands used CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4 and worktree target/tmp for TMPDIR. The preset CARGO_TARGET_DIR was retained. Final tests ran one crate at a time. The final snapshot/build runs used RUSTC_WRAPPER= because the shared sccache server referenced another job's deleted temp directory.

These commands exited 0 with empty stdout and stderr:

  • cargo fmt --check
  • rustfmt --edition 2024 --check crates/calternal-server/src/integrations_review.rs
  • cargo clippy -p calternal-server --all-targets --quiet -- -D warnings
  • cargo clippy -p calternal-plugin-mail --all-targets --quiet -- -D warnings

cargo test -p calternal-server --quiet -- --test-threads=1, exit 0, complete output verbatim:


running 130 tests
....................................................................................... 87/130
...............................ii......i...
test result: ok. 127 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 31.20s

cargo test -p calternal-plugin-mail --quiet -- --test-threads=1, exit 0, complete output verbatim:


running 41 tests
...............................i.i..i....
test result: ok. 38 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 4.21s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo test -p calternal-server --quiet independent_review -- --test-threads=1 --nocapture (with snapshot directory), exit 0, complete output verbatim:


running 13 tests
.review completed marker: later legacy account appears in Connected Accounts
.review Round 5: damaged Mail isolated, Calendar committed, repair retried, failures cleared, reboot unchanged
.review new defect: distinct Other servers with local login reader = AccountConflict; second unrelated Mail account stays unlinked on repeated boot
...INTEGRATION_LATE_MAIL_PROFILE {"accounts":4,"messages":1,"migration_us":7418}
.review two-User matrix: owner list=1, other list=0, foreign PATCH=404, DELETE=404, owner row unchanged
.review #626 ordering: fresh=true mail_first=true passed
review #626 ordering: fresh=true mail_first=false passed
review #626 ordering: fresh=false mail_first=true passed
review #626 ordering: fresh=false mail_first=false passed
.review real loopback: attachment=400 (no provider IO)
.review real loopback: read-state=400 (no provider IO)
..review #626 compatibility: old membership conflict target is rejected
review local migration elapsed_us=5395
INTEGRATION_MIGRATION_PROFILE {"memberships":4018,"messages":4000,"migration_us":5395}
review mail_messages: rows=4000 before=e2781e1486c45bc0 after=e2781e1486c45bc0
review mail_memberships: rows=4018 before=19c85a1d271200c3 after=19c85a1d271200c3
review mail_folders: rows=1 before=96a48d9dfc5e91c9 after=96a48d9dfc5e91c9
review mail_sync_generations: rows=2 before=3030700ccc2850ff after=3030700ccc2850ff
review calendar_calendars: rows=1 before=92289d809d596cc7 after=92289d809d596cc7
review calendar_events: rows=1 before=c74fd5924eb5ec92 after=c74fd5924eb5ec92
.
test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 117 filtered out; finished in 3.51s

cargo test -p calternal-plugin-mail --quiet migrated_production_shape_resumes_without_refetch -- --ignored --test-threads=1 --nocapture (with snapshot path), exit 0, complete output verbatim:


running 1 test
review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands
.
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 13.57s

The first ignored resume invocation omitted the snapshot setting. The first snapshot export used a directory that did not exist. Both failed in test setup and passed after the settings and directory were supplied. The first Server build failed in shared sccache with a deleted temp path. Raw attempt logs remain in artifacts/integrations-recheck/.

The production Web build (bun run --cwd apps/web build) and production Server build (cargo build -p calternal-server --quiet) exited 0. The Server build had empty stdout and stderr.

One time-boxed local API round used the production Server and SPA (timeout 180s bun tests/adversarial/integrations_api.mjs), exit 0. Output verbatim:

PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged
Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed

No additional non-SLOW API finding appeared in this round. It uses inert credentials and no provider sign-in.

Known gaps

  • No external provider or old image was launched. Exact retained bytes and both encryption domains were checked.
  • #626 is tested with its exact pending SQL, not a resolved combined production binary. Its migration and corrected store adapter must ship together. An old image needs its matching Index snapshot after #626.
  • The provider resume test covers a completed live generation. Ordering tests check pending-generation cache bytes. Pending-generation provider resume is not covered.
  • No UI source changed. Web type/test gates and screenshots were not repeated. A production Web build supplies the Server's embedded assets.
  • No feature or hot path changed. No performance profile was added or run.

Decisions

Reuse the existing fixture helpers. Check no-op boot through an actual close/reopen of the Index. Record the wrong rejection as a diagnostic without changing product behavior. No new product design decision was made.

Cleanup

Cargo output, Web build output, snapshots and test runtime directories were removed. Review logs remain in artifacts/integrations-recheck/. Cargo cleanup output, verbatim:

     Removed 15535 files, 7.9GiB total
Independent second re-check finished. Verdict: **NO-GO**. Final head: `cd79e2a660f88ea98c90b52222e9323f5cb92268`. Working tree clean. Test changes: `48167e0ec3e912535540244e2160aa7c50e52d39`; report commit: `cd79e2a660f88ea98c90b52222e9323f5cb92268`. No push or deploy. # #407 second re-check: NO-GO The original Calendar-first Fastmail defect is fixed. A new matching defect blocks an unrelated Other account. Product code was not changed. Reviewed author head: `6ad967087b73b523218caa1edc2b7524ba6aca85`. Gated test head: `48167e0ec3e912535540244e2160aa7c50e52d39`. Branch: `job/integrations-review-round5`. The single required fetch and merge used `origin/dev` at `687ff703136e71e89f8dfba139e93cd0788b25c1`. Output: `Already up to date.` No push or deploy. ## Results | Requirement | Result | Evidence | | --- | --- | --- | | Calendar first, then Mail with the same sign-in | PASS | One shared row has Mail and Calendar, all three Mail/SMTP/Calendar passwords, stable cache IDs, and another User stays separate. | | An unrelated account in the same pass migrates | PASS for the original Fastmail case; FAIL for Other | The original acceptance test passes. Two Other Mail servers with the same local login leave the second account unlinked. | | Failure isolation and retry | PASS | Injected Calendar statement failure keeps Mail committed. Damaged Mail keeps Calendar committed. Repairing Mail clears the failure without rewriting Calendar. | | Reboot is a no-op | PASS | Shared rows, links and status stay unchanged. The added test closes both pools, reopens the Index and checks all six account/link/status tables. | | Shared credential consumers | PASS | Attachment and read-state reach endpoint validation with an unusable legacy copy. Mail routes and sync use `decrypt_account`; its AAD uses the shared ID. | | Legacy credentials for downgrade | PASS | Original Mail and SMTP secrets decrypt from exact retained bytes. Calendar Basic and OAuth checks still pass. | | #626 order | PASS within the test fixture | Exact SQL applies in both orders on fresh and upgraded Index schemas. Namespace versions, foreign keys, cache bytes and repeated application pass. | ## Required fix `crates/calternal-server/src/integrations.rs:320–340` matches every shared account for the User/provider by normalized login. It does not use the custom server to distinguish Other sign-ins. The service-slot check then rejects the second Mail account. The new diagnostic creates valid legacy accounts: - `reader@alpha.example`, server `imap.alpha.example`, login `reader`. - `reader@beta.example`, server `imap.beta.example`, login `reader`. Reconciliation twice returns `AccountConflict`. Only one Connected Account exists. The second account remains unlinked and has an `account_conflict` entry. Every legacy Mail column remains unchanged. Round 4 did not apply this shared-account matcher to incoming Mail, so this is new in Round 5. Keep distinct Other server sign-ins separate. Retain the named-provider merge, each service's cache identity and every credential. After the fix, change this diagnostic to require both accounts to migrate and an unchanged reboot. Its current assertions record the defect; they do not define accepted behavior. Verbatim evidence: ```text review new defect: distinct Other servers with local login reader = AccountConflict; second unrelated Mail account stays unlinked on repeated boot review Round 5: damaged Mail isolated, Calendar committed, repair retried, failures cleared, reboot unchanged ``` ## Imported test audit Compared independent head `47f98145758e51fa36c75774ffd55efb45ce0c21`, import `1d8d1d6dc`, and the reviewed author head. The exact #626 SQL and production-shape SQL fixtures are byte-identical. Full-column equality still covers six cache tables with 4,000 messages and 4,018 memberships. The shared/legacy secret assertions remain. The old reverse-order rejection diagnostic was replaced with `later_mail_merges_with_existing_shared_calendar`. Its acceptance checks are stronger. The old whole-pass rollback assertion changed to one committed Mail account because Round 5 explicitly requires per-account isolation. No imported cache-integrity assertion was weakened. This review changed no existing expectation. The source scan checked owner-bound Mail links, shared AAD resolution, toggles, disconnect, sync queue IDs, status failure IDs and UI references to the shared ID. No other new integrity blocker was found. This job adds no migration; fetched `origin/dev` has no conflicting core 0011. ## Built and files - `crates/calternal-server/src/integrations_review.rs`: two independent tests for repaired credential retry, reopened-Index idempotence, and the distinct-server diagnostic. Reuses existing fixture and snapshot helpers. - `review-findings.md`: this report. Module and function doc comments were re-read. No dependencies or versions changed. ## Gates All Cargo commands used `CARGO_PROFILE_DEV_DEBUG=line-tables-only`, `CARGO_INCREMENTAL=0`, `CARGO_BUILD_JOBS=4` and worktree `target/tmp` for `TMPDIR`. The preset `CARGO_TARGET_DIR` was retained. Final tests ran one crate at a time. The final snapshot/build runs used `RUSTC_WRAPPER=` because the shared sccache server referenced another job's deleted temp directory. These commands exited 0 with empty stdout and stderr: - `cargo fmt --check` - `rustfmt --edition 2024 --check crates/calternal-server/src/integrations_review.rs` - `cargo clippy -p calternal-server --all-targets --quiet -- -D warnings` - `cargo clippy -p calternal-plugin-mail --all-targets --quiet -- -D warnings` `cargo test -p calternal-server --quiet -- --test-threads=1`, exit 0, complete output verbatim: ```text running 130 tests ....................................................................................... 87/130 ...............................ii......i... test result: ok. 127 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 31.20s ``` `cargo test -p calternal-plugin-mail --quiet -- --test-threads=1`, exit 0, complete output verbatim: ```text running 41 tests ...............................i.i..i.... test result: ok. 38 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 4.21s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo test -p calternal-server --quiet independent_review -- --test-threads=1 --nocapture (with snapshot directory)`, exit 0, complete output verbatim: ```text running 13 tests .review completed marker: later legacy account appears in Connected Accounts .review Round 5: damaged Mail isolated, Calendar committed, repair retried, failures cleared, reboot unchanged .review new defect: distinct Other servers with local login reader = AccountConflict; second unrelated Mail account stays unlinked on repeated boot ...INTEGRATION_LATE_MAIL_PROFILE {"accounts":4,"messages":1,"migration_us":7418} .review two-User matrix: owner list=1, other list=0, foreign PATCH=404, DELETE=404, owner row unchanged .review #626 ordering: fresh=true mail_first=true passed review #626 ordering: fresh=true mail_first=false passed review #626 ordering: fresh=false mail_first=true passed review #626 ordering: fresh=false mail_first=false passed .review real loopback: attachment=400 (no provider IO) .review real loopback: read-state=400 (no provider IO) ..review #626 compatibility: old membership conflict target is rejected review local migration elapsed_us=5395 INTEGRATION_MIGRATION_PROFILE {"memberships":4018,"messages":4000,"migration_us":5395} review mail_messages: rows=4000 before=e2781e1486c45bc0 after=e2781e1486c45bc0 review mail_memberships: rows=4018 before=19c85a1d271200c3 after=19c85a1d271200c3 review mail_folders: rows=1 before=96a48d9dfc5e91c9 after=96a48d9dfc5e91c9 review mail_sync_generations: rows=2 before=3030700ccc2850ff after=3030700ccc2850ff review calendar_calendars: rows=1 before=92289d809d596cc7 after=92289d809d596cc7 review calendar_events: rows=1 before=c74fd5924eb5ec92 after=c74fd5924eb5ec92 . test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 117 filtered out; finished in 3.51s ``` `cargo test -p calternal-plugin-mail --quiet migrated_production_shape_resumes_without_refetch -- --ignored --test-threads=1 --nocapture (with snapshot path)`, exit 0, complete output verbatim: ```text running 1 test review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 13.57s ``` The first ignored resume invocation omitted the snapshot setting. The first snapshot export used a directory that did not exist. Both failed in test setup and passed after the settings and directory were supplied. The first Server build failed in shared sccache with a deleted temp path. Raw attempt logs remain in `artifacts/integrations-recheck/`. The production Web build (`bun run --cwd apps/web build`) and production Server build (`cargo build -p calternal-server --quiet`) exited 0. The Server build had empty stdout and stderr. One time-boxed local API round used the production Server and SPA (`timeout 180s bun tests/adversarial/integrations_api.mjs`), exit 0. Output verbatim: ```text PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed ``` No additional non-SLOW API finding appeared in this round. It uses inert credentials and no provider sign-in. ## Known gaps - No external provider or old image was launched. Exact retained bytes and both encryption domains were checked. - #626 is tested with its exact pending SQL, not a resolved combined production binary. Its migration and corrected store adapter must ship together. An old image needs its matching Index snapshot after #626. - The provider resume test covers a completed live generation. Ordering tests check pending-generation cache bytes. Pending-generation provider resume is not covered. - No UI source changed. Web type/test gates and screenshots were not repeated. A production Web build supplies the Server's embedded assets. - No feature or hot path changed. No performance profile was added or run. ## Decisions Reuse the existing fixture helpers. Check no-op boot through an actual close/reopen of the Index. Record the wrong rejection as a diagnostic without changing product behavior. No new product design decision was made. ## Cleanup Cargo output, Web build output, snapshots and test runtime directories were removed. Review logs remain in `artifacts/integrations-recheck/`. Cargo cleanup output, verbatim: ```text Removed 15535 files, 7.9GiB total ```
Author
Owner

Starting Round 6 on job/integrations at base/head 6ad967087b. Read the latest NO-GO and review-findings.md at cd79e2a66. I will import the retry/reopened-Index tests and turn the distinct Other server diagnostic into acceptance coverage, then use one endpoint-aware sign-in identity for creation and boot reconciliation. No push or deploy.

Starting Round 6 on job/integrations at base/head 6ad967087b73b523218caa1edc2b7524ba6aca85. Read the latest NO-GO and review-findings.md at cd79e2a66. I will import the retry/reopened-Index tests and turn the distinct Other server diagnostic into acceptance coverage, then use one endpoint-aware sign-in identity for creation and boot reconciliation. No push or deploy.
Author
Owner

Finding: the shared account UNIQUE(owner_id, provider, email) also rejects distinct Other endpoints with one email label. Round 6 adds a core schema upgrade that preserves account/credential bytes and saves/restores the owner-bound Mail links while rebuilding the table with foreign keys enabled. Named-provider labels retain their partial unique index. One sign_in_identity function now defines endpoint/login matching for creation and reconciliation. Decision: Other usernames retain case; IMAP and SMTP host/port/login are identity fields; CalDAV host/port/login identifies Calendar. Do not infer identity across distinct Other protocols from a login alone. This explicitly changes legacy_accounts_upgrade_losslessly_and_only_once: its imap.custom.example and dav.custom.example rows now remain separate, with unchanged caches and secrets. The imported diagnostic alone changes from defect-recording rejection to required acceptance; retry/reopened-Index and named-provider Calendar-first tests remain intact.

Finding: the shared account UNIQUE(owner_id, provider, email) also rejects distinct Other endpoints with one email label. Round 6 adds a core schema upgrade that preserves account/credential bytes and saves/restores the owner-bound Mail links while rebuilding the table with foreign keys enabled. Named-provider labels retain their partial unique index. One sign_in_identity function now defines endpoint/login matching for creation and reconciliation. Decision: Other usernames retain case; IMAP and SMTP host/port/login are identity fields; CalDAV host/port/login identifies Calendar. Do not infer identity across distinct Other protocols from a login alone. This explicitly changes legacy_accounts_upgrade_losslessly_and_only_once: its imap.custom.example and dav.custom.example rows now remain separate, with unchanged caches and secrets. The imported diagnostic alone changes from defect-recording rejection to required acceptance; retry/reopened-Index and named-provider Calendar-first tests remain intact.
Author
Owner

Progress: committed the endpoint-label schema slice as 9923ccb22. Populated migration preserves encrypted bytes and Mail links, and foreign-key ownership/delete checks pass. cargo fmt --check and cargo clippy -p calternal-db --all-targets --quiet -- -D warnings exited 0 with empty output. Database test output (verbatim result lines): test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.22s / test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 1.78s. Server clippy also exited 0 with empty output. Web check: svelte-check found 0 errors and 0 warnings. Web test: Test Files 149 passed (149); Tests 1025 passed (1025). The full Server test run is in progress. Perf VM SSH failed with No route to host; measurements will be labelled local.

Progress: committed the endpoint-label schema slice as 9923ccb22. Populated migration preserves encrypted bytes and Mail links, and foreign-key ownership/delete checks pass. cargo fmt --check and cargo clippy -p calternal-db --all-targets --quiet -- -D warnings exited 0 with empty output. Database test output (verbatim result lines): test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.22s / test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 1.78s. Server clippy also exited 0 with empty output. Web check: svelte-check found 0 errors and 0 warnings. Web test: Test Files 149 passed (149); Tests 1025 passed (1025). The full Server test run is in progress. Perf VM SSH failed with No route to host; measurements will be labelled local.
Author
Owner

Finding: local performance profile completed with load average 21.12 before and 19.67 after; perf VM was unreachable. Two Other servers p50/p95 migration = 10.124/15.051 ms, worker mean CPU 39.57%, mean RSS 48,846,953 bytes, peak RSS 59,392,000 bytes. Three parallel workers with 250 Other servers each = p50/p95 19,563.384/19,782.577 ms, mean worker CPU 70.73%, mean RSS 58,500,712 bytes, peak RSS 63,467,520 bytes. This reveals quadratic candidate endpoint reads for a large custom-account list; it is a performance limitation, not an integrity failure. There is no corresponding migration metric in docs/perf/baseline.json, so no threshold comparison or regression claim is possible. Raw data: artifacts/integrations-round6/performance.json. Cache migration with 4,000 messages remains p50/p95 7.847/10.814 ms. The documentation audit corrected stale comments about the both-off legacy state, link cascades, and the test-only review module in bba06d4d1. Final Web gates passed again: 0 diagnostics, 149 files / 1,025 tests. Final Rust gates and the production Server build are in progress.

Finding: local performance profile completed with load average 21.12 before and 19.67 after; perf VM was unreachable. Two Other servers p50/p95 migration = 10.124/15.051 ms, worker mean CPU 39.57%, mean RSS 48,846,953 bytes, peak RSS 59,392,000 bytes. Three parallel workers with 250 Other servers each = p50/p95 19,563.384/19,782.577 ms, mean worker CPU 70.73%, mean RSS 58,500,712 bytes, peak RSS 63,467,520 bytes. This reveals quadratic candidate endpoint reads for a large custom-account list; it is a performance limitation, not an integrity failure. There is no corresponding migration metric in docs/perf/baseline.json, so no threshold comparison or regression claim is possible. Raw data: artifacts/integrations-round6/performance.json. Cache migration with 4,000 messages remains p50/p95 7.847/10.814 ms. The documentation audit corrected stale comments about the both-off legacy state, link cascades, and the test-only review module in bba06d4d1. Final Web gates passed again: 0 diagnostics, 149 files / 1,025 tests. Final Rust gates and the production Server build are in progress.
Author
Owner

Round 6 implementation complete at bba06d4d17072f63dc25768a36424c37af898b6a on job/integrations. No push or deploy. The single fetch/merge used origin/dev at 687ff703136e71e89f8dfba139e93cd0788b25c1: Already up to date. Fetched core migrations end at 0006, so new core 0012 does not collide.

Built:

  • One documented sign_in_identity rule for account creation and boot reconciliation. Named providers use the normalized sign-in address; Other uses protocol hosts, ports and usernames. Distinct Other servers with the same local login both migrate.
  • Core 0012 permits identical Other email labels across endpoints. A populated upgrade retains credentials and owner-bound Mail links with foreign keys enabled.
  • Imported the retry/reopened-Index tests from cd79e2a66; replaced its owner-requested defect diagnostic with acceptance. Added shared-label, endpoint/port/login and creation-matcher isolation coverage. Calendar-first Fastmail, unrelated-account isolation, retained credentials, cache bytes and reboot no-op pass.
  • Extended the migration performance profile to custom servers, with two accounts for average runs and three concurrent 250-account workers for worst case.

Files:

bench/integrations-migration-407.py
crates/calternal-db/src/integrations.rs
crates/calternal-db/src/migrations.rs
crates/calternal-db/src/migrations/0012_integration_endpoint_identity.sql
crates/calternal-server/src/integrations.rs
crates/calternal-server/src/integrations_review.rs
docs/DESIGN.md

Atomic commits: 9923ccb22 schema; f3d206997 identity and regressions; 5bc1c1ce4 profile; bba06d4d1 comment audit. No dependencies or versions changed. No UI source changed.

Gates:
All Cargo commands used CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4, worktree target/tmp for TMPDIR, and the preset CARGO_TARGET_DIR. RUSTC_WRAPPER was empty because the previous review found a stale shared sccache temp path.

These commands exited 0 with empty stdout and stderr: cargo fmt --check; rustfmt --edition 2024 --check crates/calternal-server/src/integrations_review.rs; cargo clippy -p calternal-db --all-targets --quiet -- -D warnings; cargo clippy -p calternal-server --all-targets --quiet -- -D warnings. The comment-only audit also passed direct rustfmt checks of the changed Rust files.

cargo test -p calternal-db --quiet -- --test-threads=1, exit 0, complete output verbatim:


running 18 tests
..................
test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.93s


running 17 tests
...i.............
test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 1.95s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo test -p calternal-server --quiet -- --test-threads=1, exit 0, complete output verbatim:


running 132 tests
....................................................................................... 87/132
.................................ii......i...
test result: ok. 129 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 71.59s

bun run --cwd apps/web check, exit 0, complete output verbatim:

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/integrations/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

bun run --cwd apps/web test --silent --reporter=dot, exit 0, complete output verbatim:

$ vitest run --silent "--reporter=dot"

 RUN  v5.0.1 /home/kayg/Developer/calternal-wt/integrations/apps/web

·····················Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
······Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
··Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
··Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
··Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
···Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
··Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
···Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
····Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
··Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
··Not implemented: Window's scrollTo() method
····Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
··Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
··Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
··Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
····Not implemented: Window's scrollTo() method
·Not implemented: Window's scrollTo() method
······Not implemented: Window's scrollTo() method
··Could not parse CSS stylesheet
·Not implemented: Window's scrollTo() method
·········································································································································································································································································································································································································································································································································································································································································································································································································································································································································································

 Test Files  149 passed (149)
      Tests  1025 passed (1025)
   Start at  03:10:57
   Duration  127.04s (transform 47%, import 22%, environment 16%, tests 10%, setup 4%)

  Transform  |component| transforming modules took 152.45s · 40% of tracked time, re-done on every run
             persist transforms across runs with fsModuleCache: true
             learn more: https://vitest.dev/guide/improving-performance#caching-between-reruns

Performance (local shared build host, debug test binary): perf VM SSH failed with No route to host. These are timed migrations; worker CPU/RSS includes fixture setup and verification. No equivalent migration metric exists in docs/perf/baseline.json, so no threshold comparison is possible.

Profile p50 ms p95 ms Mean worker CPU % Mean RSS bytes Peak RSS bytes
4,000 messages / 4,018 memberships 7.847 10.814 66.76 64186178 81584128
Three-worker cache burst 13.046 17.121 39.77 61999655 78340096
Calendar-first 10.191 16.439 36.58 49386046 75173888
Calendar-first burst 13.335 16.147 5.18 44553208 75517952
Two Other servers 10.124 15.051 39.57 48846953 59392000
Three workers, 250 Other servers each 19563.384 19782.577 70.73 58500712 63467520

Load averages before: [21.1171875, 24.44921875, 24.07861328125]; after: [19.671875, 23.36767578125, 23.7314453125]. Raw data: artifacts/integrations-round6/performance.json.

Decisions:

  • Named-provider address means the credential login address, with the stored label as fallback for a legacy OAuth sign-in that has no login name. This keeps named-provider Mail/Calendar merging and alias isolation intact.
  • Other login names retain case after trimming; hosts use canonical host parsing, lower case and no final dot. SMTP host/port/login participates in Mail identity. CalDAV identity uses its host, effective port and Calendar login. Do not infer an Other cross-protocol link from a login alone. This rule is recorded in DESIGN §49 I8.
  • The existing legacy_accounts_upgrade_losslessly_and_only_once assertions explicitly change with this endpoint rule: imap.custom.example and dav.custom.example now produce separate shared rows (4 instead of 3), with the Calendar credential bound to its own ID. Cache and secret assertions remain. The imported diagnostic changes to required acceptance at the owner's request. No other existing expectations changed.

Known gaps:

  • No external provider or old image was launched. Fixtures check exact retained bytes and both credential domains. The ignored provider resume test was not repeated in this round.
  • #626 remains an exact-SQL ordering fixture for its pending migration; the combined production binary is not tested here.
  • Other matching reads service endpoints per candidate and scales quadratically. The 250-account burst took about 19.8 seconds under local load. Performance is not a merge gate; no baseline exists to classify this as a measured regression.
  • No UI source changed, so screenshots were not repeated. Full Web gates and a production Web build passed. The first preflight Server test attempts lacked that Web build and failed at RustEmbed; after building it, all preflight and final tests passed. Raw attempt logs remain in artifacts/integrations-round6/.

Module and changed-function comments were re-read. The audit corrected stale service-switch and projection-deletion descriptions.

Build and one time-boxed local API round:

  • bun run --cwd apps/web build, exit 0. Build output is in web-build.log.
  • cargo build -p calternal-server --quiet, exit 0, empty stdout and stderr.
  • timeout 180s bun tests/adversarial/integrations_api.mjs, exit 0, complete output verbatim:
PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged
Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed

No additional non-SLOW API finding appeared. The round used the real Server and production Web build, inert credentials, and real owner/member sessions. It performed no provider sign-in.

Cleanup completed: Cargo output and generated Web build directories were removed. Only review logs and performance data remain in artifacts/integrations-round6/; no artifact was committed. Working tree is clean. Cargo cleanup output verbatim:

     Removed 14926 files, 7.7GiB total

The issue remains open for independent re-check. No push or deploy.

Round 6 implementation complete at `bba06d4d17072f63dc25768a36424c37af898b6a` on `job/integrations`. No push or deploy. The single fetch/merge used `origin/dev` at `687ff703136e71e89f8dfba139e93cd0788b25c1`: `Already up to date.` Fetched core migrations end at 0006, so new core 0012 does not collide. Built: - One documented `sign_in_identity` rule for account creation and boot reconciliation. Named providers use the normalized sign-in address; Other uses protocol hosts, ports and usernames. Distinct Other servers with the same local login both migrate. - Core 0012 permits identical Other email labels across endpoints. A populated upgrade retains credentials and owner-bound Mail links with foreign keys enabled. - Imported the retry/reopened-Index tests from `cd79e2a66`; replaced its owner-requested defect diagnostic with acceptance. Added shared-label, endpoint/port/login and creation-matcher isolation coverage. Calendar-first Fastmail, unrelated-account isolation, retained credentials, cache bytes and reboot no-op pass. - Extended the migration performance profile to custom servers, with two accounts for average runs and three concurrent 250-account workers for worst case. Files: ```text bench/integrations-migration-407.py crates/calternal-db/src/integrations.rs crates/calternal-db/src/migrations.rs crates/calternal-db/src/migrations/0012_integration_endpoint_identity.sql crates/calternal-server/src/integrations.rs crates/calternal-server/src/integrations_review.rs docs/DESIGN.md ``` Atomic commits: `9923ccb22` schema; `f3d206997` identity and regressions; `5bc1c1ce4` profile; `bba06d4d1` comment audit. No dependencies or versions changed. No UI source changed. Gates: All Cargo commands used CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4, worktree target/tmp for TMPDIR, and the preset CARGO_TARGET_DIR. RUSTC_WRAPPER was empty because the previous review found a stale shared sccache temp path. These commands exited 0 with empty stdout and stderr: cargo fmt --check; rustfmt --edition 2024 --check crates/calternal-server/src/integrations_review.rs; cargo clippy -p calternal-db --all-targets --quiet -- -D warnings; cargo clippy -p calternal-server --all-targets --quiet -- -D warnings. The comment-only audit also passed direct rustfmt checks of the changed Rust files. `cargo test -p calternal-db --quiet -- --test-threads=1`, exit 0, complete output verbatim: ```text running 18 tests .................. test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.93s running 17 tests ...i............. test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 1.95s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo test -p calternal-server --quiet -- --test-threads=1`, exit 0, complete output verbatim: ```text running 132 tests ....................................................................................... 87/132 .................................ii......i... test result: ok. 129 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 71.59s ``` `bun run --cwd apps/web check`, exit 0, complete output verbatim: ```text $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/integrations/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` `bun run --cwd apps/web test --silent --reporter=dot`, exit 0, complete output verbatim: ```text $ vitest run --silent "--reporter=dot" RUN v5.0.1 /home/kayg/Developer/calternal-wt/integrations/apps/web ·····················Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ······Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ··Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ··Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method ··Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ···Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ··Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ···Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ····Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ··Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ··Not implemented: Window's scrollTo() method ····Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method ··Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ··Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method ··Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method ····Not implemented: Window's scrollTo() method ·Not implemented: Window's scrollTo() method ······Not implemented: Window's scrollTo() method ··Could not parse CSS stylesheet ·Not implemented: Window's scrollTo() method ········································································································································································································································································································································································································································································································································································································································································································································································································································································································································································· Test Files 149 passed (149) Tests 1025 passed (1025) Start at 03:10:57 Duration 127.04s (transform 47%, import 22%, environment 16%, tests 10%, setup 4%) Transform |component| transforming modules took 152.45s · 40% of tracked time, re-done on every run persist transforms across runs with fsModuleCache: true learn more: https://vitest.dev/guide/improving-performance#caching-between-reruns ``` Performance (local shared build host, debug test binary): perf VM SSH failed with `No route to host`. These are timed migrations; worker CPU/RSS includes fixture setup and verification. No equivalent migration metric exists in docs/perf/baseline.json, so no threshold comparison is possible. | Profile | p50 ms | p95 ms | Mean worker CPU % | Mean RSS bytes | Peak RSS bytes | | --- | ---: | ---: | ---: | ---: | ---: | | 4,000 messages / 4,018 memberships | 7.847 | 10.814 | 66.76 | 64186178 | 81584128 | | Three-worker cache burst | 13.046 | 17.121 | 39.77 | 61999655 | 78340096 | | Calendar-first | 10.191 | 16.439 | 36.58 | 49386046 | 75173888 | | Calendar-first burst | 13.335 | 16.147 | 5.18 | 44553208 | 75517952 | | Two Other servers | 10.124 | 15.051 | 39.57 | 48846953 | 59392000 | | Three workers, 250 Other servers each | 19563.384 | 19782.577 | 70.73 | 58500712 | 63467520 | Load averages before: [21.1171875, 24.44921875, 24.07861328125]; after: [19.671875, 23.36767578125, 23.7314453125]. Raw data: artifacts/integrations-round6/performance.json. Decisions: - Named-provider address means the credential login address, with the stored label as fallback for a legacy OAuth sign-in that has no login name. This keeps named-provider Mail/Calendar merging and alias isolation intact. - Other login names retain case after trimming; hosts use canonical host parsing, lower case and no final dot. SMTP host/port/login participates in Mail identity. CalDAV identity uses its host, effective port and Calendar login. Do not infer an Other cross-protocol link from a login alone. This rule is recorded in DESIGN §49 I8. - The existing legacy_accounts_upgrade_losslessly_and_only_once assertions explicitly change with this endpoint rule: imap.custom.example and dav.custom.example now produce separate shared rows (4 instead of 3), with the Calendar credential bound to its own ID. Cache and secret assertions remain. The imported diagnostic changes to required acceptance at the owner's request. No other existing expectations changed. Known gaps: - No external provider or old image was launched. Fixtures check exact retained bytes and both credential domains. The ignored provider resume test was not repeated in this round. - #626 remains an exact-SQL ordering fixture for its pending migration; the combined production binary is not tested here. - Other matching reads service endpoints per candidate and scales quadratically. The 250-account burst took about 19.8 seconds under local load. Performance is not a merge gate; no baseline exists to classify this as a measured regression. - No UI source changed, so screenshots were not repeated. Full Web gates and a production Web build passed. The first preflight Server test attempts lacked that Web build and failed at RustEmbed; after building it, all preflight and final tests passed. Raw attempt logs remain in artifacts/integrations-round6/. Module and changed-function comments were re-read. The audit corrected stale service-switch and projection-deletion descriptions. Build and one time-boxed local API round: - `bun run --cwd apps/web build`, exit 0. Build output is in web-build.log. - `cargo build -p calternal-server --quiet`, exit 0, empty stdout and stderr. - `timeout 180s bun tests/adversarial/integrations_api.mjs`, exit 0, complete output verbatim: ```text PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged Integrations API probe: anonymous access, private and Unicode endpoints, unknown fields, malformed/oversized JSON, hostile IDs, cross-Plugin empty-state consistency, and 24 parallel reads passed ``` No additional non-SLOW API finding appeared. The round used the real Server and production Web build, inert credentials, and real owner/member sessions. It performed no provider sign-in. Cleanup completed: Cargo output and generated Web build directories were removed. Only review logs and performance data remain in artifacts/integrations-round6/; no artifact was committed. Working tree is clean. Cargo cleanup output verbatim: ```text Removed 14926 files, 7.7GiB total ``` The issue remains open for independent re-check. No push or deploy.
Author
Owner

Third re-check started on review/integrations-407-round6, base bba06d4d17. Tests-only review of endpoint identity, unchanged prior regressions, core 0012 upgrade and Mail 0009 ordering. No push or deploy.

Third re-check started on review/integrations-407-round6, base bba06d4d17072f63dc25768a36424c37af898b6a. Tests-only review of endpoint identity, unchanged prior regressions, core 0012 upgrade and Mail 0009 ordering. No push or deploy.
Author
Owner

Third re-check evidence: Mail 0009 at c4a61e8cf is byte-identical to the exact-SQL ordering fixture (cmp exit 0). Compared imported regression function bodies with cd79e2a66: all retained regressions are unchanged. Added test-only host canonicalisation (Unicode/punycode, host case, final dot, ports and case-sensitive Other logins), plus populated core 0011 to 0012 upgrades in both Mail 0009 orders with exact account/link/cache snapshots. cargo fmt --check and Server all-targets Clippy have passed; Server tests are running. Required origin/dev merge returned Already up to date.

Third re-check evidence: Mail 0009 at c4a61e8cf is byte-identical to the exact-SQL ordering fixture (cmp exit 0). Compared imported regression function bodies with cd79e2a66: all retained regressions are unchanged. Added test-only host canonicalisation (Unicode/punycode, host case, final dot, ports and case-sensitive Other logins), plus populated core 0011 to 0012 upgrades in both Mail 0009 orders with exact account/link/cache snapshots. cargo fmt --check and Server all-targets Clippy have passed; Server tests are running. Required origin/dev merge returned Already up to date.
Author
Owner

Tests committed as 8623562e3 on review/integrations-407-round6. Final Server gates passed: formatting (empty output), all-targets Clippy with -D warnings, and 131 tests passed / 0 failed / 3 ignored. Core Index tests passed (18 unit tests; 16 integration tests passed, 1 ignored). The ignored Mail resume test and the bounded real-session local contract check remain in progress before the final verdict.

Tests committed as 8623562e3 on review/integrations-407-round6. Final Server gates passed: formatting (empty output), all-targets Clippy with -D warnings, and 131 tests passed / 0 failed / 3 ignored. Core Index tests passed (18 unit tests; 16 integration tests passed, 1 ignored). The ignored Mail resume test and the bounded real-session local contract check remain in progress before the final verdict.
Author
Owner

GO for #407 Round 6: the third re-check found no new blocker in the reviewed migration and sign-in identity behavior.

Branch: review/integrations-407-round6. Head: 8623562e35dad96413ce79ec5f737abc02dee236.
Review base: bba06d4d17072f63dc25768a36424c37af898b6a.
The required fetch and merge of origin/dev (687ff703136e71e89f8dfba139e93cd0788b25c1) returned Already up to date. No push or deploy.

Built and files:

  • Added two independent tests in crates/calternal-server/src/integrations_review.rs. No production code changed.
  • The identity matrix checks host case, final dots, Unicode/punycode equivalence, case-sensitive Other IMAP/SMTP usernames, changed ports, actual default IMAP 993 versus explicit discovery 993, and omitted HTTPS port versus explicit 443.
  • The populated upgrade matrix moves an already linked core 0011 Index through 0012 in both orders with Mail 0009. It compares every account, link, cache and credential row and checks migration namespaces and foreign keys.

Confirmed:

  • Two Other servers with the same login migrate separately, including an identical email label.
  • Calendar-first Fastmail and later Mail merge, preserve separate service secrets and retain cache IDs. All four named providers use the same normalized-address identity rule.
  • Account conflicts and damaged credentials stay isolated. Late-statement rollback and repair/retry still pass.
  • Repeated reconciliation and a closed/reopened Index are no-ops.
  • Fresh and upgraded Index schemas accept core 0012 with Mail 0009 in either order. Populated 0011 links survive the parent-table rebuild.
  • Earlier imported regression function bodies match cd79e2a66 unchanged. Only the already-authorized Round 6 distinct-server acceptance replaced its earlier defect diagnostic.
  • Exact Mail 0009 SQL at c4a61e8cf090170f35b1bed3350d9de20c83ecd5 is byte-identical to the existing fixture (cmp, exit 0).
  • The existing ignored Mail resume test passed against the Server's migrated snapshot: 4,000 messages, 4,018 memberships, no repeated UID FETCH commands.

All gates below exited 0. These are verbatim result excerpts; complete logs remain in artifacts/round6-review/.

cargo fmt --check: empty output. The final comment audit also passed formatting with empty output.

cargo clippy -p calternal-server --all-targets -- -D warnings

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 48.09s

cargo test -p calternal-server

    Finished `test` profile [unoptimized + debuginfo] target(s) in 2m 54s
test result: ok. 131 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 19.27s

cargo test -p calternal-db

    Finished `test` profile [unoptimized + debuginfo] target(s) in 44.66s
test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.78s
test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.82s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo test -p calternal-plugin-mail migrated_production_shape_resumes_without_refetch -- --ignored --nocapture

    Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 20s
review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 1.80s

The production Web build and cargo build -p calternal-server --quiet exited 0. The Server build produced empty output.

One bounded local contract round, timeout 180s bun tests/adversarial/integrations_api.mjs --contract-only, exited 0. Complete output, verbatim:

PASS bounded local integrations contract: authenticated reads, anonymous 401, schema rejection, empty cross-Plugin state
PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged

Known gaps:

  • No real external provider or old image was launched. #626 ordering uses exact SQL; the combined c4a61e8cf production binary was not tested. This worktree's Mail crate still ships migrations through 0008.
  • The local round used bounded schema and real-session checks. The full hostile-input campaign was not repeated.
  • No UI changed. Web type/test gates and screenshots were not repeated. A real production Web build supplied the Server's embedded assets.
  • No feature or hot path changed. The performance profile was not repeated. The previously reported quadratic Other-account scan remains a performance limitation.

Decisions: no new product design decision. Reused the existing fixtures and snapshot helper. Kept the historical #626 fixture name because its SQL matches c4a61e8cf exactly. No existing test expectation was changed by this re-check.

Re-read all module/function doc comments in the touched file. Cleanup removed Cargo output, Web output, the fixture snapshot and test runtime directories. Working tree is clean. Cargo cleanup output, verbatim:

     Removed 15165 files, 8.1GiB total

The issue stays open for the orchestrator.

GO for #407 Round 6: the third re-check found no new blocker in the reviewed migration and sign-in identity behavior. Branch: `review/integrations-407-round6`. Head: `8623562e35dad96413ce79ec5f737abc02dee236`. Review base: `bba06d4d17072f63dc25768a36424c37af898b6a`. The required fetch and merge of `origin/dev` (`687ff703136e71e89f8dfba139e93cd0788b25c1`) returned `Already up to date.` No push or deploy. Built and files: - Added two independent tests in `crates/calternal-server/src/integrations_review.rs`. No production code changed. - The identity matrix checks host case, final dots, Unicode/punycode equivalence, case-sensitive Other IMAP/SMTP usernames, changed ports, actual default IMAP 993 versus explicit discovery 993, and omitted HTTPS port versus explicit 443. - The populated upgrade matrix moves an already linked core 0011 Index through 0012 in both orders with Mail 0009. It compares every account, link, cache and credential row and checks migration namespaces and foreign keys. Confirmed: - Two Other servers with the same login migrate separately, including an identical email label. - Calendar-first Fastmail and later Mail merge, preserve separate service secrets and retain cache IDs. All four named providers use the same normalized-address identity rule. - Account conflicts and damaged credentials stay isolated. Late-statement rollback and repair/retry still pass. - Repeated reconciliation and a closed/reopened Index are no-ops. - Fresh and upgraded Index schemas accept core 0012 with Mail 0009 in either order. Populated 0011 links survive the parent-table rebuild. - Earlier imported regression function bodies match `cd79e2a66` unchanged. Only the already-authorized Round 6 distinct-server acceptance replaced its earlier defect diagnostic. - Exact Mail 0009 SQL at `c4a61e8cf090170f35b1bed3350d9de20c83ecd5` is byte-identical to the existing fixture (`cmp`, exit 0). - The existing ignored Mail resume test passed against the Server's migrated snapshot: 4,000 messages, 4,018 memberships, no repeated UID FETCH commands. All gates below exited 0. These are verbatim result excerpts; complete logs remain in `artifacts/round6-review/`. `cargo fmt --check`: empty output. The final comment audit also passed formatting with empty output. `cargo clippy -p calternal-server --all-targets -- -D warnings` ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 48.09s ``` `cargo test -p calternal-server` ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 2m 54s test result: ok. 131 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 19.27s ``` `cargo test -p calternal-db` ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 44.66s test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.78s test result: ok. 16 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.82s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo test -p calternal-plugin-mail migrated_production_shape_resumes_without_refetch -- --ignored --nocapture` ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 20s review migrated sync: 4000 messages, 4018 memberships, 0 repeated UID FETCH commands test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 40 filtered out; finished in 1.80s ``` The production Web build and `cargo build -p calternal-server --quiet` exited 0. The Server build produced empty output. One bounded local contract round, `timeout 180s bun tests/adversarial/integrations_api.mjs --contract-only`, exited 0. Complete output, verbatim: ```text PASS bounded local integrations contract: authenticated reads, anonymous 401, schema rejection, empty cross-Plugin state PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged ``` Known gaps: - No real external provider or old image was launched. #626 ordering uses exact SQL; the combined c4a61e8cf production binary was not tested. This worktree's Mail crate still ships migrations through 0008. - The local round used bounded schema and real-session checks. The full hostile-input campaign was not repeated. - No UI changed. Web type/test gates and screenshots were not repeated. A real production Web build supplied the Server's embedded assets. - No feature or hot path changed. The performance profile was not repeated. The previously reported quadratic Other-account scan remains a performance limitation. Decisions: no new product design decision. Reused the existing fixtures and snapshot helper. Kept the historical #626 fixture name because its SQL matches c4a61e8cf exactly. No existing test expectation was changed by this re-check. Re-read all module/function doc comments in the touched file. Cleanup removed Cargo output, Web output, the fixture snapshot and test runtime directories. Working tree is clean. Cargo cleanup output, verbatim: ```text Removed 15165 files, 8.1GiB total ``` The issue stays open for the orchestrator.
Author
Owner

Owner (2026-10-02): no row dividers inside Settings section cards; separate rows by spacing only (shared SettingRow/card component). Folded into the Settings redesign brief.

Owner (2026-10-02): no row dividers inside Settings section cards; separate rows by spacing only (shared SettingRow/card component). Folded into the Settings redesign brief.
Author
Owner

Starting #407 work on branch job/settings-50, based on job/merge-round-7a at 2f4482ded0.

Starting #407 work on branch job/settings-50, based on job/merge-round-7a at 2f4482ded066d9c5d9c59130377907f7fd2916c9.
Author
Owner

Finding during the Cmd+K access checks: the member Settings index correctly includes Sync & Backup at /settings/sync-backup, so the old broad backup substring assertion incorrectly treated a User page as Admin content. I changed the guard to assert the actual Admin route is absent and added an assertion for the User page. The access suite also awaited a live /api/v1/search request even though its assertions discard server results; after giving that provider a valid empty test response, the client access suite completed without the timeout/provider leak. Evidence: bunx vitest run --project=unit --reporter=dot src/lib/search/access.test.ts — Test Files 1 passed (1), Tests 5 passed (5).

Finding during the Cmd+K access checks: the member Settings index correctly includes `Sync & Backup` at `/settings/sync-backup`, so the old broad `backup` substring assertion incorrectly treated a User page as Admin content. I changed the guard to assert the actual Admin route is absent and added an assertion for the User page. The access suite also awaited a live `/api/v1/search` request even though its assertions discard server results; after giving that provider a valid empty test response, the client access suite completed without the timeout/provider leak. Evidence: `bunx vitest run --project=unit --reporter=dot src/lib/search/access.test.ts` — `Test Files 1 passed (1)`, `Tests 5 passed (5)`.
Author
Owner

Integration finding: after merging the required origin/dev (440e19dce) and moved job/merge-round-7a (efe8323f) branches, neither contracts/openapi.json nor packages/api-client/src/generated.ts contains /api/v1/shortcuts/preferences or its initialize route, and the merged calternal-server has no shortcut preference handler. The retained #542 preset chooser calls those routes. bun run check therefore ends with 7 errors, all in apps/web/src/lib/shortcuts/preferences.ts, for missing paths and response fields. The separate job/shortcuts-542 branch carries this behavior in the server, CLI and MCP crates; integrating it would change other crates' behavior outside #407's Settings scope. I am continuing the Settings work without adding a local-only fallback and will report the unresolved #542 integration dependency.

Integration finding: after merging the required `origin/dev` (440e19dce) and moved `job/merge-round-7a` (efe8323f) branches, neither `contracts/openapi.json` nor `packages/api-client/src/generated.ts` contains `/api/v1/shortcuts/preferences` or its initialize route, and the merged `calternal-server` has no shortcut preference handler. The retained #542 preset chooser calls those routes. `bun run check` therefore ends with 7 errors, all in `apps/web/src/lib/shortcuts/preferences.ts`, for missing paths and response fields. The separate `job/shortcuts-542` branch carries this behavior in the server, CLI and MCP crates; integrating it would change other crates' behavior outside #407's Settings scope. I am continuing the Settings work without adding a local-only fallback and will report the unresolved #542 integration dependency.
Author
Owner

Copy audit evidence for the Connected Accounts scope in this issue. The current Settings UI still shows provider sign-in forms in Mail and Calendars. The labels also name third-party products and use protocol terms.

  • apps/web/src/routes/settings/sections.ts:81,87-89: “Calendars”, “Calendar accounts” and “Connect a calendar account”. Provider sign-in belongs under “Connected Accounts”; Calendar settings should keep only calendar preferences and a link to the account.
  • apps/web/src/routes/settings/sections.ts:95,98-99: “Mail”, “Mail accounts” and “Connect a mail account”. Mail settings should keep only mail preferences and a link to the account.
  • apps/web/src/routes/settings/calendars/calendarAccounts.ts:19,26,33: provider choices “iCloud”, “Fastmail” and “Nextcloud”. Replace these visible product names with a generic account choice. Show the User’s account name or email after sign-in.
  • apps/web/src/routes/settings/calendars/calendarAccounts.ts:28-29: “Your Fastmail email address.” and “Make an app password in Fastmail … with calendar (CalDAV) access.” → “Your email address.” and “Create an app password in your account settings, with Calendar access.”
  • apps/web/src/routes/settings/calendars/calendarAccounts.ts:35-36: “Your Nextcloud username.” and “Make an app password in Nextcloud … The server URL ends in /remote.php/dav.” → “Your username.” and “Create an app password in your account settings. Enter your calendar server address.”
  • apps/web/src/routes/settings/calendars/calendarAccounts.ts:66: “point to a CalDAV server” → “use a calendar server address”.
  • apps/web/src/routes/settings/mail/MailSection.svelte:52,60,68: provider labels “Gmail”, “iCloud” and “Fastmail”; line 54 “Your full Gmail address.”; line 62 “Your Apple Account email address.”; lines 70-72 “Your Fastmail email address.” / “Create a Fastmail app password”. Replace with generic account names and help such as “Your full email address” and “Create an app password in your account settings.”
  • apps/web/src/routes/settings/mail/MailSection.svelte:614: “Connect an IMAP account”, “source of truth”, “encrypted app password” and “rebuildable copy” expose protocol and implementation details. Use plain copy about connecting a mail account and what happens to saved mail when it is removed.
  • apps/web/src/routes/settings/mail/MailSection.svelte:633,665,669-676,678,680-681: “IMAP”, “SMTP”, “TLS” and “STARTTLS” appear in help, field labels and choices. Use “Incoming mail server”, “Outgoing mail server”, “Port” and plain secure-connection choices. Keep technical values in the fields only where a custom server needs them.

Owner rule: use “Connected Accounts” for provider sign-ins and do not name third-party products in UI copy. DESIGN §49 I1-I2 says a provider account is added once under Connected Accounts; Mail and Calendars keep service preferences and link to that account.

Expected behaviour: one Connected Accounts page owns provider sign-in. The Mail and Calendar pages do not ask for a second sign-in. Visible setup copy uses plain words and no provider product names or protocol acronyms.

Test idea: like a User, add one account, enable its Mail and Calendar services, then open both Settings pages. Check that each page links to the same Connected Account and that visible and screen-reader labels contain no provider name or protocol acronym.

Copy audit evidence for the Connected Accounts scope in this issue. The current Settings UI still shows provider sign-in forms in Mail and Calendars. The labels also name third-party products and use protocol terms. - `apps/web/src/routes/settings/sections.ts:81,87-89`: “Calendars”, “Calendar accounts” and “Connect a calendar account”. Provider sign-in belongs under “Connected Accounts”; Calendar settings should keep only calendar preferences and a link to the account. - `apps/web/src/routes/settings/sections.ts:95,98-99`: “Mail”, “Mail accounts” and “Connect a mail account”. Mail settings should keep only mail preferences and a link to the account. - `apps/web/src/routes/settings/calendars/calendarAccounts.ts:19,26,33`: provider choices “iCloud”, “Fastmail” and “Nextcloud”. Replace these visible product names with a generic account choice. Show the User’s account name or email after sign-in. - `apps/web/src/routes/settings/calendars/calendarAccounts.ts:28-29`: “Your Fastmail email address.” and “Make an app password in Fastmail … with calendar (CalDAV) access.” → “Your email address.” and “Create an app password in your account settings, with Calendar access.” - `apps/web/src/routes/settings/calendars/calendarAccounts.ts:35-36`: “Your Nextcloud username.” and “Make an app password in Nextcloud … The server URL ends in /remote.php/dav.” → “Your username.” and “Create an app password in your account settings. Enter your calendar server address.” - `apps/web/src/routes/settings/calendars/calendarAccounts.ts:66`: “point to a CalDAV server” → “use a calendar server address”. - `apps/web/src/routes/settings/mail/MailSection.svelte:52,60,68`: provider labels “Gmail”, “iCloud” and “Fastmail”; line 54 “Your full Gmail address.”; line 62 “Your Apple Account email address.”; lines 70-72 “Your Fastmail email address.” / “Create a Fastmail app password”. Replace with generic account names and help such as “Your full email address” and “Create an app password in your account settings.” - `apps/web/src/routes/settings/mail/MailSection.svelte:614`: “Connect an IMAP account”, “source of truth”, “encrypted app password” and “rebuildable copy” expose protocol and implementation details. Use plain copy about connecting a mail account and what happens to saved mail when it is removed. - `apps/web/src/routes/settings/mail/MailSection.svelte:633,665,669-676,678,680-681`: “IMAP”, “SMTP”, “TLS” and “STARTTLS” appear in help, field labels and choices. Use “Incoming mail server”, “Outgoing mail server”, “Port” and plain secure-connection choices. Keep technical values in the fields only where a custom server needs them. Owner rule: use “Connected Accounts” for provider sign-ins and do not name third-party products in UI copy. DESIGN §49 I1-I2 says a provider account is added once under Connected Accounts; Mail and Calendars keep service preferences and link to that account. Expected behaviour: one Connected Accounts page owns provider sign-in. The Mail and Calendar pages do not ask for a second sign-in. Visible setup copy uses plain words and no provider product names or protocol acronyms. Test idea: like a User, add one account, enable its Mail and Calendar services, then open both Settings pages. Check that each page links to the same Connected Account and that visible and screen-reader labels contain no provider name or protocol acronym.
Author
Owner

Static audit evidence for DESIGN §§49-50:

Settings still has separate account setup flows. apps/web/src/routes/settings/sections.ts:80-100 registers Calendar accounts / Connect a calendar account and Mail accounts / Connect a mail account as separate pages. The Calendar form asks for provider URL, username and password in apps/web/src/routes/settings/calendars/CalendarsSection.svelte:408-436; Mail loads its own accounts at apps/web/src/routes/settings/mail/MailSection.svelte:86,544.

Expected: one Connected Accounts page signs in once per provider account and enables Mail, Calendar and Contacts there; service pages keep preferences and link back to the account. Regression idea: connect one provider account once, toggle two services, and verify both service views use that account.

Static audit evidence for DESIGN §§49-50: Settings still has separate account setup flows. apps/web/src/routes/settings/sections.ts:80-100 registers Calendar accounts / Connect a calendar account and Mail accounts / Connect a mail account as separate pages. The Calendar form asks for provider URL, username and password in apps/web/src/routes/settings/calendars/CalendarsSection.svelte:408-436; Mail loads its own accounts at apps/web/src/routes/settings/mail/MailSection.svelte:86,544. Expected: one Connected Accounts page signs in once per provider account and enables Mail, Calendar and Contacts there; service pages keep preferences and link back to the account. Regression idea: connect one provider account once, toggle two services, and verify both service views use that account.
Author
Owner

More copy evidence for Settings → Apps and Settings → Calendars

Settings → Apps

  • apps/web/src/routes/settings/apps/AppsSection.svelte:19: row names API, CLI, MCP, WebMCP. Use plain choices such as Other apps, Apps on this device, AI helpers, and This browser.
  • :21-25: App passwords and external API clients, Installation tokens, including command line clients, Remote AI client tools, Tools available to this browser, and Apple Notes sync over IMAP. Use one short description for each task. Remove the protocol and product names.
  • :57-60: Instance app access, App access, and descriptions with client surface and clients. Use Apps and describe which apps can use this User's data or every User's data.

Settings → Apps → Calendar feeds

  • apps/web/src/routes/settings/apps/CalendarFeedsGroup.svelte:60-65: the status can show Apple Calendar, Outlook, Google Calendar, Thunderbird, or a raw user-agent string. Use a neutral label such as Calendar app; do not show the raw user-agent string.
  • :160-162: Calendar feeds, Publish a read-only Calendar feed, and Published calendar feeds. Use Share a calendar and explain that a link lets other people see the selected events.
  • :187-220: No published feeds yet, New feed, Create calendar feed, New Calendar Feed, Source, Area tag, Detail, Full, Busy only, Feed colour, and Include dated Tasks as Events. Use short task labels, such as No shared calendars yet, Share a calendar, What to share, Details, Full details, and Busy times only.
  • :213,217,220-221: Anyone with the link can read this feed, webcal links, HTTPS, and Webcal. Use plain text such as Anyone with this link can see these events, Scan with a calendar app to add them, Web link, and Calendar app link.

Settings → Calendars → External calendars

  • apps/web/src/routes/settings/calendars/ExternalCalendarsGroup.svelte:103: Subscribe to an HTTPS or webcal link. The remote Calendar is stored as a read-only layer and is refreshed on its own schedule. Say Paste a calendar link. It appears here, and calternal checks for updates automatically.
  • :105,126,130-131: External calendar subscriptions, No external calendars yet. Add a public Calendar URL below., Calendar URL with an https://… or webcal://… placeholder, and Layer colour. Use Shared calendars, No calendars yet. Add a calendar link below., Calendar link, and Calendar colour.

These are copy defects in the Settings structure covered by #407 and DESIGN §§49–50. The owner rule from 2026-10-02 also says not to name third-party products in the UI.

Test idea: open each group and check its heading, empty state, form, status text, and screen-reader labels. Add and refresh one real calendar link. Confirm that no protocol name, raw user-agent string, or product name appears.

More copy evidence for Settings → Apps and Settings → Calendars **Settings → Apps** - `apps/web/src/routes/settings/apps/AppsSection.svelte:19`: row names `API`, `CLI`, `MCP`, `WebMCP`. Use plain choices such as `Other apps`, `Apps on this device`, `AI helpers`, and `This browser`. - `:21-25`: `App passwords and external API clients`, `Installation tokens, including command line clients`, `Remote AI client tools`, `Tools available to this browser`, and `Apple Notes sync over IMAP`. Use one short description for each task. Remove the protocol and product names. - `:57-60`: `Instance app access`, `App access`, and descriptions with `client surface` and `clients`. Use `Apps` and describe which apps can use this User's data or every User's data. **Settings → Apps → Calendar feeds** - `apps/web/src/routes/settings/apps/CalendarFeedsGroup.svelte:60-65`: the status can show `Apple Calendar`, `Outlook`, `Google Calendar`, `Thunderbird`, or a raw user-agent string. Use a neutral label such as `Calendar app`; do not show the raw user-agent string. - `:160-162`: `Calendar feeds`, `Publish a read-only Calendar feed`, and `Published calendar feeds`. Use `Share a calendar` and explain that a link lets other people see the selected events. - `:187-220`: `No published feeds yet`, `New feed`, `Create calendar feed`, `New Calendar Feed`, `Source`, `Area tag`, `Detail`, `Full`, `Busy only`, `Feed colour`, and `Include dated Tasks as Events`. Use short task labels, such as `No shared calendars yet`, `Share a calendar`, `What to share`, `Details`, `Full details`, and `Busy times only`. - `:213,217,220-221`: `Anyone with the link can read this feed`, `webcal links`, `HTTPS`, and `Webcal`. Use plain text such as `Anyone with this link can see these events`, `Scan with a calendar app to add them`, `Web link`, and `Calendar app link`. **Settings → Calendars → External calendars** - `apps/web/src/routes/settings/calendars/ExternalCalendarsGroup.svelte:103`: `Subscribe to an HTTPS or webcal link. The remote Calendar is stored as a read-only layer and is refreshed on its own schedule.` Say `Paste a calendar link. It appears here, and calternal checks for updates automatically.` - `:105,126,130-131`: `External calendar subscriptions`, `No external calendars yet. Add a public Calendar URL below.`, `Calendar URL` with an `https://… or webcal://…` placeholder, and `Layer colour`. Use `Shared calendars`, `No calendars yet. Add a calendar link below.`, `Calendar link`, and `Calendar colour`. These are copy defects in the Settings structure covered by #407 and DESIGN §§49–50. The owner rule from 2026-10-02 also says not to name third-party products in the UI. Test idea: open each group and check its heading, empty state, form, status text, and screen-reader labels. Add and refresh one real calendar link. Confirm that no protocol name, raw user-agent string, or product name appears.
Author
Owner

More Mail copy evidence for Settings and the reader

  • apps/web/src/routes/settings/mail/MailSection.svelte:78-79: The username your mail provider gives you. It defaults to your email address. / Use an app password if your mail provider offers one. → Use the sign-in name from your mail account. / Use an app password if your mail account offers one.
  • :190: Enter the SMTP username or use the same sign-in for both servers. → Enter the sending account name or use the same sign-in for both mail servers.
  • :222-223: The provider refused the username or app password. / The provider could not be reached securely. Check the server settings and try again. → Your mail account did not accept that sign-in. Check the account name and app password. / Could not connect to your mail account securely. Check the account settings and try again.
  • :620,632: Choose when opening a message marks it as read at your mail provider. and the screen-reader label Mail provider → Choose when to mark opened messages as read. and Mail account.
  • apps/web/src/lib/mail/MailView.svelte:249: The read state could not be saved to the provider. → Could not update this message in your mail account.
  • :544: This message exceeds the cached body limit. The remaining content is unavailable here. → This message is too long to show in full. The rest is not available here.
  • :636: Connect an IMAP account to read Mail. → Connect a mail account to read Mail.

Test idea: check each error and empty state. Confirm Mail uses the account in Connected Accounts and does not ask for a second sign-in.

More Mail copy evidence for Settings and the reader - `apps/web/src/routes/settings/mail/MailSection.svelte:78-79`: `The username your mail provider gives you. It defaults to your email address.` / `Use an app password if your mail provider offers one.` → `Use the sign-in name from your mail account.` / `Use an app password if your mail account offers one.` - `:190`: `Enter the SMTP username or use the same sign-in for both servers.` → `Enter the sending account name or use the same sign-in for both mail servers.` - `:222-223`: `The provider refused the username or app password.` / `The provider could not be reached securely. Check the server settings and try again.` → `Your mail account did not accept that sign-in. Check the account name and app password.` / `Could not connect to your mail account securely. Check the account settings and try again.` - `:620,632`: `Choose when opening a message marks it as read at your mail provider.` and the screen-reader label `Mail provider` → `Choose when to mark opened messages as read.` and `Mail account`. - `apps/web/src/lib/mail/MailView.svelte:249`: `The read state could not be saved to the provider.` → `Could not update this message in your mail account.` - `:544`: `This message exceeds the cached body limit. The remaining content is unavailable here.` → `This message is too long to show in full. The rest is not available here.` - `:636`: `Connect an IMAP account to read Mail.` → `Connect a mail account to read Mail.` Test idea: check each error and empty state. Confirm Mail uses the account in Connected Accounts and does not ask for a second sign-in.
Author
Owner

settings-50 report

Status: The implementation is committed on job/settings-50, but the job is incomplete. The required real-server review and final gates did not finish before the four-hour job cap. Do not treat this report as a merge-ready verification.

Head: 1dc1cba58804b03051135eb1f7f4285a2fec41b1

Built

  • Added the User/Admin Settings tree, sub-sections, stable route mapping and legacy URL destinations.
  • Built plugin-backed Tabs ordering, including pointer drag and keyboard ordering, and each Tab's Settings menu action.
  • Moved the Date & Time, Storage, Background Work, Video, Photos and App Access settings to their new homes. Added a real unavailable state for Account Providers because its backend is absent.
  • Added Settings page/card/label targets to Cmd+K, with deep links to matching settings and shortcut rows. There is no inline search field.
  • Added phone list/pushed-page history handling, including the #649 fallback to the Settings list for direct links.
  • Removed hairline separators inside shared Settings rows and fixed Copy link hover/focus selectors.
  • Added the production review E2E script and expanded the Settings open/burst benchmark profile.

Files

  • Registry, routing, and page moves: apps/web/src/routes/settings/sections.ts, sections.test.ts, [...path]/+page.svelte, api.svelte.ts, and the Settings account/admin/apps/calendars/files/jobs/mail/photos/plugins/shortcuts section files.
  • Search and shortcut links: apps/web/src/lib/search/providers.ts, providers.test.ts, access.svelte.ts, access.test.ts, apps/web/src/lib/shortcuts/*, and apps/web/src/lib/components/KeyboardShortcutsCard.svelte.
  • Shared row/sidebar behavior: packages/ui/src/components/SettingRow.svelte, FloatingSidebar.svelte, apps/web/src/lib/components/app-sidebar.svelte, and apps/web/src/routes/settings/parts/AccountList.svelte.
  • Review and performance scripts: apps/web/e2e/settings-review-50.mjs, apps/web/e2e/maintenance-links.mjs, apps/web/package.json, and bench/settings-shortcut.mjs.

Gate output

The production web build completed after the Copy link CSS fix:

✓ built in 1m 3s
> Using @sveltejs/adapter-static
  Wrote site to "build"
  ✔ done

The earlier bun run check integration pass reported the missing #542 API types. These lines are verbatim from that run; it reported seven errors in apps/web/src/lib/shortcuts/preferences.ts:

svelte-check found 7 errors and 0 warnings in 1 file
error: script "check" exited with code 1

The targeted Settings registry tests passed:

Test Files  2 passed (2)
     Tests  29 passed (29)

The local server build was interrupted while still linking under shared-host contention:

exit_code: 130

Cleanup completed:

Removed 7232 files, 3.7GiB total

The final full bun run check, bun run test, generated contract check, parity check, production E2E, benchmark run, and adversarial round were not completed. No Rust source or route changed in this job. The full Settings E2E was not run, so the legacy redirects in that script have not been confirmed against a local server.

Known gaps and UX gaps left

  • The merged API contract does not contain /api/v1/shortcuts/preferences or its response fields from #542. The preset chooser remains server-backed and does not have a local-only fallback; it cannot complete until that API change is merged. The earlier type check found seven related errors.
  • #479's share-link invitation setting is absent from the merged backend contract. The requested switch was not built; the Invitations page has no fake control.
  • The macOS-emulated screenshot set was not captured, so required visual review at 390, 820 and 1440 px in light and dark, including cap-height checks, is pending.
  • The Settings E2E and full web suite were not run after the final changes. Pointer, touch, keyboard, screen-reader and cross-surface behavior therefore still needs the real-server pass.
  • The expanded benchmark was added but not run. There are no new measurements. The nearest existing baseline is 1440 /settings/appearance: data-ready p50 1,584 ms, p95 2,069 ms; it is not the same route or workload.

UX gaps closed

The implementation adds Copy link controls for Settings destinations and rows, exact shortcut deep links from Cmd+K, real plugin-catalog retry/offline handling, keyboard ordering for Tabs, phone back navigation, and shared row spacing without separators.

Decisions

  • Account Providers shows an unavailable state because no backend is present; it does not show sample providers.
  • AI Tab settings resolve to the existing AI Connections page so the same settings have one home.
  • Direct plugin Settings links wait for the live plugin catalog before deciding that a Tab is disabled.

Mac checks pending

The macOS VM is offline, so it was not contacted. Run test:e2e:settings-50 with the local server and Mac platform emulation, capture the files under artifacts/settings-50/review, inspect every requested viewport/theme and zoom in on icon/label rows, then attach them for visual review.

## settings-50 report **Status:** The implementation is committed on `job/settings-50`, but the job is incomplete. The required real-server review and final gates did not finish before the four-hour job cap. Do not treat this report as a merge-ready verification. **Head:** `1dc1cba58804b03051135eb1f7f4285a2fec41b1` ### Built - Added the User/Admin Settings tree, sub-sections, stable route mapping and legacy URL destinations. - Built plugin-backed Tabs ordering, including pointer drag and keyboard ordering, and each Tab's Settings menu action. - Moved the Date & Time, Storage, Background Work, Video, Photos and App Access settings to their new homes. Added a real unavailable state for Account Providers because its backend is absent. - Added Settings page/card/label targets to Cmd+K, with deep links to matching settings and shortcut rows. There is no inline search field. - Added phone list/pushed-page history handling, including the #649 fallback to the Settings list for direct links. - Removed hairline separators inside shared Settings rows and fixed Copy link hover/focus selectors. - Added the production review E2E script and expanded the Settings open/burst benchmark profile. ### Files - Registry, routing, and page moves: `apps/web/src/routes/settings/sections.ts`, `sections.test.ts`, `[...path]/+page.svelte`, `api.svelte.ts`, and the Settings account/admin/apps/calendars/files/jobs/mail/photos/plugins/shortcuts section files. - Search and shortcut links: `apps/web/src/lib/search/providers.ts`, `providers.test.ts`, `access.svelte.ts`, `access.test.ts`, `apps/web/src/lib/shortcuts/*`, and `apps/web/src/lib/components/KeyboardShortcutsCard.svelte`. - Shared row/sidebar behavior: `packages/ui/src/components/SettingRow.svelte`, `FloatingSidebar.svelte`, `apps/web/src/lib/components/app-sidebar.svelte`, and `apps/web/src/routes/settings/parts/AccountList.svelte`. - Review and performance scripts: `apps/web/e2e/settings-review-50.mjs`, `apps/web/e2e/maintenance-links.mjs`, `apps/web/package.json`, and `bench/settings-shortcut.mjs`. ### Gate output The production web build completed after the Copy link CSS fix: ```text ✓ built in 1m 3s > Using @sveltejs/adapter-static Wrote site to "build" ✔ done ``` The earlier `bun run check` integration pass reported the missing #542 API types. These lines are verbatim from that run; it reported seven errors in `apps/web/src/lib/shortcuts/preferences.ts`: ```text svelte-check found 7 errors and 0 warnings in 1 file error: script "check" exited with code 1 ``` The targeted Settings registry tests passed: ```text Test Files 2 passed (2) Tests 29 passed (29) ``` The local server build was interrupted while still linking under shared-host contention: ```text exit_code: 130 ``` Cleanup completed: ```text Removed 7232 files, 3.7GiB total ``` The final full `bun run check`, `bun run test`, generated contract check, parity check, production E2E, benchmark run, and adversarial round were not completed. No Rust source or route changed in this job. The full Settings E2E was not run, so the legacy redirects in that script have not been confirmed against a local server. ### Known gaps and UX gaps left - The merged API contract does not contain `/api/v1/shortcuts/preferences` or its response fields from #542. The preset chooser remains server-backed and does not have a local-only fallback; it cannot complete until that API change is merged. The earlier type check found seven related errors. - #479's share-link invitation setting is absent from the merged backend contract. The requested switch was not built; the Invitations page has no fake control. - The macOS-emulated screenshot set was not captured, so required visual review at 390, 820 and 1440 px in light and dark, including cap-height checks, is pending. - The Settings E2E and full web suite were not run after the final changes. Pointer, touch, keyboard, screen-reader and cross-surface behavior therefore still needs the real-server pass. - The expanded benchmark was added but not run. There are no new measurements. The nearest existing baseline is `1440 /settings/appearance`: data-ready p50 1,584 ms, p95 2,069 ms; it is not the same route or workload. ### UX gaps closed The implementation adds Copy link controls for Settings destinations and rows, exact shortcut deep links from Cmd+K, real plugin-catalog retry/offline handling, keyboard ordering for Tabs, phone back navigation, and shared row spacing without separators. ### Decisions - Account Providers shows an unavailable state because no backend is present; it does not show sample providers. - AI Tab settings resolve to the existing AI Connections page so the same settings have one home. - Direct plugin Settings links wait for the live plugin catalog before deciding that a Tab is disabled. ### Mac checks pending The macOS VM is offline, so it was not contacted. Run `test:e2e:settings-50` with the local server and Mac platform emulation, capture the files under `artifacts/settings-50/review`, inspect every requested viewport/theme and zoom in on icon/label rows, then attach them for visual review.
Author
Owner

settings-50 verification and finish (branch job/settings-50, head 656d22421)

Picks up the verification that was cut at the time limit. Web-only; no Rust changed. Server: prebuilt merge-round-7a debug binary, run in a private mount namespace so its runtime rust-embed folder serves this worktree's apps/web/build.

Bugs found and fixed

  • Phone Back was broken. afterNavigate read from.url.pathname; from.url is null on the first callback. The throw aborted SvelteKit's callbacks, so Back (button or browser) from a pushed page changed the URL to /settings but kept the detail page. Now from?.url?.pathname, and to falls back to page.url.
  • Two Back buttons on a touch tablet (820 px). The sheet is used whenever the pointer is not fine, but the desktop Back was hidden only below 768 px. It is now hidden whenever the sheet owns Back.
  • Settings → Shortcuts showed no keys on touch. Kbd hides hint caps on touch devices. A new reference prop keeps them visible on this list. Caps now line up with the first line of a wrapped label.
  • Row dividers. Hairlines removed from shortcut rows, Location (Saved places and the place form), External Calendars add form, and Connected Accounts advanced settings.
  • Plugin row Copy link showed as a bare bordered button (the segment variant needs a PillGroup), and its hover reveal rule came before the hide rule, so hover never showed it. Now variant="pill", with the rules in the right order. Calendar feeds, MCP event subscriptions and External Calendars links also use the pill variant now.
  • Sheet title repeated "User" above the "User" group on the phone list. Before any heading crosses, only a large title can take the compact title; until then the sheet shows "Settings".
  • Rail truncated "Connected Accounts" and "Account Providers". The default width is now 248 px.
  • Type check failed (7 errors). The branch had a copy of #542's server preset sync (/api/v1/shortcuts/preferences), which is only on job/shortcuts-542. I removed the preset row, its search labels and the sign-in sync from this branch; #542 adds them back. Also fixed 'to' is possibly 'null'.
  • Stale tests now follow the DESIGN §50 IDs (apps-devices, admin/app-access, /settings/tabs/calendar/add) and Title Case (Your Accounts). The review e2e had wrong selectors (phone detail heading, card aria-busy, dotted ID app.settings) and pressed Cmd+K before its handler was attached.
  • DESIGN §33 now gives the Background Work slugs (it still said Maintenance), and §50 S5 now says there is no inline search field.

Maintenance naming: the tree no longer uses "Maintenance". DESIGN §50 names both pages Background Work and S3 says the same name twice is fine at two scopes, so I left both labels as they are.

Gates (verbatim)

svelte-check: COMPLETED 2000 FILES 0 ERRORS 0 WARNINGS 0 FILES_WITH_PROBLEMS
bun run test: Test Files  155 passed (155)
              Tests  1088 passed (1088)
test:e2e:settings-50: PASS 26 legacy Settings URLs resolve to their canonical homes
                      PASS the Calendar overflow menu opens its Tab Settings page

Settings open timing

  • bench/settings-shortcut.mjs (1440, /settings/plugins, 30 runs, shared host with load average about 26): open p50 291 ms, p95 664 ms, mean 348 ms; browser CPU per open p50 495 ms; JS heap 19.3 MB. Burst of 50 Cmd+, presses: 644 ms, Settings stayed open.
  • Cmd+, from Today until #sec-active exists (7 warm opens): 299, 223, 257, 300, 207, 244, 177 ms.

Open for review (not changed)

  1. 8 of the 13 Tabs pages are empty ("This Plugin has no settings for this User."): Analytics, Files, Notes, Notifications, Search, System, Tags, Video. The Plugins list also shows a "Settings" pill for some of these. S2 says one page per enabled Plugin, but the S2 goal is a short Settings. Proposal: hide pages with no groups, at least for the core plugins (System, Search, Tags). This needs an owner decision.
  2. Tabs and Admin rows appear 1–3 s after Settings opens (deferred catalog and role load, #642), so the rail jumps. A cached catalog, as for the cached User, would remove the jump.
  3. On touch, every list row shows a Copy link icon (the rule for coarse pointers). This is noisy on the phone list. A swipe action (owner rule) would be cleaner.
  4. In Admin → Plugins at 390 px, the row's Copy link wraps below the description.
  5. Sync & Backup and Account Providers are "not available" pages (they have no backend yet; this is not fake data).

Screenshots: 208 captures (every section at 390/820/1440, light and dark, Mac platform signals) plus 40 review-flow captures, kept locally for the visual review.

## settings-50 verification and finish (branch `job/settings-50`, head `656d22421`) Picks up the verification that was cut at the time limit. Web-only; no Rust changed. Server: prebuilt `merge-round-7a` debug binary, run in a private mount namespace so its runtime `rust-embed` folder serves this worktree's `apps/web/build`. ### Bugs found and fixed - **Phone Back was broken.** `afterNavigate` read `from.url.pathname`; `from.url` is null on the first callback. The throw aborted SvelteKit's callbacks, so Back (button or browser) from a pushed page changed the URL to `/settings` but kept the detail page. Now `from?.url?.pathname`, and `to` falls back to `page.url`. - **Two Back buttons on a touch tablet (820 px).** The sheet is used whenever the pointer is not fine, but the desktop Back was hidden only below 768 px. It is now hidden whenever the sheet owns Back. - **Settings → Shortcuts showed no keys on touch.** `Kbd` hides hint caps on touch devices. A new `reference` prop keeps them visible on this list. Caps now line up with the first line of a wrapped label. - **Row dividers.** Hairlines removed from shortcut rows, Location (Saved places and the place form), External Calendars add form, and Connected Accounts advanced settings. - **Plugin row Copy link** showed as a bare bordered button (the `segment` variant needs a PillGroup), and its hover reveal rule came before the hide rule, so hover never showed it. Now `variant="pill"`, with the rules in the right order. Calendar feeds, MCP event subscriptions and External Calendars links also use the pill variant now. - **Sheet title repeated "User"** above the "User" group on the phone list. Before any heading crosses, only a large title can take the compact title; until then the sheet shows "Settings". - **Rail truncated** "Connected Accounts" and "Account Providers". The default width is now 248 px. - **Type check failed (7 errors).** The branch had a copy of #542's server preset sync (`/api/v1/shortcuts/preferences`), which is only on `job/shortcuts-542`. I removed the preset row, its search labels and the sign-in sync from this branch; #542 adds them back. Also fixed `'to' is possibly 'null'`. - Stale tests now follow the DESIGN §50 IDs (`apps-devices`, `admin/app-access`, `/settings/tabs/calendar/add`) and Title Case (`Your Accounts`). The review e2e had wrong selectors (phone detail heading, card `aria-busy`, dotted ID `app.settings`) and pressed Cmd+K before its handler was attached. - DESIGN §33 now gives the Background Work slugs (it still said Maintenance), and §50 S5 now says there is no inline search field. **Maintenance naming:** the tree no longer uses "Maintenance". DESIGN §50 names both pages **Background Work** and S3 says the same name twice is fine at two scopes, so I left both labels as they are. ### Gates (verbatim) ``` svelte-check: COMPLETED 2000 FILES 0 ERRORS 0 WARNINGS 0 FILES_WITH_PROBLEMS bun run test: Test Files 155 passed (155) Tests 1088 passed (1088) test:e2e:settings-50: PASS 26 legacy Settings URLs resolve to their canonical homes PASS the Calendar overflow menu opens its Tab Settings page ``` ### Settings open timing - `bench/settings-shortcut.mjs` (1440, `/settings/plugins`, 30 runs, shared host with load average about 26): open p50 291 ms, p95 664 ms, mean 348 ms; browser CPU per open p50 495 ms; JS heap 19.3 MB. Burst of 50 Cmd+, presses: 644 ms, Settings stayed open. - Cmd+, from Today until `#sec-active` exists (7 warm opens): 299, 223, 257, 300, 207, 244, 177 ms. ### Open for review (not changed) 1. **8 of the 13 Tabs pages are empty** ("This Plugin has no settings for this User."): Analytics, Files, Notes, Notifications, Search, System, Tags, Video. The Plugins list also shows a "Settings" pill for some of these. S2 says one page per enabled Plugin, but the S2 goal is a short Settings. Proposal: hide pages with no groups, at least for the core plugins (System, Search, Tags). This needs an owner decision. 2. **Tabs and Admin rows appear 1–3 s after Settings opens** (deferred catalog and role load, #642), so the rail jumps. A cached catalog, as for the cached User, would remove the jump. 3. On touch, every list row shows a Copy link icon (the rule for coarse pointers). This is noisy on the phone list. A swipe action (owner rule) would be cleaner. 4. In Admin → Plugins at 390 px, the row's Copy link wraps below the description. 5. Sync & Backup and Account Providers are "not available" pages (they have no backend yet; this is not fake data). Screenshots: 208 captures (every section at 390/820/1440, light and dark, Mac platform signals) plus 40 review-flow captures, kept locally for the visual review.
Author
Owner

Owner decision (2026-10-03): hide per-plugin Settings pages that have no settings for the User; a page appears automatically once a plugin offers at least one setting. Also: cache the plugin list so Tabs/Admin rows don't jump in, and on touch use the swipe Copy link action instead of an icon on every row.

Owner decision (2026-10-03): hide per-plugin Settings pages that have no settings for the User; a page appears automatically once a plugin offers at least one setting. Also: cache the plugin list so Tabs/Admin rows don't jump in, and on touch use the swipe Copy link action instead of an icon on every row.
Author
Owner

Starting Settings production round on job/round-settings, base cfee85c6b11537968aaa0685d1ed1c3ac68a8c3e. Integrate job/oneacct-1014 (includes Settings §50), resolve against origin/dev, verify Settings and Connected Accounts, and prepare staging evidence. Production is out of scope. Known plugin-list cache and touch Copy link follow-ups remain out of this round.

Starting Settings production round on `job/round-settings`, base `cfee85c6b11537968aaa0685d1ed1c3ac68a8c3e`. Integrate `job/oneacct-1014` (includes Settings §50), resolve against origin/dev, verify Settings and Connected Accounts, and prepare staging evidence. Production is out of scope. Known plugin-list cache and touch Copy link follow-ups remain out of this round.
Author
Owner

Integration finding: job/oneacct-1014 fast-forwarded from cfee85c6b to 12893025e. The one required origin/dev refresh then merged #724 at c64119671, without conflicts. The Settings slice changes web/UI only. The dev refresh changes calternal-fs, calternal-notes-core, calternal-plugin-notes and calternal-plugin-calendar; these get sequential Rust gates. No changed routes or OpenAPI contract. The staging Users have zero Connected Accounts. Staging smoke will use temporary real API rows, with no API interception; provider login/successful external sync is not claimed.

Integration finding: `job/oneacct-1014` fast-forwarded from `cfee85c6b` to `12893025e`. The one required origin/dev refresh then merged #724 at `c64119671`, without conflicts. The Settings slice changes web/UI only. The dev refresh changes calternal-fs, calternal-notes-core, calternal-plugin-notes and calternal-plugin-calendar; these get sequential Rust gates. No changed routes or OpenAPI contract. The staging Users have zero Connected Accounts. Staging smoke will use temporary real API rows, with no API interception; provider login/successful external sync is not claimed.
Author
Owner

Gate finding: the merged Calendar account heading used font-weight: 600 at CalendarsSection.svelte:381. Full Vitest: 155 files/1091 tests passed, one shared font-weight guard failed. Replaced the numeric value with var(--weight-semibold) (the same 600 weight). The original assertion is unchanged. Focused guard + Calendar, Mail and Connected Accounts tests: 4 files, 23 tests passed. Production assets rebuilt after this fix.

Gate finding: the merged Calendar account heading used `font-weight: 600` at CalendarsSection.svelte:381. Full Vitest: 155 files/1091 tests passed, one shared font-weight guard failed. Replaced the numeric value with `var(--weight-semibold)` (the same 600 weight). The original assertion is unchanged. Focused guard + Calendar, Mail and Connected Accounts tests: 4 files, 23 tests passed. Production assets rebuilt after this fix.
Author
Owner

Evidence finding: Settings review initially rendered the prebuilt server’s old embedded UI because the scripts did not call routeCurrentBuild. Added the existing production-asset helper to the Settings and Connected Accounts review contexts. No test expectations changed. The corrected run captures this branch’s production build at macOS platform signals and all required widths/themes.

Staging limitation: both available staging sessions have zero Connected Accounts, and creation requires a successful provider login. A private input-file path was requested; credentials are never requested in chat. Without it, staging can prove real empty states only, and the populated-account smoke remains incomplete.

Evidence finding: Settings review initially rendered the prebuilt server’s old embedded UI because the scripts did not call `routeCurrentBuild`. Added the existing production-asset helper to the Settings and Connected Accounts review contexts. No test expectations changed. The corrected run captures this branch’s production build at macOS platform signals and all required widths/themes. Staging limitation: both available staging sessions have zero Connected Accounts, and creation requires a successful provider login. A private input-file path was requested; credentials are never requested in chat. Without it, staging can prove real empty states only, and the populated-account smoke remains incomplete.
Author
Owner

Final web gates after the Calendar heading-token fix:

svelte-check found 0 errors and 0 warnings
Test Files  156 passed (156)
Tests  1092 passed (1092)

Settings #407 review passed at 390/820/1440 in light/dark, including 26 legacy Settings redirects and the Calendar overflow Settings action. Production assets were served with the existing override helper against the prebuilt API server. Notes-plugin tests: 186 passed, 1 ignored (real-server upgrade E2E fixture), plus the integration test passed. Calendar gates and Connected Accounts review are running.

Final web gates after the Calendar heading-token fix: ```text svelte-check found 0 errors and 0 warnings Test Files 156 passed (156) Tests 1092 passed (1092) ``` Settings #407 review passed at 390/820/1440 in light/dark, including 26 legacy Settings redirects and the Calendar overflow Settings action. Production assets were served with the existing override helper against the prebuilt API server. Notes-plugin tests: 186 passed, 1 ignored (real-server upgrade E2E fixture), plus the integration test passed. Calendar gates and Connected Accounts review are running.
Author
Owner

Connected Accounts production UI review passed: 66 macOS-rendered captures across 390/820/1440 light/dark; provider setup, switches, Copy link menus, Mail options, Calendar options and Manage links exercised. The populated UI rows in this local review are test fixtures. Label alignment offsets were 0.0078125–0.015625 px.

Focused real-server contract and two-User isolation check passed:

PASS bounded local integrations contract: authenticated reads, anonymous 401, schema rejection, empty cross-Plugin state
PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged

Calendar Clippy completed successfully. The long-running sequential gate shell was interrupted with exit 143 before it started Calendar tests; the missing cargo test -p calternal-plugin-calendar -- --test-threads=4 is now running separately. The passed commands are not repeated.

Connected Accounts production UI review passed: 66 macOS-rendered captures across 390/820/1440 light/dark; provider setup, switches, Copy link menus, Mail options, Calendar options and Manage links exercised. The populated UI rows in this local review are test fixtures. Label alignment offsets were 0.0078125–0.015625 px. Focused real-server contract and two-User isolation check passed: ```text PASS bounded local integrations contract: authenticated reads, anonymous 401, schema rejection, empty cross-Plugin state PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged ``` Calendar Clippy completed successfully. The long-running sequential gate shell was interrupted with exit 143 before it started Calendar tests; the missing `cargo test -p calternal-plugin-calendar -- --test-threads=4` is now running separately. The passed commands are not repeated.
Author
Owner

Local review artifacts are attached to #407 (macOS, all widths/themes). Connected Accounts population uses explicit test fixtures; staging will use only real API rows.

Local review artifacts are attached to #407 (macOS, all widths/themes). Connected Accounts population uses explicit test fixtures; staging will use only real API rows. - [settings-round-fcd9f38b8-local-1440.zip](https://git.kayg.org/attachments/cce66278-4e8b-4932-86f2-256098e7ef4b) - [settings-round-fcd9f38b8-local-390.zip](https://git.kayg.org/attachments/3fa29337-9cdd-4e73-8f08-13a2a5f57ffe) - [settings-round-fcd9f38b8-local-820.zip](https://git.kayg.org/attachments/ef8f2774-865b-4213-8d47-2bdc26e30a98)
Author
Owner

All requested per-crate Rust gates passed. cargo fmt --check returned 0 with no output.

cargo clippy -p calternal-fs --all-targets -- -D warnings and cargo test -p calternal-fs -- --test-threads=4:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 17.02s
test result: ok. 59 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 10.46s
test result: ok. 44 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.01s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-notes-core --all-targets -- -D warnings and cargo test -p calternal-notes-core -- --test-threads=4:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 20.96s
test result: ok. 523 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.36s
test result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.59s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.69s
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings and cargo test -p calternal-plugin-notes -- --test-threads=4:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 4m 27s
test result: ok. 186 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 277.98s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.21s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings and cargo test -p calternal-plugin-calendar -- --test-threads=4:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 6m 06s
test result: ok. 88 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 11.42s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.31s
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.17s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Staging image build started from 92634987e, with the assigned target, four Cargo jobs, OPENSSL_NO_VENDOR=1 and this worktree’s production web build. It uses the shared existing recipe in scripts/staging-724-build.sh, with CALTERNAL_BUILD_BRANCH=job/round-settings.

All requested per-crate Rust gates passed. `cargo fmt --check` returned 0 with no output. `cargo clippy -p calternal-fs --all-targets -- -D warnings` and `cargo test -p calternal-fs -- --test-threads=4`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 17.02s test result: ok. 59 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 10.46s test result: ok. 44 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.01s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-notes-core --all-targets -- -D warnings` and `cargo test -p calternal-notes-core -- --test-threads=4`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 20.96s test result: ok. 523 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.36s test result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.59s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.69s test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings` and `cargo test -p calternal-plugin-notes -- --test-threads=4`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 4m 27s test result: ok. 186 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 277.98s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.21s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings` and `cargo test -p calternal-plugin-calendar -- --test-threads=4`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 6m 06s test result: ok. 88 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 11.42s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.31s test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.17s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` Staging image build started from `92634987e`, with the assigned target, four Cargo jobs, OPENSSL_NO_VENDOR=1 and this worktree’s production web build. It uses the shared existing recipe in `scripts/staging-724-build.sh`, with `CALTERNAL_BUILD_BRANCH=job/round-settings`.
Author
Owner

UX finding in the inherited account contract: ConnectedAccountsSection.svelte disables Mail when it is the account’s last active service; integrations.rs:update_account returns 400 with “Keep at least one service enabled” if both become off. The existing #407 reconciliation notes explicitly retain that rule for new create/update requests. Thus the Mail-off smoke uses an account that also has Calendar enabled, as the inherited #1014 review does. A Mail-only account cannot be paused through its switch. I have not changed this Server behavior in the Settings integration round; it remains a UX gap for owner review.

UX finding in the inherited account contract: ConnectedAccountsSection.svelte disables Mail when it is the account’s last active service; `integrations.rs:update_account` returns 400 with “Keep at least one service enabled” if both become off. The existing #407 reconciliation notes explicitly retain that rule for new create/update requests. Thus the Mail-off smoke uses an account that also has Calendar enabled, as the inherited #1014 review does. A Mail-only account cannot be paused through its switch. I have not changed this Server behavior in the Settings integration round; it remains a UX gap for owner review.
Author
Owner

Candidate image built successfully from 92634987e97d428741829706e50f39a6c934afe4:

Successfully tagged localhost/calternal-cloud:staging-92634987e
STAGING_IMAGE_READY staging-92634987e

The live XUser runner stopped during setup because it requires debug/calternal, while the staging recipe builds the CLI in release/. The release CLI exists and is the same candidate. Added a target-directory symlink (not repository source) at the expected test location and resumed within the existing 15-minute round budget. No expectations were changed. The completed preparation already confirmed revoked-share and missing-item HTTP 404 profiles match (median delta 0.9 ms, 12 alternating pairs).

Candidate image built successfully from `92634987e97d428741829706e50f39a6c934afe4`: ```text Successfully tagged localhost/calternal-cloud:staging-92634987e STAGING_IMAGE_READY staging-92634987e ``` The live XUser runner stopped during setup because it requires `debug/calternal`, while the staging recipe builds the CLI in `release/`. The release CLI exists and is the same candidate. Added a target-directory symlink (not repository source) at the expected test location and resumed within the existing 15-minute round budget. No expectations were changed. The completed preparation already confirmed revoked-share and missing-item HTTP 404 profiles match (median delta 0.9 ms, 12 alternating pairs).
Author
Owner

Settings production round — #407

Head: dae797a33635374c3ca94f66ea70b3bff362e1fc.

Integrated job/oneacct-1014 (includes Settings §50), then merged origin/dev once. The origin/dev refresh also includes #724. No conflicts or contract regeneration were required.

Files and changes

  • Settings and Connected Accounts source changes from the two job branches (108 changed files in total against the starting base).
  • apps/web/src/routes/settings/calendars/CalendarsSection.svelte: use the shared semibold token; the numeric-weight guard found this.
  • apps/web/e2e/settings-review-50.mjs and integrations-review.mjs: use current production assets with a prebuilt API server.
  • apps/web/e2e/staging-settings-407.mjs: real staging data, required widths/themes, service-off consistency, cleanup and preference restoration.
  • scripts/staging-724-build.sh: one image recipe with an explicit job-branch override; the default remains unchanged.
  • tests/adversarial/test_settings_private_inputs.py: test the actual staging entry point with malformed private JSON. The failure output must not include its contents.

Gates (verbatim)

cargo fmt --check exited 0 and emitted no output. Other gate output follows.

cargo clippy -p calternal-fs --all-targets -- -D warnings and cargo test -p calternal-fs -- --test-threads=4:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 17.02s
test result: ok. 59 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 10.46s
test result: ok. 44 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.01s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-notes-core --all-targets -- -D warnings and cargo test -p calternal-notes-core -- --test-threads=4:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 20.96s
test result: ok. 523 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.36s
test result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.59s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.69s
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings and cargo test -p calternal-plugin-notes -- --test-threads=4:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 4m 27s
test result: ok. 186 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 277.98s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.21s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings and cargo test -p calternal-plugin-calendar -- --test-threads=4:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 6m 06s
test result: ok. 88 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 11.42s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.31s
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.17s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

web-check-final.log:

svelte-check found 0 errors and 0 warnings

web-test-final.log:

 Test Files  156 passed (156)
      Tests  1092 passed (1092)

settings-e2e.log:

PASS 26 legacy Settings URLs resolve to their canonical homes
PASS the Calendar overflow menu opens its Tab Settings page
Settings #407 review screenshots saved under /home/kayg/Developer/calternal-wt/round-settings/artifacts/settings-50/review

accounts-e2e.log:

PASS Connected Accounts and service Settings review: 66 screenshots in /home/kayg/Developer/calternal-wt/round-settings/artifacts/connected-accounts

accounts-isolation-candidate.log (exact release candidate):

PASS bounded local integrations contract: authenticated reads, anonymous 401, schema rejection, empty cross-Plugin state
PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged

xuser-classification.log:

Cross-User classification gate: 342 operations classified
Generated entry point classification: 960 tools classified

Local screenshots

Mac platform signals, 390/820/1440 px, light and dark. Settings review: 40 captures; Connected Accounts review: 66. Connected Account populations in the local UI review are test fixtures; the API isolation test uses real sessions and an inert test-owned row.

UX gaps closed

  • One home for account management: Connected Accounts. Mail and Calendar expose service options and Manage links.
  • Calendar heading now uses the shared weight token.
  • Review harness cannot silently capture the prebuilt server’s old UI when asset override is requested.
  • Optional staging setup preserves existing accounts. Parse failures cannot print private input excerpts.

UX gaps left

  • Existing contract requires one active service: a Mail-only account cannot be paused through its last switch. A dual-service account can turn Mail off. This was reported with UI and Server evidence.
  • Empty per-plugin Settings pages remain visible, despite the latest owner follow-up. Plugin-list caching and touch swipe Copy link were explicitly excluded from this round.
  • Global Mail remote-content preference is not backed by the current API; no fake control was shipped.

Decisions

  • No new product decision. Reused the existing staging build recipe with a branch override; preserved its default.
  • Staging smoke accepts private account inputs from a local file; it never logs provider inputs or intercepts the API.

Release and isolation gates (verbatim)

Production web build:

✓ built in 43.52s
✓ built in 100ms
✓ built in 1m 33s
  Wrote site to "build"

Staging release build:

    Finished `release` profile [optimized] target(s) in 22m 57s
STAGING_IMAGE_READY staging-92634987e

The live matrix ran against that release candidate. The first setup attempt found no debug CLI; a symlink in the assigned target directory pointed to the built release CLI. No source or test expectation changed. The matrix completed within its single time-boxed round.

Two-User OpenAPI matrix: 342 operations classified; 159 operations replayed; 733 A-ID vs missing-ID comparisons across B, C, D and anonymous; 25 identifier routes classified with no local fixture factory; median absolute timing delta 0.5 ms
Job/Mail/quota ownership checks: 97 comparisons; 0 denial failures
Revoked Share timing control: identical HTTP 404 profiles; median delta 3.7 ms across 12 alternating pairs

The 25 routes without generic fixture factories are a coverage limit. The focused Connected Accounts test above covers foreign account PATCH/DELETE with a seeded row and real sessions. Provider sync itself was not verified.

python3 -m unittest discover -s tests/adversarial -p test_settings_private_inputs.py:

.
----------------------------------------------------------------------
Ran 1 test in 0.047s

OK

Rust tests ran sequentially with four test threads. The initial gate wrapper stopped after Calendar clippy; only the missing Calendar tests were resumed. The full web suite initially found the numeric font-weight guard; after the token fix, the focused tests and full suite passed. No existing expectations were changed.

Staging

Deployed localhost/calternal-cloud:staging-92634987e to staging only. Production was not touched. Image build source: 92634987e97d428741829706e50f39a6c934afe4. Later commits change only staging test safety and its Python regression test; compiled app/server inputs are identical to the final head.

The supplied deployment script was read and used. The staging environment file was verified unchanged. Deployed image identity matches the local image.

STAGING_ENV_PRESERVED yes
staging deployed localhost/calternal-cloud:staging-92634987e: healthy
STAGING_DEPLOY_EXIT 0
STAGING_IMAGE_MATCH yes
STAGING_PUBLIC_HEALTH 200
STAGING_ENV_PRESERVED yes

Staging smoke produced 24 real-API captures: Settings home, Connected Accounts, Mail and Calendars, each at 390/820/1440 px in light/dark with macOS platform signals. Appearance was restored. Browser error assertions passed. These captures show real empty states; populated local review captures use explicit test fixtures.

STAGING ACCOUNTS: connected=0, Mail=0, Calendar=0
GAP Staging needs two Mail accounts and one CalDAV account for the populated smoke.
GAP Mail-off smoke needs an account with both Mail and Calendar enabled.
SETTINGS STAGING SMOKE: INCOMPLETE

This smoke exited 2 to report incomplete coverage. No private provider-input file was supplied. Thus account uniqueness with two real Mail accounts and one CalDAV account, and Mail-off stopping sync on staging, remain unverified.

For the merge round

Complete the populated staging smoke with approved private provider inputs. Use an empty test User and at least one account with both Mail and Calendar enabled. The optional setup removes only accounts it creates and restores preferences:

CALTERNAL_SETTINGS_ACCOUNT_INPUTS=/private/path.json bun apps/web/e2e/staging-settings-407.mjs

It must prove each account appears once, service pages contain their options and Manage links, and turning Mail off stops sync. If staging already has the required accounts, omit the input-file variable. Full global e2e and Mac interop remain merge-round scope. Performance measurements were not run because this issue is not about performance, per the final verification policy.

Cleanup and status

Doc comments in changed files were reviewed. git diff --check passed; the worktree is clean. Cargo and web build output were removed; review artifacts remain ignored.

     Removed 20347 files, 8.9GiB total

Local commits only. No push, no dev/main merge, no production deployment. The job branch contains the requested integration and the single origin/dev refresh.

SETTINGS ROUND READY FOR PRODUCTION: no — the required populated staging smoke remains incomplete.

# Settings production round — #407 Head: `dae797a33635374c3ca94f66ea70b3bff362e1fc`. Integrated `job/oneacct-1014` (includes Settings §50), then merged origin/dev once. The origin/dev refresh also includes #724. No conflicts or contract regeneration were required. ## Files and changes - Settings and Connected Accounts source changes from the two job branches (108 changed files in total against the starting base). - `apps/web/src/routes/settings/calendars/CalendarsSection.svelte`: use the shared semibold token; the numeric-weight guard found this. - `apps/web/e2e/settings-review-50.mjs` and `integrations-review.mjs`: use current production assets with a prebuilt API server. - `apps/web/e2e/staging-settings-407.mjs`: real staging data, required widths/themes, service-off consistency, cleanup and preference restoration. - `scripts/staging-724-build.sh`: one image recipe with an explicit job-branch override; the default remains unchanged. - `tests/adversarial/test_settings_private_inputs.py`: test the actual staging entry point with malformed private JSON. The failure output must not include its contents. ## Gates (verbatim) `cargo fmt --check` exited 0 and emitted no output. Other gate output follows. `cargo clippy -p calternal-fs --all-targets -- -D warnings` and `cargo test -p calternal-fs -- --test-threads=4`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 17.02s test result: ok. 59 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 10.46s test result: ok. 44 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.01s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-notes-core --all-targets -- -D warnings` and `cargo test -p calternal-notes-core -- --test-threads=4`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 20.96s test result: ok. 523 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.36s test result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.59s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.69s test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings` and `cargo test -p calternal-plugin-notes -- --test-threads=4`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 4m 27s test result: ok. 186 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 277.98s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.21s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings` and `cargo test -p calternal-plugin-calendar -- --test-threads=4`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 6m 06s test result: ok. 88 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 11.42s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.31s test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.17s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `web-check-final.log`: ```text svelte-check found 0 errors and 0 warnings ``` `web-test-final.log`: ```text Test Files 156 passed (156) Tests 1092 passed (1092) ``` `settings-e2e.log`: ```text PASS 26 legacy Settings URLs resolve to their canonical homes PASS the Calendar overflow menu opens its Tab Settings page Settings #407 review screenshots saved under /home/kayg/Developer/calternal-wt/round-settings/artifacts/settings-50/review ``` `accounts-e2e.log`: ```text PASS Connected Accounts and service Settings review: 66 screenshots in /home/kayg/Developer/calternal-wt/round-settings/artifacts/connected-accounts ``` `accounts-isolation-candidate.log` (exact release candidate): ```text PASS bounded local integrations contract: authenticated reads, anonymous 401, schema rejection, empty cross-Plugin state PASS real-session two-User integrations matrix: owner list=1, member list=0, foreign PATCH/DELETE=404, owner row unchanged ``` `xuser-classification.log`: ```text Cross-User classification gate: 342 operations classified Generated entry point classification: 960 tools classified ``` ## Local screenshots Mac platform signals, 390/820/1440 px, light and dark. Settings review: 40 captures; Connected Accounts review: 66. Connected Account populations in the local UI review are test fixtures; the API isolation test uses real sessions and an inert test-owned row. - [settings-round-fcd9f38b8-local-1440.zip](https://git.kayg.org/attachments/cce66278-4e8b-4932-86f2-256098e7ef4b) - [settings-round-fcd9f38b8-local-390.zip](https://git.kayg.org/attachments/3fa29337-9cdd-4e73-8f08-13a2a5f57ffe) - [settings-round-fcd9f38b8-local-820.zip](https://git.kayg.org/attachments/ef8f2774-865b-4213-8d47-2bdc26e30a98) ## UX gaps closed - One home for account management: Connected Accounts. Mail and Calendar expose service options and Manage links. - Calendar heading now uses the shared weight token. - Review harness cannot silently capture the prebuilt server’s old UI when asset override is requested. - Optional staging setup preserves existing accounts. Parse failures cannot print private input excerpts. ## UX gaps left - Existing contract requires one active service: a Mail-only account cannot be paused through its last switch. A dual-service account can turn Mail off. This was reported with UI and Server evidence. - Empty per-plugin Settings pages remain visible, despite the latest owner follow-up. Plugin-list caching and touch swipe Copy link were explicitly excluded from this round. - Global Mail remote-content preference is not backed by the current API; no fake control was shipped. ## Decisions - No new product decision. Reused the existing staging build recipe with a branch override; preserved its default. - Staging smoke accepts private account inputs from a local file; it never logs provider inputs or intercepts the API. ## Release and isolation gates (verbatim) Production web build: ```text ✓ built in 43.52s ✓ built in 100ms ✓ built in 1m 33s Wrote site to "build" ``` Staging release build: ```text Finished `release` profile [optimized] target(s) in 22m 57s STAGING_IMAGE_READY staging-92634987e ``` The live matrix ran against that release candidate. The first setup attempt found no debug CLI; a symlink in the assigned target directory pointed to the built release CLI. No source or test expectation changed. The matrix completed within its single time-boxed round. ```text Two-User OpenAPI matrix: 342 operations classified; 159 operations replayed; 733 A-ID vs missing-ID comparisons across B, C, D and anonymous; 25 identifier routes classified with no local fixture factory; median absolute timing delta 0.5 ms Job/Mail/quota ownership checks: 97 comparisons; 0 denial failures Revoked Share timing control: identical HTTP 404 profiles; median delta 3.7 ms across 12 alternating pairs ``` The 25 routes without generic fixture factories are a coverage limit. The focused Connected Accounts test above covers foreign account PATCH/DELETE with a seeded row and real sessions. Provider sync itself was not verified. `python3 -m unittest discover -s tests/adversarial -p test_settings_private_inputs.py`: ```text . ---------------------------------------------------------------------- Ran 1 test in 0.047s OK ``` Rust tests ran sequentially with four test threads. The initial gate wrapper stopped after Calendar clippy; only the missing Calendar tests were resumed. The full web suite initially found the numeric font-weight guard; after the token fix, the focused tests and full suite passed. No existing expectations were changed. ## Staging Deployed `localhost/calternal-cloud:staging-92634987e` to staging only. Production was not touched. Image build source: `92634987e97d428741829706e50f39a6c934afe4`. Later commits change only staging test safety and its Python regression test; compiled app/server inputs are identical to the final head. The supplied deployment script was read and used. The staging environment file was verified unchanged. Deployed image identity matches the local image. ```text STAGING_ENV_PRESERVED yes staging deployed localhost/calternal-cloud:staging-92634987e: healthy STAGING_DEPLOY_EXIT 0 STAGING_IMAGE_MATCH yes STAGING_PUBLIC_HEALTH 200 STAGING_ENV_PRESERVED yes ``` Staging smoke produced 24 real-API captures: Settings home, Connected Accounts, Mail and Calendars, each at 390/820/1440 px in light/dark with macOS platform signals. Appearance was restored. Browser error assertions passed. These captures show real empty states; populated local review captures use explicit test fixtures. ```text STAGING ACCOUNTS: connected=0, Mail=0, Calendar=0 GAP Staging needs two Mail accounts and one CalDAV account for the populated smoke. GAP Mail-off smoke needs an account with both Mail and Calendar enabled. SETTINGS STAGING SMOKE: INCOMPLETE ``` This smoke exited 2 to report incomplete coverage. No private provider-input file was supplied. Thus account uniqueness with two real Mail accounts and one CalDAV account, and Mail-off stopping sync on staging, remain unverified. - [Staging 390 px, light/dark](https://git.kayg.org/attachments/aa0d35ba-affc-4134-b312-6fa104ea5ea9) - [Staging 820 px, light/dark](https://git.kayg.org/attachments/4a7557d5-b582-4c79-9409-cc7c65d544aa) - [Staging 1440 px, light/dark](https://git.kayg.org/attachments/21ab2400-13b0-4be6-b0e8-fd87295d52f4) ## For the merge round Complete the populated staging smoke with approved private provider inputs. Use an empty test User and at least one account with both Mail and Calendar enabled. The optional setup removes only accounts it creates and restores preferences: ```sh CALTERNAL_SETTINGS_ACCOUNT_INPUTS=/private/path.json bun apps/web/e2e/staging-settings-407.mjs ``` It must prove each account appears once, service pages contain their options and Manage links, and turning Mail off stops sync. If staging already has the required accounts, omit the input-file variable. Full global e2e and Mac interop remain merge-round scope. Performance measurements were not run because this issue is not about performance, per the final verification policy. ## Cleanup and status Doc comments in changed files were reviewed. `git diff --check` passed; the worktree is clean. Cargo and web build output were removed; review artifacts remain ignored. ```text Removed 20347 files, 8.9GiB total ``` Local commits only. No push, no dev/main merge, no production deployment. The job branch contains the requested integration and the single origin/dev refresh. **SETTINGS ROUND READY FOR PRODUCTION: no** — the required populated staging smoke remains incomplete.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#407
No description provided.