Abstain on ambiguous bindings and bind receipts to the full request
Two options with the same text ("repair button behavior") both discharge a button-error obligation. The current implementation chooses whichever appears first; reversing the option order changes the choice. Its input hash covers only state, so changing the questions/options does not change the receipt identity. It also returns a 90% probability despite having no empirical receipts.
This patch abstains on ambiguous bindings (retaining sorted ambiguous option IDs), rejects duplicate option IDs, and hashes the full request. A unique evidence-gathering option may still be proposed while marked abstained. The probabilities field remains present but empty: structural binding and a smoothed empirical success rate are not a calibrated distribution over options. The latter is exposed separately as smoothed_success_rate when receipts exist, with the existing count/confidence basis.
Run python -B -m unittest test_decision_contract -v: all 3 tests fail on the base revision and pass with this change. The new tests contain the complete request reproducer and verify both option orders, changed-question hashes, and duplicate refusal. Prior scoped checks of this exact source repair retained the original routing results (16/16 dev, 30/32 held-out, 2/2 structured cases); the two pre-existing held-out misses remain. This does not claim a broader routing or specialist benchmark improvement.
Compatibility: callers that previously consumed fabricated probability values should use the choice/abstention and evidence fields. Source-only repair plus standard-library tests; no runtime adapter or data dependency.
Base revision: 08a9f1e70b8e78d9078b4bd9f308b99b9800bcb0.