What the CLOUD Act / zero-trust posture cost the people who actually use MapFlow, and the one exposure we accept because no alternative exists.
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.
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.
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 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:
The honest trade-off. Mandating "no external LLM" is a defensible residency decision — but it is not free. There are three paths, not two:
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
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.
Opportunity Cost
Specific features, iterations, and AI optimisations delayed or abandoned while waiting for manual proxy or firewall clearances.
Operational Friction
Hours spent writing workarounds or waiting for change-control boards for environments (Python and Node) that were already technically approved.
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.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.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.
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.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.Data Inefficiencies
The cost of building complex local PII-scrubbing scripts because the centralised proxy lacks real-time, flexible routing for UK data residency.
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.