|
|
@@ -23,7 +23,9 @@ from agent.orchestration.validation_policy import (
|
|
|
ValidationContext,
|
|
|
)
|
|
|
|
|
|
-from script_build_host.domain.artifacts import ArtifactKind
|
|
|
+from script_build_host.domain.artifacts import ArtifactKind, BusinessArtifact
|
|
|
+from script_build_host.domain.candidate_validation import placeholder_paths
|
|
|
+from script_build_host.domain.defects import ScriptDefectV1, validate_defect_set
|
|
|
from script_build_host.domain.ports import (
|
|
|
MissionBindingRepository,
|
|
|
ScriptBusinessArtifactRepository,
|
|
|
@@ -38,6 +40,25 @@ RETRIEVAL_KINDS = frozenset(
|
|
|
"knowledge-retrieval",
|
|
|
}
|
|
|
)
|
|
|
+PHASE_TWO_KINDS = frozenset(
|
|
|
+ {
|
|
|
+ "structure",
|
|
|
+ "paragraph",
|
|
|
+ "element-set",
|
|
|
+ "compare",
|
|
|
+ "compose",
|
|
|
+ "candidate-portfolio",
|
|
|
+ }
|
|
|
+)
|
|
|
+_ARTIFACT_KIND_BY_TASK_KIND = {
|
|
|
+ "direction": ArtifactKind.DIRECTION,
|
|
|
+ "structure": ArtifactKind.STRUCTURE,
|
|
|
+ "paragraph": ArtifactKind.PARAGRAPH,
|
|
|
+ "element-set": ArtifactKind.ELEMENT_SET,
|
|
|
+ "compare": ArtifactKind.COMPARISON,
|
|
|
+ "compose": ArtifactKind.STRUCTURED_SCRIPT,
|
|
|
+ "candidate-portfolio": ArtifactKind.CANDIDATE_PORTFOLIO,
|
|
|
+}
|
|
|
_DIGEST = re.compile(r"^sha256:[0-9a-f]{64}$")
|
|
|
|
|
|
|
|
|
@@ -59,10 +80,10 @@ class ScriptBuildValidationPolicy:
|
|
|
kind = task_kind(context.task.current_spec.context_refs)
|
|
|
if kind in RETRIEVAL_KINDS:
|
|
|
preset = "script_retrieval_validator"
|
|
|
- elif kind == "direction":
|
|
|
+ elif kind == "direction" or kind in PHASE_TWO_KINDS:
|
|
|
preset = "script_candidate_validator"
|
|
|
else:
|
|
|
- raise ValueError(f"Unsupported phase-one task kind: {kind!r}")
|
|
|
+ raise ValueError(f"Unsupported script-build task kind: {kind!r}")
|
|
|
return ValidationPlan(
|
|
|
mode=ValidationMode.AGENT,
|
|
|
validator_preset=preset,
|
|
|
@@ -106,19 +127,24 @@ def precheck_snapshot(context: ValidationContext) -> list[DeterministicRuleResul
|
|
|
and context.snapshot.evidence_refs[0].kind == ArtifactKind.EVIDENCE.value
|
|
|
)
|
|
|
expected = "one evidence reference"
|
|
|
- elif kind == "direction":
|
|
|
+ elif kind in _ARTIFACT_KIND_BY_TASK_KIND:
|
|
|
+ expected_kind = _ARTIFACT_KIND_BY_TASK_KIND[kind]
|
|
|
shape_ok = (
|
|
|
len(context.snapshot.artifact_refs) == 1
|
|
|
and not context.snapshot.evidence_refs
|
|
|
- and context.snapshot.artifact_refs[0].kind == ArtifactKind.DIRECTION.value
|
|
|
+ and context.snapshot.artifact_refs[0].kind == expected_kind.value
|
|
|
)
|
|
|
- expected = "one direction artifact reference"
|
|
|
+ expected = f"one {expected_kind.value} artifact reference"
|
|
|
else:
|
|
|
shape_ok = False
|
|
|
expected = "a supported phase-one task kind"
|
|
|
results.append(
|
|
|
DeterministicRuleResult(
|
|
|
- rule_id="phase-one-artifact-shape",
|
|
|
+ rule_id=(
|
|
|
+ "phase-two-artifact-shape"
|
|
|
+ if kind in PHASE_TWO_KINDS
|
|
|
+ else "phase-one-artifact-shape"
|
|
|
+ ),
|
|
|
verdict=ValidationVerdict.PASSED if shape_ok else ValidationVerdict.FAILED,
|
|
|
reason=(
|
|
|
f"Attempt contains {expected}" if shape_ok else f"Attempt must contain {expected}"
|
|
|
@@ -128,6 +154,44 @@ def precheck_snapshot(context: ValidationContext) -> list[DeterministicRuleResul
|
|
|
return results
|
|
|
|
|
|
|
|
|
+def validation_layer(kind: str) -> str:
|
|
|
+ """Return the semantic layer without granting the Validator decision rights."""
|
|
|
+
|
|
|
+ if kind == "compare":
|
|
|
+ return "compare"
|
|
|
+ if kind == "compose":
|
|
|
+ return "global"
|
|
|
+ if kind == "candidate-portfolio":
|
|
|
+ return "governance"
|
|
|
+ if kind in PHASE_TWO_KINDS:
|
|
|
+ return "local"
|
|
|
+ if kind in RETRIEVAL_KINDS or kind == "direction":
|
|
|
+ return "phase-one"
|
|
|
+ raise ValueError(f"unsupported script-build task kind: {kind!r}")
|
|
|
+
|
|
|
+
|
|
|
+def precheck_business_artifact(artifact: BusinessArtifact) -> tuple[str, ...]:
|
|
|
+ """Detect unrealized candidate prose after domain schema checks have succeeded."""
|
|
|
+ return placeholder_paths(artifact)
|
|
|
+
|
|
|
+
|
|
|
+def validate_phase_two_defects(
|
|
|
+ values: Sequence[Mapping[str, Any]],
|
|
|
+ *,
|
|
|
+ criterion_ids: set[str],
|
|
|
+ allowed_evidence_refs: set[str],
|
|
|
+ passed: bool,
|
|
|
+) -> tuple[ScriptDefectV1, ...]:
|
|
|
+ defects = tuple(ScriptDefectV1.from_payload(item) for item in values)
|
|
|
+ validate_defect_set(
|
|
|
+ defects,
|
|
|
+ criterion_ids=criterion_ids,
|
|
|
+ allowed_evidence_refs=allowed_evidence_refs,
|
|
|
+ passed=passed,
|
|
|
+ )
|
|
|
+ return defects
|
|
|
+
|
|
|
+
|
|
|
class ScriptBuildDeterministicValidator:
|
|
|
"""Optional deterministic validator for explicitly selected rule plans."""
|
|
|
|
|
|
@@ -248,12 +312,16 @@ class ScriptBuildEvidenceProvider:
|
|
|
|
|
|
|
|
|
__all__ = [
|
|
|
+ "PHASE_TWO_KINDS",
|
|
|
"RETRIEVAL_KINDS",
|
|
|
"TASK_KIND_PREFIX",
|
|
|
"ScriptBuildArtifactEvidenceReader",
|
|
|
"ScriptBuildDeterministicValidator",
|
|
|
"ScriptBuildEvidenceProvider",
|
|
|
"ScriptBuildValidationPolicy",
|
|
|
+ "precheck_business_artifact",
|
|
|
"precheck_snapshot",
|
|
|
"task_kind",
|
|
|
+ "validate_phase_two_defects",
|
|
|
+ "validation_layer",
|
|
|
]
|