|
@@ -0,0 +1,124 @@
|
|
|
|
|
+"""Host-owned acceptance policy for script task kinds."""
|
|
|
|
|
+
|
|
|
|
|
+from __future__ import annotations
|
|
|
|
|
+
|
|
|
|
|
+from collections.abc import Sequence
|
|
|
|
|
+from hashlib import sha256
|
|
|
|
|
+from typing import Any
|
|
|
|
|
+
|
|
|
|
|
+from .task_contracts import (
|
|
|
|
|
+ PlannerCriterionInput,
|
|
|
|
|
+ ScriptCriterion,
|
|
|
|
|
+ ScriptTaskKind,
|
|
|
|
|
+ stable_semantic_id,
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+_FIXED: dict[ScriptTaskKind, tuple[ScriptCriterion, ...]] = {
|
|
|
|
|
+ ScriptTaskKind.DIRECTION: (
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "direction-coherent", "Direction goals and hard constraints are coherent", True
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptTaskKind.PATTERN_RETRIEVAL: (
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "evidence-usable", "Retrieval returns usable and attributable evidence", True
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptTaskKind.DECODE_RETRIEVAL: (
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "evidence-usable", "Retrieval returns usable and attributable evidence", True
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptTaskKind.EXTERNAL_RETRIEVAL: (
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "evidence-usable", "Retrieval returns usable and attributable evidence", True
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptTaskKind.KNOWLEDGE_RETRIEVAL: (
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "evidence-usable", "Retrieval returns usable and attributable evidence", True
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptTaskKind.STRUCTURE: (
|
|
|
|
|
+ ScriptCriterion("structure-complete", "Structure covers its declared content scope", True),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptTaskKind.PARAGRAPH: (
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "paragraph-content-complete", "Paragraph contains complete publishable prose", True
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptTaskKind.ELEMENT_SET: (
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "elements-linked", "Every Element is valid and linked to a Paragraph", True
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptTaskKind.COMPARE: (
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "comparison-grounded", "Recommendation is grounded in the frozen candidates", True
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptTaskKind.COMPOSE: (
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "script-content-complete",
|
|
|
|
|
+ "Composed script satisfies the complete content contract",
|
|
|
|
|
+ True,
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "direction-goals-satisfied", "All Direction goals have real creative coverage", True
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptTaskKind.CANDIDATE_PORTFOLIO: (
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "portfolio-closed", "Portfolio closes and adopts exactly one valid script", True
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ "direction-goals-satisfied", "All Direction goals have real creative coverage", True
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ScriptTaskKind.ROOT_DELIVERY: (),
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class TaskPolicyCatalog:
|
|
|
|
|
+ def criteria(
|
|
|
|
|
+ self,
|
|
|
|
|
+ *,
|
|
|
|
|
+ task_id: str,
|
|
|
|
|
+ task_kind: ScriptTaskKind,
|
|
|
|
|
+ business: tuple[PlannerCriterionInput, ...],
|
|
|
|
|
+ direction_constraints: Sequence[Any] = (),
|
|
|
|
|
+ ) -> tuple[ScriptCriterion, ...]:
|
|
|
|
|
+ fixed = _FIXED[task_kind]
|
|
|
|
|
+ fixed_ids = {item.criterion_id for item in fixed}
|
|
|
|
|
+ constraints = tuple(
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ f"direction-constraint-{item.constraint_id}",
|
|
|
|
|
+ f"Hard Direction constraint: {item.statement}",
|
|
|
|
|
+ True,
|
|
|
|
|
+ )
|
|
|
|
|
+ for item in direction_constraints
|
|
|
|
|
+ )
|
|
|
|
|
+ extra = tuple(
|
|
|
|
|
+ ScriptCriterion(
|
|
|
|
|
+ stable_semantic_id(task_id, "criterion", item.client_key),
|
|
|
|
|
+ item.description,
|
|
|
|
|
+ item.hard,
|
|
|
|
|
+ )
|
|
|
|
|
+ for item in business
|
|
|
|
|
+ )
|
|
|
|
|
+ protected_ids = fixed_ids | {item.criterion_id for item in constraints}
|
|
|
|
|
+ if protected_ids & {item.criterion_id for item in extra}:
|
|
|
|
|
+ raise ValueError("business criteria cannot override fixed criteria")
|
|
|
|
|
+ return (*fixed, *constraints, *extra)
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def manifest_digest(self) -> str:
|
|
|
|
|
+ encoded = "\n".join(
|
|
|
|
|
+ f"{kind.value}:{item.criterion_id}:{item.description}:{int(item.hard)}"
|
|
|
|
|
+ for kind in ScriptTaskKind
|
|
|
|
|
+ for item in _FIXED[kind]
|
|
|
|
|
+ )
|
|
|
|
|
+ return "sha256:" + sha256(encoded.encode()).hexdigest()
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+__all__ = ["TaskPolicyCatalog"]
|