Dropping that config was the right call, and the lever you actually want is execution mode rather than a setting.
1. Flow concurrency. The properties reference is the list of supported pipeline settings, and there is no concurrency cap on it, which is why the configs circulating in those threads never checked out. What the docs do describe is a behavioral difference between the two execution modes: "In a triggered pipeline, the driver might process a subset of streams in parallel at a time, to avoid memory and CPU constraints." A continuous update does not work that way. Since your pain is a one-time hydration, that difference is the supported version of what you were reaching for. Run the initial load as a triggered update to get the staged behavior, then switch to continuous for steady state. Past that, the documented way to control driver load is deciding how many flows sit in one pipeline.
2. Driver sizing. The docs give thresholds rather than a formula. Past roughly 30 to 40 streaming tables in one pipeline the driver becomes a CPU bottleneck, and driver memory problems start showing up around 30 or more parallel flows, with the docs explicitly declining to name a limit because it depends on flow complexity. At 200+ you were well past both. Setting a driver type independently of the worker type is documented, with "choosing a larger driver type to avoid out-of-memory issues" called out as a reason to do it, so your fix is the sanctioned one.
3. Staged backfill vs one big update. Once flows let you hydrate in stages, but pick the right flavour. If those historic load flows target the same streaming tables as your CDC merge flows, append_flow(once=True) and INSERT ONCE INTO will not attach, because a streaming table that is the target of an AUTO CDC flow can only be targeted by other AUTO CDC flows. The one that fits is create_auto_cdc_flow(..., once=True) in Python, or AUTO CDC ONCE INTO in SQL. The CDC docs describe your exact pattern: "For initial hydration from a source with a change feed, use AUTO CDC with a once flow and then continue processing the change feed."
Your ordering was right, though. Size the driver first and hold splitting for when you outgrow it, which at 200+ flows I would expect eventually, since staging the hydration gets you through the first load but leaves the same 200+ flows on one driver every update afterwards. Tables move between pipelines without a full refresh, with requirements on the move-table page worth reading first. One trap if you go that way: once flows are not preserved across a move, and the docs say they "might run again in the destination pipeline." Comment them out of the destination before you run it, or you re-hydrate all 800M rows.
4. Alerting on gc_pressure. Useful as a diagnostic, but I would not anchor alerting to it. The event log schema reference publishes a maturity_level for what it documents and recommends building monitoring only on fields marked stable, so the durable place to point an alert is flow_progress and update_progress. Those also give you a better signal for this specific incident: an update sitting in RUNNING for five hours with nothing committing shows up as stalled batch progress no matter what caused it, so that alert would have caught this and will catch the next stall too, whether or not GC is involved. Publish the event log to a Unity Catalog table and put a scheduled alert on it, or use an event hook if you want it in-process.
On the dev-versus-prod question, since dev ran the same 200+ flow graph on the default driver without trouble, whatever tipped prod over scaled with data rather than with flow count. Worth comparing the per-flow initial snapshot size and the source table file counts between the two before you conclude the flow count alone was the cause.