2026-09-14 16:29:25 +08:00
|
|
|
"""Tests for EOT/INT DeepSeek suggestion validation without network calls."""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import unittest
|
2026-09-14 18:43:58 +08:00
|
|
|
from pathlib import Path
|
|
|
|
|
import json
|
|
|
|
|
import tempfile
|
2026-09-14 16:29:25 +08:00
|
|
|
|
2026-09-14 18:43:58 +08:00
|
|
|
from adjudicate_easycom_eot_int_candidates import (
|
|
|
|
|
_transport_rows, build_user_prompt, read_candidates, validate_decisions,
|
|
|
|
|
)
|
2026-09-14 16:29:25 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class EOTINTAdjudicationTests(unittest.TestCase):
|
|
|
|
|
def test_prompt_contains_task_and_context(self) -> None:
|
|
|
|
|
prompt = build_user_prompt(
|
2026-09-14 18:43:58 +08:00
|
|
|
[{"uid": "u1", "candidate_source": "WEARER_ONSET", "task": "eot_response",
|
|
|
|
|
"temporal_evidence": {"wearer_duration": 2.0},
|
|
|
|
|
"context": [{"transcription": "Yes."}]}],
|
2026-09-14 16:29:25 +08:00
|
|
|
0,
|
|
|
|
|
)
|
2026-09-14 18:43:58 +08:00
|
|
|
self.assertIn("WEARER_ONSET", prompt)
|
|
|
|
|
self.assertIn("wearer_duration", prompt)
|
2026-09-14 16:29:25 +08:00
|
|
|
self.assertIn("Yes.", prompt)
|
|
|
|
|
|
|
|
|
|
def test_decisions_require_exact_uid_and_vocabulary(self) -> None:
|
|
|
|
|
payload = {
|
|
|
|
|
"items": [
|
|
|
|
|
{
|
|
|
|
|
"uid": "u1",
|
2026-09-14 18:43:58 +08:00
|
|
|
"verdict": "HARD_NEGATIVE",
|
|
|
|
|
"event_type": None,
|
|
|
|
|
"subtype": "INT_OTHER_BACKCHANNEL",
|
|
|
|
|
"confidence": 0.91,
|
|
|
|
|
"reason": "Brief feedback while the wearer continues.",
|
|
|
|
|
"needs_human_review": False,
|
2026-09-14 16:29:25 +08:00
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
decisions = validate_decisions(payload, ["u1"])
|
2026-09-14 18:43:58 +08:00
|
|
|
self.assertEqual(decisions[0]["subtype"], "INT_OTHER_BACKCHANNEL")
|
2026-09-14 16:29:25 +08:00
|
|
|
with self.assertRaisesRegex(ValueError, "mismatch"):
|
|
|
|
|
validate_decisions({"items": []}, ["u1"])
|
|
|
|
|
|
2026-09-14 18:43:58 +08:00
|
|
|
def test_markdown_escaped_uid_is_normalized_but_still_unique(self) -> None:
|
|
|
|
|
item = {
|
|
|
|
|
"uid": "Session\\_4/wearer\\_onset/00000024",
|
|
|
|
|
"verdict": "POSITIVE",
|
|
|
|
|
"event_type": "EOT_RESPONSE",
|
|
|
|
|
"subtype": None,
|
|
|
|
|
"confidence": 0.9,
|
|
|
|
|
"reason": "Sustained wearer response after the other speaker stops.",
|
|
|
|
|
"needs_human_review": False,
|
|
|
|
|
}
|
|
|
|
|
expected = "Session_4/wearer_onset/00000024"
|
|
|
|
|
decision = validate_decisions({"items": [item]}, [expected])[0]
|
|
|
|
|
self.assertEqual(decision["uid"], expected)
|
|
|
|
|
with self.assertRaisesRegex(ValueError, "duplicate"):
|
|
|
|
|
validate_decisions({"items": [item, {**item, "uid": expected}]}, [expected])
|
|
|
|
|
|
|
|
|
|
def test_duplicate_rule_uids_are_disambiguated_with_provenance(self) -> None:
|
|
|
|
|
with tempfile.TemporaryDirectory() as temporary:
|
|
|
|
|
path = Path(temporary) / "candidates.jsonl"
|
|
|
|
|
base = {"uid": "Session_4/other_to_other/00003600", "task": "eot_response"}
|
|
|
|
|
rows = [
|
|
|
|
|
{**base, "previous_other_participant_ids": [6], "incoming_other_participant_ids": [4]},
|
|
|
|
|
{**base, "previous_other_participant_ids": [3], "incoming_other_participant_ids": [6]},
|
|
|
|
|
]
|
|
|
|
|
path.write_text("".join(json.dumps(row) + "\n" for row in rows), encoding="utf-8")
|
|
|
|
|
loaded = read_candidates(path)
|
|
|
|
|
self.assertEqual(len({row["uid"] for row in loaded}), 2)
|
|
|
|
|
self.assertTrue(all(row["uid_disambiguated_from"] == base["uid"] for row in loaded))
|
|
|
|
|
|
|
|
|
|
def test_transport_ids_are_short_unique_and_reversible(self) -> None:
|
|
|
|
|
rows = [{"uid": "Session_4/other_to_other/00003600/a"},
|
|
|
|
|
{"uid": "Session_4/other_to_other/00003600/b"}]
|
|
|
|
|
transported, mapping = _transport_rows(rows)
|
|
|
|
|
self.assertEqual([row["uid"] for row in transported], ["item-0000", "item-0001"])
|
|
|
|
|
self.assertEqual(mapping["item-0001"], rows[1]["uid"])
|
|
|
|
|
|
2026-09-14 16:29:25 +08:00
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
unittest.main()
|