BPShift — UE Blueprint → C++ migration with parity verify that doesn't touch an LLM

I open-sourced a toolchain that migrates UE 5.2 Blueprints to C++. The deterministic parts (`UCLASS(…)`, `UPROPERTY` initializers, constructor body, dispatcher delegates) are emitted from the BP without an LLM. An LLM only writes function bodies. After it’s done, a separate verify step snapshots the original BP at runtime, replays the same scenario against the C++ class, and diffs them via UE’s own UPROPERTY reflection + Python set-diff. No LLM is in that comparator — so “the LLM finished” and “the migration matches the BP” are independent signals.

If anything diverges, the report tells you the exact property path, the expected value, and the actual value. The LLM cannot have silently dropped a field, because the comparator walks reflection from outside.

Real example. A 4-component Actor BP with 53 SCS overrides (mesh, materials, collision profile/responses, mass, damping, etc.):

- After LLM-only: `initialValueMismatches: 53`

  • After running the deterministic `emit-component-overrides` and pasting it into the constructor: `initialValueMismatches: 0` — every override byte-for-byte confirmed by reflection.

There’s also a caller-graph surgery cycle (`rewrite-callers` + `verify-callers`) that walks `K2Node_CallFunction` across caller BPs when a function gets renamed during migration, then force-unloads + recompiles and reads `FCompilerResultsLog::NumErrors` (because `compile_blueprint()` is a known false-positive signal — that one caught me twice).

Honest limits (full list in `LIMITATIONS.md`): UE 5.2 / Windows verified only; BP-defined `BI_*_C` interfaces can’t be native-overridden (engine constraint, recipe routes you to selective migration); verify covers static state + scenario returns, not Tick-order/async timing — PIE smoke is still your call.

Origin. Not designed top-down. Reverse-engineered against a single production project; every silent failure I tripped over became either a deterministic rule, a gate, or a `LIMITATIONS.md` row. Same evolution mode going forward — PRs welcome, the gaps are where the next round of value lives.

Repo (MIT): https://github.com/SeanAblur/BPShift