End-User Impact — The Honest Trade-Off Register

What the CLOUD Act / zero-trust posture cost the people who actually use MapFlow, and the one exposure we accept because no alternative exists.

Architectural trade-offs
Accepted CLOUD Act exposure
Local-first everywhere else
The elegant solution we started with
What MapFlow was meant to be before the residency work.

MapFlow was designed as a clean pipeline: read the source database, map the fields, load the result into Salesforce. One tool, one flow, one cloud platform doing the work. The operator pointed at a source, drew the mapping lines, and pressed go. That was the whole product.

What the CLOUD Act posture dirtied
Every control below exists because the hosting platform (Base44) is US-parent-owned and therefore within CLOUD Act reach.

The key is no longer in the app — it's in your Windows Vault.

The AES-256 PII key lives in the operator's Windows Credential Vault (DPAPI), not in the cloud. To decrypt, a Local Proxy must be running on the operator's own machine with the key loaded. The app can no longer "just" decrypt; it has to ask the proxy, and the proxy has to be up.

There is a second piece of software to install and keep running — and how many depends on the engines.

The Local Proxy is a Python process bound to localhost. If it isn't running, or the key isn't loaded, decryption and encrypted uploads fail. The operator now babysits a local process that didn't exist in the elegant version.

How many proxies you need:

One engine = one proxy. A single proxy is connection-parameterised — every request carries its own server/database/credentials, so it serves all connections of that engine. Source SQL Server + replacement SQL Server warehouse = one sql-server-proxy.py covering both reads and writes.

Mixed engines = one per engine. Source SQL Server + replacement PostgreSQL warehouse = two: sql-server-proxy.py (source reads) and postgres-proxy.py (warehouse writes + DPAPI key + encrypt/decrypt routes).

They both default to port 3001, so you cannot start a second one out of the box. Set MAPFLOW_PROXY_PORT before launching the second one — e.g. sql-server-proxy.py on 3001 (default) and MAPFLOW_PROXY_PORT=3002 postgres-proxy.py on 3002. The Postgres proxy also has a separate Power BI REST API listener on port 5000 (set via --rest-port) — that is not the main proxy port. Point each MapFlow DBConnection at the right localhost:port.

Splitting the same engine onto two ports (isolation only) is optional and not required.

AI features are off by default — and some never come back.

The master llm_enabled kill switch ships OFF. PII classification, field profiling, and file-table scoring run deterministic non-AI engines instead. The Slack/Teams bots and screenshot field detection return a clean "AI disabled" state. Follow-Me field mapping does not — its non-AI reverse-engineering engine stays available, so the operator can still derive source↔destination mappings by feeding the engine matched record pairs; only the cloud-LLM suggestion path is off. An admin can re-enable the LLM path, but it's gated, allowlisted to UK-hosted models, and independently admin-gated per feature.

The overnight refresh is now a scheduled task on the operator's PC.

The overnight Salesforce→Postgres refresh runs as a Windows Task Scheduler job on the operator's own machine, not in the cloud — so the key never leaves the estate. That means the operator's PC must be on, logged in, and reachable to the source at 01:00. The "it runs in the cloud while you sleep" story is gone.

Likely throughput hit. The destination decides how much is lost:
  • Salesforce loads: ~10–25% slower — the Salesforce REST API limit and 200-row composite batch are still the ceiling, so the per-row AES-256-GCM encrypt + localhost proxy hop sits on top of the dominant SF round-trip latency, not in place of it.
  • Source → local warehouse bulk writes (encrypting millions of rows): ~30–60% slower vs. a scale-out cloud backend, because the operator's desktop CPU + proxy concurrency semaphores replace elastic cloud capacity as the throughput floor. A higher-spec operator box or a second proxy process on a second machine narrows this toward the lower bound.
These are planning ranges, not guarantees — real figures depend on the operator's CPU, the proxy's MAX_CONCURRENT, row width, and the client DB's own throughput.

The warehouse is now a client-provisioned local database, not Postgres.

With storage_mode = local_only (the default), the cloud Postgres warehouse is disabled by policy. Citizen data lives in a client-provisioned Oracle / PostgreSQL / SQL Server database reached only through the Local Proxy. The "it's already in Postgres, just query it" convenience is gone — every read is proxy-routed (see the topology note above — the engine of the replacement warehouse decides whether the operator runs one proxy or two).

The Query Console — MapFlow's governed read path — follows the same rule: it runs against the local estate, not the cloud. Whichever local engine the warehouse is (Postgres, Oracle, or SQL Server), the Console connects to it only through the Local Proxy, never to a cloud Postgres. An admin picks the local DBConnection, writes the SQL, and the Console proxies the query to that engine — reads stay inside the estate until the operator exports them.

The hardware cost of "no external LLMs"
If InfoSec mandates no external / cloud LLM and the operator wants GPT-4-class reasoning locally, that decision has a concrete price tag. This is the real-world impact of the AI-residency mandate, stated plainly.

The only single-device path to cloud-LLM parity

A MacBook Pro with an M-Max chip and maximum unified memory (~£5k) is the only laptop configuration that can host a frontier-scale model (Llama 3 70B, Qwen 2.5 72B, DeepSeek-R1) entirely in RAM and actually use its GPU. Apple Silicon's unified memory lets the GPU and CPU share one large pool (128–192 GB), so the whole model sits in memory; Ollama's Metal GPU backend is already active on Apple Silicon, so inference runs on the GPU the moment you start. No other laptop architecture does both at this capacity.

Why the cheaper alternatives fall short of cloud parity:

  • Windows Copilot+ laptops (Snapdragon X Elite, 32 GB): CPU inference works today and is fast, but the 45 TOPS Hexagon NPU sits idle — Ollama does not yet route through Qualcomm's QNN backend. RAM is also split between system and a discrete GPU's limited VRAM, so it cannot hold a 70B+ model. Cloud-parity reasoning is not reachable on this class of machine today.
  • ChromeOS Googlebooks (same Snapdragon X Elite): the NPU is locked off by ChromeOS — reserved for system features, not exposed to the Crostini Linux container where Ollama would run. Inference is CPU-only via Crostini, and the AES key falls back to a Linux keyring with no hardware root-of-trust (no DPAPI/TPM, no Secure Enclave). Functionally works, but strictly weaker on both compute and key binding.
  • Lower-spec Macs (M-series base/Pro, 16–32 GB): excellent for 8B-class models (Llama 3 8B, Phi-3, Qwen 2.5 7B), but the memory ceiling means they cannot hold the 70B+ models that reach cloud-LLM reasoning quality.

The honest trade-off. Mandating "no external LLM" is a defensible residency decision — but it is not free. There are three paths, not two:

  • (a) ~£5k per operator for a maxed-memory M-Max MacBook Pro to retain cloud-comparable reasoning locally (the single-device path above).
  • (b) Civo "real AI" / Project Mercury — a UK-sovereign hosted LLM (Civo LON1 GPU cloud, non-US-parent) that gives cloud-LLM parity without the per-operator hardware spend. This path is provisioned by the client — MapFlow does not supply the Civo account, the GPU instance, or the Project Mercury infrastructure. The client stands up the sovereign inference host; MapFlow's proxy only shuttles encrypted prompts to the client's endpoint and receives the textual answer back.
  • (c) Deterministic non-AI engines that ship under the default kill switch — which is exactly what the posture delivers today.
The cost of the mandate is the hardware (a), a client-provisioned sovereign cloud account (b), or the absence of LLM reasoning (c). See the Local LLM Setup guide for the per-platform install path, the Sovereign AI Setup Guide for the Civo/Project Mercury provisioning path, and the AI Degradation Guide for the deterministic fallback.

The accepted final step — loading into Salesforce
This is the one CLOUD Act exposure MapFlow does not, and cannot, eliminate.

Everything above keeps citizen data sovereign up to the last step. The final step — loading the mapped data into Salesforce — is the deliberate, accepted exception.

Why it's accepted

There is no alternative. Salesforce and Arcus do not offer a non-US, non-cloud destination for this data. Arcus is a Salesforce-native product; Salesforce is a US-headquartered cloud company. The client has contracted to run their Arcus deployment on Salesforce. Loading the mapped citizen data into Salesforce is the entire point of the migration — it is the outcome the client bought.

What "in Salesforce" actually means

  • The data is in the cloud — Salesforce is a SaaS platform, not an on-premise system.
  • The underlying database is Oracle — Salesforce's core metadata repository runs on Oracle Database, hosted in Salesforce's cloud. Oracle Corporation is itself a US-headquartered provider, so it is a second US custodian in the storage chain (the order would be served on Salesforce as the direct ECSP, but the data physically rests on Oracle's database technology inside Salesforce's estate).
  • The cloud custodian is Salesforce, Inc. — a US-headquartered "electronic communication service provider" that physically hosts the data in its own cloud.
  • The application vendor is Arcus Global — a UK-headquartered company whose Arcus product runs as a Salesforce-native app on top of Salesforce's platform. Arcus is not itself a US custodian; it holds the data only insofar as the data lives inside Salesforce.
  • The data is subject to the CLOUD Act — because Salesforce is the US electronic communication service provider that physically stores it, a US lawful production order can compel Salesforce to disclose that data regardless of where in the world it is stored. Arcus's UK nationality does not change this: the order reaches the data through the US custodian (Salesforce), not through Arcus.

This is not a gap in MapFlow's posture — it is the contractual boundary of the engagement. MapFlow's job is to keep citizen data sovereign until the client's contracted destination, and to make that final hand-off a conscious, documented decision rather than an accidental leak. Everything before Salesforce is local-first; everything in Salesforce is the client's accepted CLOUD Act surface, recorded here honestly.

Risk & Loss Register — what the posture cost, by category
A bulletproof, client-facing register of the delay, friction, waste, and inefficiency caused by corporate policy bottlenecks — grouped so nothing can be dismissed as "just the way it is".

Opportunity Cost

Specific features, iterations, and AI optimisations delayed or abandoned while waiting for manual proxy or firewall clearances.

  • The LLM-based Follow-Me field-mapping suggestions and Deep PII Scan sat behind a manual kill-switch enablement + per-feature admin gate; the deterministic reverse-engineering engine shipped in their place, but the higher-accuracy AI path was never delivered on the default tenant.
  • The Slack / Teams conversational bots return a canned "AI disabled" reply on the local-first posture — the natural-language Q&A over the warehouse that clients asked for was deferred indefinitely.
  • Screenshot field-detection (vision model) never went live under the default posture; field mapping from screen grabs falls back to manual capture.
  • Real-time schema re-describe and overnight optimisation runs were reshaped into scheduled local tasks, so "iterate on today's data" became "iterate on yesterday's snapshot".

Operational Friction

Hours spent writing workarounds or waiting for change-control boards for environments (Python and Node) that were already technically approved.

  • Each engine got its own Local Proxy (sql-server-proxy.py, postgres-proxy.py, oracle-proxy.py, ms-access-proxy.py) — four codebases to install, keep running, and bind to separate MAPFLOW_PROXY_PORT values so more than one can run at once.
  • A Windows Task Scheduler job (overnight_sf_to_supabase_runner.py) had to be authored, registered, and babysat because the cloud overnight path was disallowed by policy — even though the same logic ran fine server-side in every other engagement.
  • Change-control boards reviewed the Python and Node runtimes even though both were already on the approved toolchain, adding days of sign-off latency to every proxy revision.

Financial Waste

Billable hours spent refactoring ephemeral "now you see it, now you don't" code loops just to satisfy a static, snapshot-in-time compliance checklist.

  • The Postgres OAuth connector was wired up, reviewed, and then torn back out because secrets:read could mint a service_role backdoor — a full build cycle discarded for a posture that was decided before the first line was written.
  • Backend-driven Salesforce loaders were built, then re-architected to a local "No decrypt" ciphertext-passthrough model once the rule that PII must not transit the US-parent backend was applied consistently — the same loader, written twice.
  • LLM classification, profiling, and field-mapping calls were written against InvokeLLM, then duplicated as deterministic non-AI engines when the kill switch became the default — two implementations of every analytical feature, one of which never runs in production.
  • Geo-IP lookups were re-implemented three times (ip-api, native hosting flag, ipwho.is) chasing a runtime-network restriction the posture created, not a product requirement.

Data Inefficiencies

The cost of building complex local PII-scrubbing scripts because the centralised proxy lacks real-time, flexible routing for UK data residency.

  • Per-row AES-256-GCM encrypt/decrypt, HMAC-SHA256 blind-index generation, and ciphertext-overflow detection all live in the Local Proxy instead of a single centralised routing layer — so every new source shape needs a new mapping of which columns to encrypt, which to index, and which to pass through as ciphertext.
  • Document-audit rows are application-level encrypted at insert with their own key attribution and blind-index pepper — a whole client-side crypto subsystem that a centralised residency router would have made unnecessary.
  • Operators hand-curate which fields are PII per table per project; with no real-time routing, that curation is the only thing standing between a plaintext column and a CLOUD Act order.
Protecting yourself while arming the client
The local setup is fully functional and legally compliant with UK data law; corporate policy bottlenecks are the sole reason for any delivery delay. These three practices keep that position defensible under audit.

Document intentional compliance.

Delivery notes explicitly state that local Node and Python runtimes were chosen specifically to adhere to UK data-residency law by processing data locally — not as a workaround, but as the compliant default. Every local-only decision is recorded against the residency control it satisfies.

Keep an immutable audit trail.

Deployment and execution history is logged locally so that if an InfoSec audit ever questions the short-lived "ghost" non-conformances (a proxy that ran for a migration window and was removed), the trail instantly proves no data left the estate and no record was altered. The InfoSec posture log and governance audit ledger are append-only and tamper-evident (SHA-256 integrity hashes).

Pivot the responsibility.

The local-first stack is fully functional and compliant with UK data law. Any delivery delay caused by waiting on manual proxy/firewall clearance or change-control boards is a corporate-policy bottleneck, not a technical or legal one — and is recorded as such in this register so the client can see the cause clearly.

Net end-user impact: the operator installs a local proxy, keeps their PC on overnight, accepts that AI is off, and queries the local estate (Postgres, Oracle, or SQL Server) through the proxy instead of a cloud Postgres warehouse. In return, a US CLOUD Act order against the hosting platform returns ciphertext and non-PII metadata — readable citizen data never leaves the UK operator's machine until the client's contracted hand-off into Salesforce, which is the accepted, documented, unavoidable final exposure.