# ALAI Mail Topology — Migadu Domains, Mailbox Inventory, John's 19-Account Ingest Loop (2026-06-08)

# ALAI Mail Topology &amp; John's Email Ingest Loop

**Last updated:** 2026-06-08 (v2 — 19 accounts, daemon-path docs, himalaya touch-points) | **MC:** #103182 | **Built by:** FlowForge | **Validated by:** Proveo (Angie Jones) — PASS

---

## 1. Mail Infrastructure — Migadu (Single Account)

All ALAI product domains are hosted on **one Migadu account**. MX records for every domain point to the same two servers:

- `aspmx1.migadu.com` (priority 10)
- `aspmx2.migadu.com` (priority 20)

**Domains on this account:** `alai.no`, `bilko.io`, `bilko.cloud`, `bilko.company`, `snowit.ba`, `basicconsulting.no`, `basicfakta.no`, `lumiscare.com`

### Migadu Admin Access

<table id="bkmrk-itemvalue-%2F-location"> <thead><tr><th>Item</th><th>Value / Location</th></tr></thead> <tbody> <tr><td>Admin login</td><td>`alem@alai.no`</td></tr> <tr><td>API key</td><td>Vaultwarden item **"migadu keyy"** (86-char token — do NOT print)</td></tr> <tr><td>IMAP host</td><td>`imap.migadu.com`</td></tr> <tr><td>SMTP host</td><td>`smtp.migadu.com`</td></tr> <tr><td>Web UI</td><td>[https://admin.migadu.com](https://admin.migadu.com)</td></tr> </tbody></table>

### Migadu API Quirks (DO NOT FORGET)

- **GET aliases** — response key is `address_aliases`, not `aliases`.
- **Create alias** — must send JSON body `{"local_part": "...", "destinations": ["..."]}` with header `Accept: application/json` (omitting Accept = HTML response, silent fail).
- **Alias destinations MUST be same-domain.** Cross-domain targets (e.g. `info@alai.no → john@basicconsulting.no`) return HTTP 400. Route to a real mailbox on the same domain instead.
- **No catch-all rewrites** — verified via `/rewrites` endpoint (empty on all domains). Any email to a non-existent local-part that has no alias **bounces**.
- App-passwords for new mailboxes are created via `PUT /v1/domains/{domain}/mailboxes/{local_part}` and stored as Vaultwarden items (never in logs).
- **Migadu catch-all copy (alem@alai.no):** alem@alai.no is configured as a global catch-all copy recipient for all outgoing ALAI-managed-domain mail. This means emails sent FROM any ALAI account will also appear in alem's INBOX. Because `alem` iterates before product accounts in the daemon list, it ingests those Message-IDs first; the UNIQUE(message\_id) constraint causes product-account inserts to be no-ops. This affects ingest attribution for ALAI-origin probes only — external (non-ALAI) mail is not affected. See Section 6 for forwarding removal note.

---

## 2. Real Mailbox Inventory

These are the real mailboxes that exist in Migadu (verified 2026-06-08 via admin API). Only real mailboxes can be used as alias destinations.

<table id="bkmrk-domainreal-mailboxes"> <thead><tr><th>Domain</th><th>Real mailboxes (local parts)</th></tr></thead> <tbody> <tr><td>`alai.no`</td><td>john, alem, dev, post, admin</td></tr> <tr><td>`bilko.io`</td><td>admin, sales, privacy</td></tr> <tr><td>`bilko.cloud`</td><td>admin, sales</td></tr> <tr><td>`bilko.company`</td><td>admin, sales</td></tr> <tr><td>`snowit.ba`</td><td>admin, info, asmir, enis</td></tr> <tr><td>`basicconsulting.no`</td><td>john, info</td></tr> <tr><td>`lumiscare.com`</td><td>hello, admin</td></tr> </tbody></table>

*Note: `basicfakta.no` is on this Migadu account but has no actively polled mailboxes in John's loop.*

*Note: `lumiscare.com` is ALAI's Migadu domain (our infrastructure). It is distinct from `caresafetyinnovations.com`, which remains a hard-stop boundary (see Section 6).*

---

## 3. John's Email Ingest — All 19 Monitored Accounts

John's email ingest is managed by `~/system/tools/email-inbox.js` and polled by `~/system/daemons/email-agent.js`. As of MC #103182 final state (2026-06-08), **19 accounts** are registered in `email-inbox.db → email_accounts`.

### Original 6 Accounts (pre-MC #103182)

<table id="bkmrk-account-name-%28db-key"> <thead><tr><th>Account name (DB key)</th><th>Email address</th><th>Vault item</th></tr></thead> <tbody> <tr><td>`john`</td><td>john@basicconsulting.no</td><td>existing</td></tr> <tr><td>`info`</td><td>info@basicconsulting.no</td><td>existing</td></tr> <tr><td>`alai`</td><td>john@alai.no</td><td>existing</td></tr> <tr><td>`dev`</td><td>dev@alai.no</td><td>existing</td></tr> <tr><td>`alem`</td><td>alem@alai.no</td><td>existing</td></tr> <tr><td>`gmail`</td><td>alembasic@gmail.com</td><td>existing</td></tr> </tbody></table>

### 11 Product/Role Accounts (added MC #103182 round 1)

<table id="bkmrk-account-name-%28db-key-1"> <thead><tr><th>Account name (DB key)</th><th>Email address</th><th>Vault item name</th></tr></thead> <tbody> <tr><td>`post-alai`</td><td>post@alai.no</td><td>Migadu — post@alai.no</td></tr> <tr><td>`admin-alai`</td><td>admin@alai.no</td><td>Migadu — admin@alai.no</td></tr> <tr><td>`sales-bilko-io`</td><td>sales@bilko.io</td><td>Migadu — sales@bilko.io</td></tr> <tr><td>`privacy-bilko-io`</td><td>privacy@bilko.io</td><td>Migadu — privacy@bilko.io</td></tr> <tr><td>`admin-bilko-io`</td><td>admin@bilko.io</td><td>Migadu — admin@bilko.io</td></tr> <tr><td>`sales-bilko-cloud`</td><td>sales@bilko.cloud</td><td>Migadu — sales@bilko.cloud</td></tr> <tr><td>`admin-bilko-cloud`</td><td>admin@bilko.cloud</td><td>Migadu — admin@bilko.cloud</td></tr> <tr><td>`sales-bilko-company`</td><td>sales@bilko.company</td><td>Migadu — sales@bilko.company</td></tr> <tr><td>`admin-bilko-company`</td><td>admin@bilko.company</td><td>Migadu — admin@bilko.company</td></tr> <tr><td>`info-snowit`</td><td>info@snowit.ba</td><td>info@snowit.ba IMAP</td></tr> <tr><td>`admin-snowit`</td><td>admin@snowit.ba</td><td>Migadu — admin@snowit.ba</td></tr> </tbody></table>

### 2 LumisCare Accounts (added MC #103182 round 2 — CEO directive 2026-06-08)

CEO directive: LumisCare must be in John's reading loop. `lumiscare.com` is ALAI's own Migadu domain — these are operational mailboxes, not CareSafety-boundary addresses.

<table id="bkmrk-account-name-%28db-key-2"> <thead><tr><th>Account name (DB key)</th><th>Email address</th><th>Vault item name</th></tr></thead> <tbody> <tr><td>`hello-lumiscare`</td><td>hello@lumiscare.com</td><td>Migadu — hello@lumiscare.com</td></tr> <tr><td>`admin-lumiscare`</td><td>admin@lumiscare.com</td><td>Migadu — admin@lumiscare.com</td></tr> </tbody></table>

**Note on hello@lumiscare.com forwarding:** A Migadu direct forward from `hello@lumiscare.com → alem@alai.no` was active since 2026-05-24. This was **removed 2026-06-08** so the mailbox is polled directly under `hello-lumiscare` with clean labeling. Before removal, LumisCare contact mail appeared in the DB under `alem` (Migadu ingested the forwarded copy first). After removal, external mail to hello@lumiscare.com is stored under `hello-lumiscare` only. Confirmed behaviourally: gmail-origin probe stored as DB id=9195 under `hello-lumiscare`, not duplicated under `alem`.

**App-passwords** for the 5 newly created `admin@*` mailboxes (round 1) were generated via the Migadu API and stored as Vaultwarden items. Vault IDs: 558181ec, 8dfe8d2d, 2f38a16a, 7d0f9216, 2fb07c20.

---

## 4. Alias Map — Dead-Address Fixes (2026-06-08)

The following addresses were previously advertised (on websites, legal pages, landing pages) but did not correspond to any real mailbox — all mail to them was silently bouncing. Migadu aliases were created to route them to the nearest real same-domain mailbox.

<table id="bkmrk-dead-address-%28was-bo"> <thead><tr><th>Dead address (was bouncing)</th><th>Now routes to</th><th>Why</th></tr></thead> <tbody> <tr><td>`info@alai.no`</td><td>`john@alai.no`</td><td>alai.no contact form was sending to this dead address — all website contact submissions were lost</td></tr> <tr><td>`support@bilko.io`</td><td>`sales@bilko.io`</td><td>bilko.io landing mailto link</td></tr> <tr><td>`podrska@bilko.io`</td><td>`sales@bilko.io`</td><td>bilko.io Bosnian support address on legal/terms pages</td></tr> <tr><td>`legal@bilko.io`</td><td>`admin@bilko.io`</td><td>bilko.io legal/terms page</td></tr> <tr><td>`security@bilko.io`</td><td>`admin@bilko.io`</td><td>bilko.io security disclosure address</td></tr> <tr><td>`support@bilko.cloud`</td><td>`sales@bilko.cloud`</td><td>bilko.cloud landing mailto</td></tr> <tr><td>`support@bilko.company`</td><td>`sales@bilko.company`</td><td>bilko.company landing mailto</td></tr> </tbody></table>

**Pre-fix state:** Only `postmaster@{domain} → admin@{domain}` aliases existed. No rewrites, no catch-all. All other non-existent local-parts bounced.  
**Post-fix:** All advertised addresses now deliver to a real monitored mailbox. Nothing bounces.

---

## 5. Contact-Form Routing

<table id="bkmrk-productcontact-form-"> <thead><tr><th>Product</th><th>Contact form path</th><th>Where mail ends up</th></tr></thead> <tbody> <tr> <td>alai.no website</td> <td>Vercel serverless: `~/business/ALAI-Holding-AS/web/api/contact.js` (nodemailer)</td> <td>Sends to `info@alai.no` (which now aliases to `john@alai.no` — monitored). *Was dead before 2026-06-08 fix.*</td> </tr> <tr> <td>Bilko landing pages</td> <td>Cloudflare Pages function: `apps/landing-*/functions/api/lead.js`</td> <td>Posts to Slack **\#ceo** channel (C0AFJDP9V6U) + writes to Cloudflare KV (`BILKO_LEADS`). No email path — separate from IMAP polling.</td> </tr> </tbody></table>

---

## 6. Boundary Accounts — NOT Polled (intentional)

<table id="bkmrk-addressreason-not-po"> <thead><tr><th>Address</th><th>Reason not polled</th></tr></thead> <tbody> <tr><td>`asmir@snowit.ba`</td><td>Personal mailbox belonging to Asmir (SnowIT partner). He reads his own mail.</td></tr> <tr><td>`enis@snowit.ba`</td><td>Personal mailbox belonging to Enis. Same reason.</td></tr> <tr><td>Any `*@caresafetyinnovations.com`</td><td>CareSafety hard-stop boundary — health/patient-adjacent service under external ownership. NOT on ALAI's Migadu account. Never poll. See CareSafety boundary memo in MEMORY.</td></tr> </tbody></table>

**Important distinction:** `lumiscare.com` (ALAI's Migadu domain — hello@, admin@) IS polled. `caresafetyinnovations.com` (external operator) is the hard boundary, not lumiscare.com.

---

## 7. Daemon Architecture — Production Path

Understanding the daemon path is critical when debugging ingest issues or adding accounts.

### Production Execution Path

- **LaunchAgent:** `com.john.email-agent` — starts `email-agent-wrapper.sh`, sets `HIMALAYA_DISABLED=1` via plist `EnvironmentVariables` key.
- **Wrapper:** `~/system/daemons/email-agent-wrapper.sh` — thin shell wrapper, does not set HIMALAYA\_DISABLED itself.
- **Daemon:** `~/system/daemons/email-agent.js` — when `HIMALAYA_DISABLED=1`, all 19 accounts use the **legacy unseen-fetch IMAP path** (direct node-imap, proven stable).

### Himalaya Layer — Present but Bypassed in Production

Even with `HIMALAYA_DISABLED=1`, the daemon still routes account resolution through `himalaya-adapter.js` ACCOUNT\_MAP. If an account name is missing from ACCOUNT\_MAP, the daemon throws `Unknown account: <name>` and the account is skipped entirely.

- **himalaya-adapter.js ACCOUNT\_MAP** — must list all 19 accounts (currently L34–56).
- **~/.config/himalaya/config.toml** — must have 19 `[accounts.*]` stanzas (verified: grep count = 19).
- When run without `HIMALAYA_DISABLED=1` (bare wrapper invocation), the himalaya binary is called and times out after 120s per account (~82 min total for 19 accounts). This is expected and non-destructive but slow. Production LaunchAgent always sets the env flag.

**Validated (2026-06-08T13:15Z):** Zero "Unknown account" errors in both daemon runs (wrapper + legacy). All 19 accounts have `last_checked_at = 2026-06-08T13:09:39Z`.

---

## 8. Components — All 8 Touch-Points

Adding any new account requires updating **all 8** of the following. Missing any one will cause silent failures or "Unknown account" errors.

<table id="bkmrk-%23filewhat-to-change-"> <thead><tr><th>\#</th><th>File</th><th>What to change</th></tr></thead> <tbody> <tr> <td>1</td> <td>`~/system/tools/email-inbox.js`</td> <td> (a) Add `INSERT OR IGNORE INTO email_accounts (name, email) VALUES ('<name>', '<email>')` seed row.  
 (b) **Add a guarded migration block** to extend the `emails` table CHECK constraint to include the new account name. The CHECK constraint is hardcoded and cannot be altered without rebuilding the table (SQLite limitation). The guard must use a unique string from the new account name (e.g. `!ddlRow.sql.includes("'<name>'")`). All existing rows and all 25 columns must be preserved in the rebuilt table. This is the most error-prone step — see Section 9 for the gotcha detail. </td> </tr> <tr> <td>2</td> <td>`~/system/tools/mail-native.js`</td> <td>Add account-name → Vaultwarden item-name entry in `VAULT_NAMES` map.</td> </tr> <tr> <td>3</td> <td>`~/system/tools/himalaya-adapter.js`</td> <td>Add account-name → email entry in `ACCOUNT_MAP` (L34–56 area). Without this, the daemon throws "Unknown account" and skips the account entirely even in legacy mode.</td> </tr> <tr> <td>4</td> <td>`~/.config/himalaya/config.toml`</td> <td>Add a new `[accounts.<name>]` stanza. Required even when HIMALAYA\_DISABLED=1.</td> </tr> <tr> <td>5</td> <td>`~/system/daemons/email-agent.js`</td> <td>Add account to counts map (L2459 area). Also confirm it is present in the fetch loop and `last_checked_at` update loop (both must be mirrored).</td> </tr> <tr> <td>6</td> <td>`~/system/tools/email-imap-db-audit.js`</td> <td>Add account to `ACCOUNTS` constant.</td> </tr> <tr> <td>7</td> <td>`~/system/tools/email-action-hard-check.js`</td> <td>Add account to `ALL_MONITORED_ACCOUNTS` constant.</td> </tr> <tr> <td>8</td> <td>Vaultwarden (via `bw` CLI)</td> <td>Create app-password item named `Migadu — <email>` with the IMAP/SMTP password. New admin@ mailboxes require a new app-password generated via Migadu API (`PUT /v1/domains/{d}/mailboxes/{lp}`). Existing sales@/privacy@/info@ mailboxes may already have creds in Vaultwarden — check before creating.</td> </tr> </tbody></table>

### Files Changed in MC #103182 (round 1 — 11 accounts)

All files modified additively. Round 1 changed 5 files (himalaya touch-points were added in round 2 as BLOCKER-2 fix).

<table id="bkmrk-filelines-changed-em"> <thead><tr><th>File</th><th>Lines changed</th></tr></thead> <tbody> <tr><td>`email-inbox.js`</td><td>L159–172 (seeds) + L141–208 (CHECK migration, 17-account guard)</td></tr> <tr><td>`mail-native.js`</td><td>L76–88 (11 VAULT\_NAMES entries)</td></tr> <tr><td>`email-imap-db-audit.js`</td><td>L51 (ACCOUNTS 5→16)</td></tr> <tr><td>`email-action-hard-check.js`</td><td>L14–22 (ALL\_MONITORED\_ACCOUNTS 17 accounts)</td></tr> <tr><td>`email-agent.js`</td><td>L1853–1861 (fetch loop), L1889–1895 (last\_checked\_at loop)</td></tr> </tbody></table>

### Files Changed in MC #103182 (round 2 — LumisCare + BLOCKER-2 fix)

<table id="bkmrk-filelines-changed-em-1"> <thead><tr><th>File</th><th>Lines changed</th></tr></thead> <tbody> <tr><td>`email-inbox.js`</td><td>L212–311 (second guarded CHECK migration, 19-account guard: `!ddlRow2.sql.includes("'hello-lumiscare'")`); 2 new email\_accounts seed rows</td></tr> <tr><td>`mail-native.js`</td><td>L90–91 (hello-lumiscare + admin-lumiscare VAULT\_NAMES)</td></tr> <tr><td>`himalaya-adapter.js`</td><td>L34–56 (ACCOUNT\_MAP expanded to 19 entries)</td></tr> <tr><td>`~/.config/himalaya/config.toml`</td><td>2 new \[accounts.\*\] stanzas (19 total)</td></tr> <tr><td>`email-agent.js`</td><td>L1862 (fetch loop), L1899 (last\_checked\_at loop), L2459–2468 (counts map)</td></tr> <tr><td>`email-action-hard-check.js`</td><td>L24 (hello-lumiscare + admin-lumiscare in ALL\_MONITORED\_ACCOUNTS)</td></tr> <tr><td>`email-imap-db-audit.js`</td><td>L60 (both accounts in ACCOUNTS array)</td></tr> </tbody></table>

### Known Minor Issue (pre-existing, non-blocking)

After SMTP send via `mail-native.js`, the IMAP post-send copy to Sent folder times out with `ETIMEOUT`. Delivery succeeds (Message-ID is logged). This is a cosmetic issue in the IMAP cleanup code — pre-existing, unrelated to MC #103182. Separate MC recommended.

---

## 9. GOTCHA — emails Table CHECK Constraint

This is the most dangerous footgun when adding new accounts. **Read before touching email-inbox.js.**

The `emails` table in `~/system/databases/email-inbox.db` has a hardcoded SQLite CHECK constraint:

```
account TEXT NOT NULL CHECK(account IN ('john','info','alai','dev','alem','gmail',
  'post-alai','admin-alai',
  'sales-bilko-io','privacy-bilko-io','admin-bilko-io',
  'sales-bilko-cloud','admin-bilko-cloud',
  'sales-bilko-company','admin-bilko-company',
  'info-snowit','admin-snowit',
  'hello-lumiscare','admin-lumiscare'
))
```

**The trap:** `INSERT OR IGNORE` silently discards rows that violate CHECK constraints — no exception is thrown, no warning is logged. If a new account name is not in this list, every email received by that account is permanently lost at ingest time. In MC #103182 this caused 27 real emails to be silently dropped before the issue was caught by Proveo.

**The fix:** SQLite does not support `ALTER TABLE ... MODIFY COLUMN` with a new CHECK constraint. The only way to extend it is to rebuild the table:

1. Read current DDL: `SELECT sql FROM sqlite_master WHERE type='table' AND name='emails'`
2. Guard the migration: check that the new account name is NOT already in the DDL (idempotency)
3. In a transaction: `CREATE TABLE emails_new (...same schema + extended CHECK...)` → `INSERT INTO emails_new SELECT * FROM emails` → assert row count matches → `DROP TABLE emails` → `ALTER TABLE emails_new RENAME TO emails` → recreate indexes → COMMIT
4. Rollback on any error or row count mismatch

The pattern already exists in `email-inbox.js` — follow it exactly. All 25 columns must be listed explicitly, including the post-migration additions: `delegated_to`, `delegated_at`, `deadline`, `body`, `triaged_at`, `auto_forwarded`.

---

## 10. Runbook — How to Add a New Mailbox to John's Loop

1. **Verify the mailbox exists in Migadu.**  
     Check via `GET /v1/domains/{domain}/mailboxes` using the admin API key ("migadu keyy" in Vaultwarden).  
     If it does not exist, create it via the admin UI or API first.
2. **Create an app-password for the mailbox.**  
     Use Migadu admin UI (Mailbox settings &gt; App Passwords) or `PUT /v1/domains/{domain}/mailboxes/{local_part}`.  
     Store the password as a new Vaultwarden item named `Migadu — {email}`.
3. **\[Touch-point 2\] Add to `mail-native.js` VAULT\_NAMES map.**  
     Key = your chosen account name (e.g. `sales-newdomain`), value = the Vaultwarden item name.
4. **\[Touch-point 3\] Add to `himalaya-adapter.js` ACCOUNT\_MAP.**  
     Add `'<name>': '<email>'` in the ACCOUNT\_MAP object. Without this step the daemon throws "Unknown account" and the account is silently skipped.
5. **\[Touch-point 4\] Add stanza to `~/.config/himalaya/config.toml`.**  
     Follow the existing pattern for a Migadu account stanza.
6. **\[Touch-point 1a\] Add the email\_accounts seed to `email-inbox.js`.**  
     Append `INSERT OR IGNORE INTO email_accounts (name, email) VALUES ('<name>', '<email>')` in the seed block.
7. **\[Touch-point 1b — CRITICAL\] Add a guarded CHECK migration to `email-inbox.js` getDb().**  
     Read Section 9 first. Guard: `!ddlRow.sql.includes("'<name>'")`. Extend CHECK to include new account. Rebuild table in a transaction preserving all 25 columns. Test idempotency.
8. **\[Touch-point 6\] Add to `email-imap-db-audit.js` ACCOUNTS array.**
9. **\[Touch-point 7\] Add to `email-action-hard-check.js` ALL\_MONITORED\_ACCOUNTS array.**
10. **\[Touch-point 5\] Add to `email-agent.js` counts map, fetch loop, and last\_checked\_at loop.**  
     All three locations must be mirrored.
11. **Run syntax checks on all modified files.**  
     `node --check ~/system/tools/email-inbox.js && node --check ~/system/tools/mail-native.js && node --check ~/system/tools/himalaya-adapter.js && node --check ~/system/daemons/email-agent.js`
12. **Test connectivity.**  
     `node ~/system/tools/mail-native.js test --account <name>` — expect IMAP OK + SMTP OK.
13. **Restart the email-agent daemon** (LaunchAgent: `com.john.email-agent`) so the updated accounts array and config take effect.
14. **Proveo ingest probe.**  
     Send a test email from a **non-ALAI sender** (e.g. gmail account) with subject `INGEST-PROBE-<name>-<timestamp>`. This avoids the Migadu catch-all pre-emption issue (see Section 1 API quirks). Trigger one daemon cycle. Confirm the row appears under the correct account name via `node ~/system/tools/email-inbox.js search "INGEST-PROBE"`.
15. **If adding a new alias (not a real mailbox):** create the Migadu alias first (same-domain destination only, with `Accept: application/json` header). Then proceed from step 3.

---

## 11. Validation Evidence (MC #103182 — Final)

### Round 1 (17 accounts — 2026-06-08T11:24Z)

<table id="bkmrk-checkresult-code-cha"> <thead><tr><th>Check</th><th>Result</th></tr></thead> <tbody> <tr><td>Code changes (5 files) verified by Proveo</td><td>PASS</td></tr> <tr><td>DB registry — 17 rows in email\_accounts</td><td>PASS</td></tr> <tr><td>IMAP/SMTP connectivity — 11/11 new accounts</td><td>PASS</td></tr> <tr><td>emails table CHECK migration (emails\_new rebuild)</td><td>PASS — DDL confirmed, 4697 rows preserved</td></tr> <tr><td>Ingest probes — 4/4 probe accounts persist to DB</td><td>PASS (round 2 probes after schema fix; DB ids 9052/9056/9057/9059/9062/9063/9064)</td></tr> <tr><td>Regression — original 6 accounts</td><td>PASS — counts growing, timestamps advancing</td></tr> <tr><td>No-loop / alias dedup (UNIQUE on message\_id)</td><td>PASS — 0 duplicate message\_ids</td></tr> <tr><td>email-action-hard-check.js exit code</td><td>PASS — exit 0, 17 accounts in scope</td></tr> </tbody></table>

**Blocker found and fixed during round 1 validation:** The `emails` table had a hardcoded CHECK covering only the original 6 accounts. `INSERT OR IGNORE` silently dropped 27 real emails before the migration was applied. See Section 9 for the full gotcha description.

### Round 2 (19 accounts — LumisCare + daemon path — 2026-06-08T13:15Z)

<table id="bkmrk-checkresult-account_"> <thead><tr><th>Check</th><th>Result</th></tr></thead> <tbody> <tr><td>ACCOUNT\_MAP (himalaya-adapter.js) has 19 entries</td><td>PASS — L34–56 confirmed</td></tr> <tr><td>config.toml has 19 \[accounts.\*\] stanzas</td><td>PASS — grep count = 19</td></tr> <tr><td>email-agent.js counts map has 19 accounts</td><td>PASS — L2460–2468</td></tr> <tr><td>Zero "Unknown account" errors (wrapper run)</td><td>PASS — grep -c = 0 / 40 lines</td></tr> <tr><td>Zero "Unknown account" errors (legacy/production run)</td><td>PASS — grep -c = 0</td></tr> <tr><td>Zero silent drops / CHECK failures (production run)</td><td>PASS</td></tr> <tr><td>admin-lumiscare ingest proof</td><td>PASS — DB id=9070 under admin-lumiscare</td></tr> <tr><td>hello-lumiscare ingest proof (external sender)</td><td>PASS — DB id=9195 under hello-lumiscare (gmail-origin probe)</td></tr> <tr><td>sales-bilko-cloud ingest proof</td><td>PASS — DB id=9193</td></tr> <tr><td>sales-bilko-company ingest proof</td><td>PASS — DB id=9194</td></tr> <tr><td>hello@lumiscare.com forwarding removal (behavioural)</td><td>PASS — gmail-origin stored only under hello-lumiscare, not duplicated under alem</td></tr> <tr><td>All 19 last\_checked\_at fresh</td><td>PASS — 2026-06-08T13:09:39Z all accounts</td></tr> <tr><td>No duplicate message\_ids</td><td>PASS — 0 rows</td></tr> <tr><td>Regression (orig 6 + prior 11)</td><td>PASS — row counts growing, timestamps fresh</td></tr> </tbody></table>

Evidence files: `/tmp/evidence-103182/flowforge-build.md`, `/tmp/evidence-103182/proveo-validation.md`, `/tmp/evidence-103182/daemon-wrapper-run.log`, `/tmp/evidence-103182/daemon-legacy-run.log`