Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion faircode/mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,12 +391,26 @@ def _proxy_hints_impl(path, overrides=None, held_out_with=None, alpha=None,
kw.update(_exact_kwargs(exact_permutations, exact_max_rows))
kw["max_age"] = resolved["max_age"]
kw["age_reference_year"] = resolved["age_reference_year"]
output = {"hints": compute_proxy_hints(df, result["dimensions"], held_out=held_out, **kw)}
hints = compute_proxy_hints(df, result["dimensions"], held_out=held_out, **kw)
output = {"hints": hints}
sheet_notes = [n for n in (_sheet_note(path),) if n]
sheet_notes += [n for spec in (held_out_with or []) for n in (_sheet_note(partition_held_out_path(spec)[0]),) if n]
if sheet_notes:
output["sheet_notes"] = sheet_notes # deprecated alias of the sheet entries in `notes` (#950)
notes = sheet_notes + [n for n in (encoding_ignored_note(path, encoding),) if n] + held_notes
# Proxy hints compare *pairs* of dimensions, so fewer than two testable
# dimensions (detected dimensions plus any held-out columns) yields no pairs
# and an empty `hints` list. Say so, or an empty result reads as "tested,
# found nothing" rather than "nothing could be tested" (#1044).
if not hints:
testable = [d["name"] for d in result["dimensions"]] + list(held_out or {})
if len(testable) < 2:
shown = ", ".join(testable) if testable else "none"
notes = notes + [
f"no proxy pairs were tested: proxy hints compare pairs of "
f"dimensions and this dataset has {len(testable)} ({shown}); "
f"at least two are needed."
]
if notes:
output["notes"] = notes
_flag_deprecated_aliases(output)
Expand Down
35 changes: 35 additions & 0 deletions tests/test_mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,41 @@ def test_proxy_hints_with_no_significant_pairs_returns_an_empty_list_not_an_erro
assert "provenance" in result


def test_proxy_hints_notes_when_too_few_dimensions_to_test(tmp_path):
# Proxy hints compare pairs of dimensions, so a single-dimension dataset has
# no pair to test and returns an empty `hints` list. A note says why, so the
# empty result is not read as "tested, found nothing" (#1041 is the sibling
# fix for benchmark filters; this is #1044).
path = tmp_path / "one.csv"
path.write_text("sex\nM\nF\nM\nF\n", encoding="utf-8")

result = _proxy_hints_impl(str(path))

assert result["hints"] == []
assert any(
"no proxy pairs were tested" in note and "at least two are needed" in note
for note in result.get("notes", [])
), result.get("notes")

# A dataset with two associated dimensions is tested, so it carries no such note.
two = tmp_path / "two.csv"
two.write_text(
"sex,occupation\n"
+ "\n".join(
f"{'male' if i % 2 == 0 else 'female'},"
f"{'engineer' if i % 2 == 0 else 'nurse'}"
for i in range(100)
)
+ "\n",
encoding="utf-8",
)
tested = _proxy_hints_impl(str(two))
assert tested["hints"]
assert not any(
"no proxy pairs were tested" in note for note in tested.get("notes", [])
)


def test_proxy_hints_runtime_error_propagates_with_a_clean_message(tmp_path, monkeypatch):
import faircode.mcp_server as mcp_server

Expand Down
Loading