Found during ACE-083 review (#199), measured identical on main @ 439ecd1, so this predates that change and is not a regression.
WITH order_items AS (SELECT order_id, SUM(quantity) q FROM order_items GROUP BY order_id)
SELECT SUM(orders.total_amount) FROM orders JOIN order_items ON order_items.order_id = orders.id
Reports multiplied naming orders (1) <- order_items (N). The truth is not_multiplied: the CTE is grouped to order_id, so it joins 1:1 and nothing fans.
Cause. ACE-083's _resolve_cte_scope derives a one_to_one edge for the grain-changing CTE and appends it to a copy of the relationship list, but the model's own order_items -> orders many_to_one edge is still in that list and wins. The two edges are about different entities that happen to share a name.
Direction is safe (an over-report, never a false clean), which is why ACE-083 left it. But it is one name collision away from the defect class ACE-083's S3 exists to close, and shadowing a table name in a CTE is ordinary SQL.
Why it was not fixed there. Deciding which edge outranks the other is a cardinality-resolution question, not a scope-resolution one, and ACE-083 was already five slices and two review rounds deep.
Repro is _sales_org in tests/test_semantic_model_runtime.py plus the statement above through pre_flight_check.
Found during ACE-083 review (#199), measured identical on
main@439ecd1, so this predates that change and is not a regression.Reports
multipliednamingorders (1) <- order_items (N). The truth isnot_multiplied: the CTE is grouped toorder_id, so it joins 1:1 and nothing fans.Cause. ACE-083's
_resolve_cte_scopederives aone_to_oneedge for the grain-changing CTE and appends it to a copy of the relationship list, but the model's ownorder_items -> orders many_to_oneedge is still in that list and wins. The two edges are about different entities that happen to share a name.Direction is safe (an over-report, never a false clean), which is why ACE-083 left it. But it is one name collision away from the defect class ACE-083's S3 exists to close, and shadowing a table name in a CTE is ordinary SQL.
Why it was not fixed there. Deciding which edge outranks the other is a cardinality-resolution question, not a scope-resolution one, and ACE-083 was already five slices and two review rounds deep.
Repro is
_sales_orgintests/test_semantic_model_runtime.pyplus the statement above throughpre_flight_check.