chore(simulator): unify graph generation with epsilon node expansion
What does this MR do and why?
Problem
Self-referential edges (Group contains Group) create cycles in the dependency graph. Topological sort rejects cycles. So there were two entirely separate code paths: generate_subgroup_hierarchy() for the recursive group hierarchy, and generate_child_entities() for everything else. Same logic, duplicated, with subtle differences. The subgroup hierarchy also had its own config section, its own constant, and its own streaming variant.
Solution
Break the cycle by expanding self-referential edges into depth-level epsilon nodes — synthetic intermediaries that don't represent real entity types, analogous to epsilon transitions in NFAs (first time I've used this concept from my CS education in a real codepath).
If you'd like a visual reference for how this all works, see: $5967477.
Related Issues
Testing
All existing tests pass. Modified/added a few to cover DAG structure w/ epsilons, recursive hierarchy edges, rejecting recursive edge cases, compaction, etc.
Performance Analysis
- This merge request does not introduce any performance regression. If a performance regression is expected, explain why.