generated from coulomb/repo-seed
179 lines
5.5 KiB
Python
179 lines
5.5 KiB
Python
from kontextual_engine.core import (
|
|
Actor,
|
|
ActorType,
|
|
AssetRepresentation,
|
|
AssetVersion,
|
|
AuditEvent,
|
|
AuditOutcome,
|
|
Classification,
|
|
DerivedArtifactLineage,
|
|
KnowledgeAsset,
|
|
LifecycleState,
|
|
MetadataRecord,
|
|
OperationContext,
|
|
PolicyDecision,
|
|
PolicyEffect,
|
|
RepresentationKind,
|
|
Sensitivity,
|
|
SourceReference,
|
|
VersionChangeType,
|
|
)
|
|
|
|
|
|
def test_knowledge_asset_identity_is_independent_of_source_and_representation() -> None:
|
|
source = SourceReference(source_system="repo", path="docs/intent.md", checksum="sha256:source")
|
|
classification = Classification(
|
|
asset_type="document",
|
|
sensitivity=Sensitivity.INTERNAL,
|
|
lifecycle=LifecycleState.ACTIVE,
|
|
owner="Platform Knowledge",
|
|
)
|
|
asset = KnowledgeAsset.create(
|
|
"Intent",
|
|
classification,
|
|
asset_id="asset-intent",
|
|
source_refs=[source],
|
|
aliases=["INTENT.md"],
|
|
)
|
|
|
|
moved = asset.with_source_reference(
|
|
SourceReference(source_system="repo", path="wiki/INTENT.md", checksum="sha256:source")
|
|
)
|
|
normalized = AssetRepresentation.from_content(
|
|
asset.id,
|
|
RepresentationKind.NORMALIZED,
|
|
"text/markdown+normalized",
|
|
"# Intent\n\nNormalized body.",
|
|
producer="markitect-tool",
|
|
)
|
|
|
|
assert moved.id == asset.id
|
|
assert moved.source_refs[0].path == "docs/intent.md"
|
|
assert moved.source_refs[1].path == "wiki/INTENT.md"
|
|
assert normalized.asset_id == asset.id
|
|
assert normalized.kind == RepresentationKind.NORMALIZED
|
|
|
|
|
|
def test_representations_keep_source_normalized_and_derived_forms_distinct() -> None:
|
|
source = AssetRepresentation.from_content(
|
|
"asset-1",
|
|
RepresentationKind.SOURCE,
|
|
"text/markdown",
|
|
"# Source\n",
|
|
storage_ref="object://source",
|
|
)
|
|
normalized = AssetRepresentation.from_content(
|
|
"asset-1",
|
|
RepresentationKind.NORMALIZED,
|
|
"application/vnd.kontextual.normalized+json",
|
|
'{"text":"Source"}',
|
|
producer="markitect-tool",
|
|
metadata={"adapter_snapshot_id": "snapshot:123"},
|
|
)
|
|
derived = AssetRepresentation.from_content(
|
|
"asset-2",
|
|
RepresentationKind.DERIVED,
|
|
"text/markdown",
|
|
"# Summary\n",
|
|
producer="summarize",
|
|
)
|
|
|
|
assert source.kind == RepresentationKind.SOURCE
|
|
assert normalized.kind == RepresentationKind.NORMALIZED
|
|
assert derived.kind == RepresentationKind.DERIVED
|
|
assert source.digest != normalized.digest
|
|
assert normalized.metadata["adapter_snapshot_id"] == "snapshot:123"
|
|
|
|
|
|
def test_actor_policy_and_audit_context_are_explicit() -> None:
|
|
actor = Actor.create(
|
|
ActorType.AI_AGENT,
|
|
actor_id="agent-codex",
|
|
display_name="Codex",
|
|
groups=["engineering"],
|
|
)
|
|
context = OperationContext.create(
|
|
actor,
|
|
correlation_id="corr-123",
|
|
policy_scope={"sensitivity": "internal"},
|
|
)
|
|
decision = PolicyDecision.fail_closed(
|
|
actor.id,
|
|
"retrieve",
|
|
"asset:secret",
|
|
reason="missing permission envelope",
|
|
)
|
|
event = AuditEvent.from_context(
|
|
"retrieve",
|
|
"asset:secret",
|
|
AuditOutcome.DENIED,
|
|
context,
|
|
policy_decision=decision,
|
|
)
|
|
|
|
assert decision.effect == PolicyEffect.FAIL_CLOSED
|
|
assert decision.allowed is False
|
|
assert event.actor_id == "agent-codex"
|
|
assert event.correlation_id == "corr-123"
|
|
assert event.to_dict()["policy_decision"]["reason"] == "missing permission envelope"
|
|
|
|
|
|
def test_versions_and_lineage_explain_derived_artifacts() -> None:
|
|
actor = Actor.create(ActorType.HUMAN, actor_id="user-1", display_name="User")
|
|
source_version = AssetVersion(
|
|
asset_id="asset-source",
|
|
sequence=1,
|
|
change_type=VersionChangeType.CREATED,
|
|
representation_ids=("repr-source",),
|
|
actor_id=actor.id,
|
|
)
|
|
derived_version = AssetVersion(
|
|
asset_id="asset-derived",
|
|
sequence=1,
|
|
change_type=VersionChangeType.DERIVED_OUTPUT,
|
|
representation_ids=("repr-derived",),
|
|
actor_id=actor.id,
|
|
operation_id="run-summary",
|
|
parent_version_id=source_version.version_id,
|
|
)
|
|
lineage = DerivedArtifactLineage(
|
|
source_asset_ids=("asset-source",),
|
|
source_version_ids=(source_version.version_id,),
|
|
transformation_run_id="run-summary",
|
|
output_asset_id="asset-derived",
|
|
output_representation_id="repr-derived",
|
|
actor_id=actor.id,
|
|
parameters={"style": "brief"},
|
|
policy_context={"effect": "allow"},
|
|
adapter_provenance={"operation": "summarize"},
|
|
)
|
|
|
|
data = lineage.to_dict()
|
|
|
|
assert derived_version.parent_version_id == source_version.version_id
|
|
assert data["source_asset_ids"] == ["asset-source"]
|
|
assert data["source_version_ids"] == [source_version.version_id]
|
|
assert data["parameters"] == {"style": "brief"}
|
|
assert data["policy_context"] == {"effect": "allow"}
|
|
assert data["lineage_hash"].startswith("sha256:")
|
|
|
|
|
|
def test_metadata_records_distinguish_inferred_and_confirmed_values() -> None:
|
|
inferred = MetadataRecord(
|
|
"topic",
|
|
"architecture",
|
|
provenance={"producer": "classifier"},
|
|
confidence=0.74,
|
|
confirmed=False,
|
|
)
|
|
confirmed = MetadataRecord(
|
|
"owner",
|
|
"Platform Knowledge",
|
|
provenance={"producer": "human"},
|
|
confirmed=True,
|
|
)
|
|
|
|
assert inferred.to_dict()["confidence"] == 0.74
|
|
assert inferred.to_dict()["confirmed"] is False
|
|
assert confirmed.to_dict()["confirmed"] is True
|