test_task_policy.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. from __future__ import annotations
  2. import pytest
  3. from script_build_host.domain.artifacts import DirectionConstraint
  4. from script_build_host.domain.task_capabilities import LegacyTaskCapabilityCatalog
  5. from script_build_host.domain.task_contracts import (
  6. PlannerCriterionInput,
  7. ScriptTaskKind,
  8. TaskContractError,
  9. )
  10. from script_build_host.domain.task_policy import TaskPolicyCatalog
  11. def test_task_policy_injects_protected_kind_and_direction_constraint_criteria() -> None:
  12. catalog = TaskPolicyCatalog()
  13. criteria = catalog.criteria(
  14. task_id="paragraph-task",
  15. task_kind=ScriptTaskKind.PARAGRAPH,
  16. business=(
  17. PlannerCriterionInput(
  18. client_key="business-quality",
  19. description="the opening is memorable",
  20. hard=False,
  21. ),
  22. ),
  23. direction_constraints=(
  24. DirectionConstraint(
  25. constraint_id="facts-traceable",
  26. statement="Every factual claim remains traceable",
  27. rationale="hard publication rule",
  28. ),
  29. ),
  30. )
  31. assert criteria[0].criterion_id == "paragraph-content-complete"
  32. assert criteria[0].hard is True
  33. assert criteria[1].criterion_id == "direction-constraint-facts-traceable"
  34. assert criteria[1].hard is True
  35. assert criteria[2].description == "the opening is memorable"
  36. assert criteria[2].hard is False
  37. def test_legacy_retrieval_criteria_remain_readable_and_host_rendered() -> None:
  38. criteria = TaskPolicyCatalog(LegacyTaskCapabilityCatalog()).criteria(
  39. task_id="external",
  40. task_kind=ScriptTaskKind.EXTERNAL_RETRIEVAL,
  41. business=(
  42. PlannerCriterionInput(
  43. client_key="coverage",
  44. criterion_type="concept_coverage",
  45. params={"concepts": ["占器械", "玩手机", "双重标准"], "minimum_matches": 2},
  46. ),
  47. ),
  48. )
  49. assert criteria[1].description == "Evidence covers at least 2 of: 占器械, 玩手机, 双重标准"
  50. def test_retrieval_rejects_free_text_synthesis_contract_before_dispatch() -> None:
  51. with pytest.raises(TaskContractError, match="TASK_CAPABILITY_MISMATCH"):
  52. TaskPolicyCatalog(LegacyTaskCapabilityCatalog()).criteria(
  53. task_id="external",
  54. task_kind=ScriptTaskKind.EXTERNAL_RETRIEVAL,
  55. business=(
  56. PlannerCriterionInput(
  57. client_key="persona-analysis",
  58. description="write a persona analysis and element mapping document",
  59. ),
  60. ),
  61. )