|
@@ -14,10 +14,11 @@ from script_build_host.domain.artifacts import (
|
|
|
ArtifactState,
|
|
ArtifactState,
|
|
|
ArtifactVersion,
|
|
ArtifactVersion,
|
|
|
BusinessArtifact,
|
|
BusinessArtifact,
|
|
|
- Criterion,
|
|
|
|
|
|
|
+ DirectionArtifact,
|
|
|
|
|
+ DirectionConstraint,
|
|
|
DirectionGoal,
|
|
DirectionGoal,
|
|
|
|
|
+ DirectionPreference,
|
|
|
EvidenceRecordV1,
|
|
EvidenceRecordV1,
|
|
|
- ScriptDirectionArtifactV1,
|
|
|
|
|
)
|
|
)
|
|
|
from script_build_host.domain.digests import Sha256Digest
|
|
from script_build_host.domain.digests import Sha256Digest
|
|
|
from script_build_host.domain.errors import (
|
|
from script_build_host.domain.errors import (
|
|
@@ -439,7 +440,7 @@ class SqlAlchemyMissionBindingRepository:
|
|
|
def _artifact_kind(value: BusinessArtifact) -> ArtifactKind:
|
|
def _artifact_kind(value: BusinessArtifact) -> ArtifactKind:
|
|
|
if isinstance(value, EvidenceRecordV1):
|
|
if isinstance(value, EvidenceRecordV1):
|
|
|
return ArtifactKind.EVIDENCE
|
|
return ArtifactKind.EVIDENCE
|
|
|
- if isinstance(value, ScriptDirectionArtifactV1):
|
|
|
|
|
|
|
+ if isinstance(value, DirectionArtifact):
|
|
|
return ArtifactKind.DIRECTION
|
|
return ArtifactKind.DIRECTION
|
|
|
mapping = (
|
|
mapping = (
|
|
|
(StructureArtifactV1, ArtifactKind.STRUCTURE),
|
|
(StructureArtifactV1, ArtifactKind.STRUCTURE),
|
|
@@ -477,17 +478,40 @@ def _hydrate_artifact(kind: ArtifactKind, payload: dict[str, Any], digest: str)
|
|
|
created_at=datetime.fromisoformat(str(payload["created_at"]).replace("Z", "+00:00")),
|
|
created_at=datetime.fromisoformat(str(payload["created_at"]).replace("Z", "+00:00")),
|
|
|
)
|
|
)
|
|
|
if kind is ArtifactKind.DIRECTION:
|
|
if kind is ArtifactKind.DIRECTION:
|
|
|
- return ScriptDirectionArtifactV1(
|
|
|
|
|
- goals=tuple(DirectionGoal(**item) for item in payload["goals"]),
|
|
|
|
|
- criteria=tuple(Criterion(**item) for item in payload.get("criteria", [])),
|
|
|
|
|
- domain_criteria=tuple(Criterion(**item) for item in payload.get("domain_criteria", [])),
|
|
|
|
|
|
|
+ required_fields = {"goals", "constraints", "preferences", "legacy_markdown"}
|
|
|
|
|
+ required_goal_fields = {
|
|
|
|
|
+ "goal_id",
|
|
|
|
|
+ "parent_goal_id",
|
|
|
|
|
+ "statement",
|
|
|
|
|
+ "rationale",
|
|
|
|
|
+ "success_criteria",
|
|
|
|
|
+ }
|
|
|
|
|
+ if not required_fields.issubset(payload) or any(
|
|
|
|
|
+ not required_goal_fields.issubset(item) for item in payload.get("goals", [])
|
|
|
|
|
+ ):
|
|
|
|
|
+ raise ProtocolViolation("stored direction does not match current structured contract")
|
|
|
|
|
+ artifact = DirectionArtifact(
|
|
|
|
|
+ goals=tuple(
|
|
|
|
|
+ DirectionGoal(
|
|
|
|
|
+ goal_id=str(item["goal_id"]),
|
|
|
|
|
+ statement=str(item["statement"]),
|
|
|
|
|
+ rationale=str(item["rationale"]),
|
|
|
|
|
+ parent_goal_id=item["parent_goal_id"],
|
|
|
|
|
+ success_criteria=tuple(item["success_criteria"]),
|
|
|
|
|
+ )
|
|
|
|
|
+ for item in payload["goals"]
|
|
|
|
|
+ ),
|
|
|
|
|
+ constraints=tuple(DirectionConstraint(**item) for item in payload["constraints"]),
|
|
|
|
|
+ preferences=tuple(DirectionPreference(**item) for item in payload["preferences"]),
|
|
|
topic_refs=tuple(payload.get("topic_refs", [])),
|
|
topic_refs=tuple(payload.get("topic_refs", [])),
|
|
|
persona_refs=tuple(payload.get("persona_refs", [])),
|
|
persona_refs=tuple(payload.get("persona_refs", [])),
|
|
|
strategy_refs=tuple(payload.get("strategy_refs", [])),
|
|
strategy_refs=tuple(payload.get("strategy_refs", [])),
|
|
|
evidence_refs=tuple(payload.get("evidence_refs", [])),
|
|
evidence_refs=tuple(payload.get("evidence_refs", [])),
|
|
|
- legacy_markdown=str(payload.get("legacy_markdown", "")),
|
|
|
|
|
canonical_sha256=digest,
|
|
canonical_sha256=digest,
|
|
|
)
|
|
)
|
|
|
|
|
+ if payload["legacy_markdown"] != artifact.legacy_markdown:
|
|
|
|
|
+ raise ProtocolViolation("stored direction projection differs from structured content")
|
|
|
|
|
+ return artifact
|
|
|
if kind is ArtifactKind.ROOT_DELIVERY_MANIFEST:
|
|
if kind is ArtifactKind.ROOT_DELIVERY_MANIFEST:
|
|
|
return hydrate_root_delivery_manifest(payload, digest)
|
|
return hydrate_root_delivery_manifest(payload, digest)
|
|
|
return replace(hydrate_phase_two_artifact(payload), canonical_sha256=digest)
|
|
return replace(hydrate_phase_two_artifact(payload), canonical_sha256=digest)
|