Skip to content

fix: an ambiguous join is refused instead of guessed - #25

Merged
kiyeonjeon21 merged 1 commit into
mainfrom
fix/ambiguous-join-column
Jul 25, 2026
Merged

fix: an ambiguous join is refused instead of guessed#25
kiyeonjeon21 merged 1 commit into
mainfrom
fix/ambiguous-join-column

Conversation

@kiyeonjeon21

Copy link
Copy Markdown
Owner

Why

ensureJoin matched on the table pair rather than the column, so a table with two foreign keys into the same target - billing_region_id and shipping_region_id both into regions - silently joined on whichever edge sorted first.

That is the worst shape of bug this engine can have: the answer looks perfectly ordinary while answering a question the user never asked.

Reproduced on a fixture where both edges are inferred at 93%:

before:  OK -> ... JOIN "regions" ON "orders"."billing_region_id" = "regions"."id" ...
after:   REFUSED -> Cannot use "tier": orders joins regions through more than one key
         (orders.billing_region_id or orders.shipping_region_id), so this grouping is
         ambiguous. Write the SQL directly and pick the one you mean.

What

It refuses and names both candidate keys, so the agent can write the SQL it actually means. That matches how the compiler already handles fan-out and unknown metrics: refuse rather than guess.

Verification

  • npm run check exit 0; npm run test:cli 148 pass / 0 fail
  • npm run eval:engine 18/18 and eval:engine:hard 25/25, both unchanged
  • A regression test pins the fixture and asserts the refusal names both columns

Worth noting how this one was found: by reading the code path, not by measurement. Neither committed dataset can trigger it through query_metric, because a lookup table's label is never a groupable dimension - so the eval was structurally blind to it. A useful reminder that a scoreboard only covers what its cases can reach.

This closes the engine-defect list the hard dataset opened (ROADMAP step 6).

🤖 Generated with Claude Code

https://claude.ai/code/session_01CKZ9UVgw2Mhiu6T5YAG7k6

ensureJoin matched on the table pair rather than the column, so a table with two
foreign keys into the same target - billing region and shipping region - silently
joined on whichever edge sorted first. That is the worst shape of bug this engine
can have: the answer looks perfectly ordinary while answering a question the user
never asked.

It now refuses and names both candidate keys, so the agent can write the SQL it
actually means. That matches how the compiler already handles fan-out and unknown
metrics: refuse rather than guess.

Reproduced on a fixture where both edges are inferred at 93% and the compiler
picked billing without a word. Both engine suites are unchanged (18/18, 25/25) -
neither committed dataset can trigger it through query_metric, since a lookup
table's label is not a groupable dimension, which is also why the eval never
caught this one. Found by reading the code path while closing out the defect list,
not by measurement.

This closes the engine-defect list the hard dataset opened.
@kiyeonjeon21
kiyeonjeon21 merged commit 456179a into main Jul 25, 2026
1 check passed
@kiyeonjeon21
kiyeonjeon21 deleted the fix/ambiguous-join-column branch July 25, 2026 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant