|
@@ -12,9 +12,10 @@ from script_build_host.domain.artifacts import (
|
|
|
ArtifactKind,
|
|
ArtifactKind,
|
|
|
ArtifactState,
|
|
ArtifactState,
|
|
|
ArtifactVersion,
|
|
ArtifactVersion,
|
|
|
- ScriptDirectionArtifactV1,
|
|
|
|
|
|
|
+ DirectionArtifact,
|
|
|
)
|
|
)
|
|
|
from script_build_host.domain.errors import ProtocolViolation
|
|
from script_build_host.domain.errors import ProtocolViolation
|
|
|
|
|
+from script_build_host.domain.goal_coverage import GoalPolicyError, validate_goal_coverage
|
|
|
from script_build_host.domain.phase_three_artifacts import (
|
|
from script_build_host.domain.phase_three_artifacts import (
|
|
|
RootDeliveryManifestV1,
|
|
RootDeliveryManifestV1,
|
|
|
canonicalize_legacy_projection,
|
|
canonicalize_legacy_projection,
|
|
@@ -166,10 +167,27 @@ class RootDeliveryService:
|
|
|
and root_manifest.input_closure_digest == _closure_digest(closure)
|
|
and root_manifest.input_closure_digest == _closure_digest(closure)
|
|
|
)
|
|
)
|
|
|
projection_passed = False
|
|
projection_passed = False
|
|
|
|
|
+ direction = _direction(closure.direction)
|
|
|
|
|
+ portfolio = _portfolio(closure.portfolio)
|
|
|
|
|
+ structured = _structured(closure.structured)
|
|
|
|
|
+ goal_coverage_error: str | None = None
|
|
|
|
|
+ try:
|
|
|
|
|
+ validate_goal_coverage(
|
|
|
|
|
+ direction_goal_ids=tuple(item.goal_id for item in direction.goals),
|
|
|
|
|
+ coverage=structured.goal_coverage,
|
|
|
|
|
+ adopted_source_refs=structured.source_artifact_refs,
|
|
|
|
|
+ )
|
|
|
|
|
+ except GoalPolicyError as exc:
|
|
|
|
|
+ goal_coverage_error = f"{exc.code}: {exc.summary}"
|
|
|
|
|
+ goal_coverage_passed = goal_coverage_error is None
|
|
|
|
|
+ direction_contract_passed = (
|
|
|
|
|
+ structured.direction_ref == _uri(closure.direction)
|
|
|
|
|
+ and portfolio.adopted_structured_script_ref == _uri(closure.structured)
|
|
|
|
|
+ )
|
|
|
if root_manifest is not None:
|
|
if root_manifest is not None:
|
|
|
canonical = canonicalize_legacy_projection(
|
|
canonical = canonicalize_legacy_projection(
|
|
|
- _structured(closure.structured),
|
|
|
|
|
- direction=_direction(closure.direction).legacy_markdown,
|
|
|
|
|
|
|
+ structured,
|
|
|
|
|
+ direction=direction.legacy_markdown,
|
|
|
summary=root_manifest.build_summary,
|
|
summary=root_manifest.build_summary,
|
|
|
)
|
|
)
|
|
|
projection_passed = canonical.canonical_sha256 == root_manifest.legacy_projection_digest
|
|
projection_passed = canonical.canonical_sha256 == root_manifest.legacy_projection_digest
|
|
@@ -207,6 +225,32 @@ class RootDeliveryService:
|
|
|
"error": None,
|
|
"error": None,
|
|
|
"evidence_refs": [],
|
|
"evidence_refs": [],
|
|
|
},
|
|
},
|
|
|
|
|
+ {
|
|
|
|
|
+ "rule_id": "root-goal-coverage",
|
|
|
|
|
+ "verdict": "passed" if goal_coverage_passed else "failed",
|
|
|
|
|
+ "reason": (
|
|
|
|
|
+ "Every parent and child Goal has adopted creative sources"
|
|
|
|
|
+ if goal_coverage_passed
|
|
|
|
|
+ else goal_coverage_error
|
|
|
|
|
+ ),
|
|
|
|
|
+ "error": None,
|
|
|
|
|
+ "evidence_refs": list(structured.source_artifact_refs),
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ "rule_id": "root-direction-contract",
|
|
|
|
|
+ "verdict": "passed" if direction_contract_passed else "failed",
|
|
|
|
|
+ "reason": (
|
|
|
|
|
+ "StructuredScript, Direction rules and Portfolio share one frozen closure"
|
|
|
|
|
+ if direction_contract_passed
|
|
|
|
|
+ else "Root accepted inputs disagree on Direction or StructuredScript"
|
|
|
|
|
+ ),
|
|
|
|
|
+ "error": None,
|
|
|
|
|
+ "evidence_refs": [
|
|
|
|
|
+ _uri(closure.direction),
|
|
|
|
|
+ _uri(closure.portfolio),
|
|
|
|
|
+ _uri(closure.structured),
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
{
|
|
{
|
|
|
"rule_id": "root-legacy-projection",
|
|
"rule_id": "root-legacy-projection",
|
|
|
"verdict": "passed" if projection_passed else "failed",
|
|
"verdict": "passed" if projection_passed else "failed",
|
|
@@ -295,8 +339,8 @@ class _RootClosure:
|
|
|
self.structured = structured
|
|
self.structured = structured
|
|
|
|
|
|
|
|
|
|
|
|
|
-def _direction(version: ArtifactVersion) -> ScriptDirectionArtifactV1:
|
|
|
|
|
- if not isinstance(version.artifact, ScriptDirectionArtifactV1):
|
|
|
|
|
|
|
+def _direction(version: ArtifactVersion) -> DirectionArtifact:
|
|
|
|
|
+ if not isinstance(version.artifact, DirectionArtifact):
|
|
|
raise ProtocolViolation("Root Direction artifact has the wrong type")
|
|
raise ProtocolViolation("Root Direction artifact has the wrong type")
|
|
|
return version.artifact
|
|
return version.artifact
|
|
|
|
|
|