generated from coulomb/repo-seed
Implement credentialed drill packaging workplan
This commit is contained in:
16
tests/fixtures/public-api-snapshot.json
vendored
16
tests/fixtures/public-api-snapshot.json
vendored
@@ -1,9 +1,16 @@
|
||||
{
|
||||
"compatibility": {
|
||||
"release_note_template": "docs/release-note-template.md"
|
||||
},
|
||||
"exports": [
|
||||
"ADAPTER_PACK_MANIFEST_SCHEMA",
|
||||
"ActivationPlan",
|
||||
"CREDENTIALED_ADAPTER_ENV_VARS",
|
||||
"CREDENTIALED_DRILL_SCHEMA",
|
||||
"CredentialedDrillConfig",
|
||||
"Diagnostic",
|
||||
"EVALUATION_REPORT_SCHEMA",
|
||||
"EVALUATION_TREND_SCHEMA",
|
||||
"ExternalAdapterPack",
|
||||
"FakeExternalEventLog",
|
||||
"FakeExternalGraphStore",
|
||||
@@ -49,7 +56,9 @@
|
||||
"ReviewRecord",
|
||||
"RuntimeAdapterBundle",
|
||||
"RuntimeConfig",
|
||||
"SERVICE_APP_SCHEMA",
|
||||
"SERVICE_BINDING_SCHEMA",
|
||||
"ServiceAppConfig",
|
||||
"ServiceBinding",
|
||||
"ServiceResponse",
|
||||
"WordCountTokenEstimator",
|
||||
@@ -57,9 +66,14 @@
|
||||
"activation_quality_report",
|
||||
"adapter_pack_manifest",
|
||||
"branch_path",
|
||||
"build_service_binding",
|
||||
"compact_path",
|
||||
"create_path",
|
||||
"create_wsgi_app",
|
||||
"credentialed_adapter_smoke_report",
|
||||
"credentialed_drill_config_from_env",
|
||||
"evaluation_threshold_report",
|
||||
"evaluation_trend_artifact",
|
||||
"fake_external_adapter_pack",
|
||||
"fake_external_runtime_config",
|
||||
"graph_from_markitect",
|
||||
@@ -67,6 +81,7 @@
|
||||
"live_shaped_adapter_pack",
|
||||
"make_review_record",
|
||||
"merge_path",
|
||||
"missing_credentialed_adapter_env",
|
||||
"package_request_from_selection",
|
||||
"package_response_envelope",
|
||||
"path_event",
|
||||
@@ -85,6 +100,7 @@
|
||||
"retrieve_graph_neighborhood",
|
||||
"runtime_from_config",
|
||||
"select_event_path",
|
||||
"service_app_metadata",
|
||||
"service_binding_from_config",
|
||||
"service_contracts",
|
||||
"validate_adapter_pack_manifest"
|
||||
|
||||
@@ -70,3 +70,58 @@ def test_audit_retention_plan_identifies_eligible_records() -> None:
|
||||
assert plan["valid"] is True
|
||||
assert plan["plan"]["eligible_operation_ids"] == ["op:old"]
|
||||
assert plan["plan"]["eligible_count"] == 1
|
||||
|
||||
|
||||
def test_audit_retention_apply_prunes_eligible_records_and_records_apply() -> None:
|
||||
runtime = PhaseMemoryRuntime()
|
||||
runtime.audit_sink.record(
|
||||
{
|
||||
"schema_version": "phase_memory.audit.event.v1",
|
||||
"operation_id": "op:old",
|
||||
"operation": "manual",
|
||||
"timestamp": "2026-01-01T00:00:00+00:00",
|
||||
"subject": {"kind": "audit_events", "id": "old"},
|
||||
"source": {"ref": "test"},
|
||||
"dry_run": True,
|
||||
"allowed": True,
|
||||
}
|
||||
)
|
||||
runtime.audit_sink.record(
|
||||
{
|
||||
"schema_version": "phase_memory.audit.event.v1",
|
||||
"operation_id": "op:new",
|
||||
"operation": "manual",
|
||||
"timestamp": "2026-05-18T00:00:00+00:00",
|
||||
"subject": {"kind": "audit_events", "id": "new"},
|
||||
"source": {"ref": "test"},
|
||||
"dry_run": True,
|
||||
"allowed": True,
|
||||
}
|
||||
)
|
||||
|
||||
plan = runtime.audit_retention_plan(retention_days=30, now=datetime(2026, 5, 19, tzinfo=timezone.utc))
|
||||
applied = runtime.apply_audit_retention(plan["plan"])
|
||||
remaining_ids = [event["operation_id"] for event in runtime.audit_sink.query()]
|
||||
|
||||
assert applied["valid"] is True
|
||||
assert applied["result"]["pruned_operation_ids"] == ["op:old"]
|
||||
assert "op:old" not in remaining_ids
|
||||
assert "op:new" in remaining_ids
|
||||
assert any(event["operation"] == "audit.retention.apply" for event in runtime.audit_sink.query())
|
||||
|
||||
|
||||
def test_audit_retention_apply_noop_and_unsupported_paths() -> None:
|
||||
runtime = PhaseMemoryRuntime()
|
||||
noop = runtime.apply_audit_retention(retention_days=30, now=datetime(2026, 5, 19, tzinfo=timezone.utc))
|
||||
assert noop["valid"] is True
|
||||
assert noop["result"]["changed"] is False
|
||||
|
||||
class UnsupportedAuditSink:
|
||||
def record(self, event):
|
||||
return {"recorded": True, "event": event}
|
||||
|
||||
unsupported = PhaseMemoryRuntime(audit_sink=UnsupportedAuditSink())
|
||||
result = unsupported.apply_audit_retention(retention_days=30)
|
||||
|
||||
assert result["valid"] is False
|
||||
assert result["diagnostics"][0]["code"] == "audit_retention_apply_unsupported"
|
||||
|
||||
32
tests/test_credentialed_drills.py
Normal file
32
tests/test_credentialed_drills.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from phase_memory.credentialed_drills import (
|
||||
CREDENTIALED_ADAPTER_ENV_VARS,
|
||||
credentialed_adapter_smoke_report,
|
||||
missing_credentialed_adapter_env,
|
||||
)
|
||||
|
||||
|
||||
def test_credentialed_adapter_drill_reports_missing_env_without_secrets() -> None:
|
||||
report = credentialed_adapter_smoke_report({})
|
||||
|
||||
assert report["valid"] is False
|
||||
assert report["skipped"] is True
|
||||
assert tuple(report["missing_env"]) == CREDENTIALED_ADAPTER_ENV_VARS
|
||||
assert report["diagnostics"][0]["code"] == "credential_env_missing"
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
missing_credentialed_adapter_env(os.environ),
|
||||
reason="requires env vars: " + ", ".join(CREDENTIALED_ADAPTER_ENV_VARS),
|
||||
)
|
||||
def test_credentialed_adapter_drill_reuses_manifest_contract_when_env_is_present() -> None:
|
||||
report = credentialed_adapter_smoke_report(os.environ)
|
||||
|
||||
assert report["valid"] is True
|
||||
assert report["skipped"] is False
|
||||
assert report["adapter_pack"]["name"] == "live-shaped"
|
||||
assert report["config"]["credential_fingerprint"]
|
||||
assert "PHASE_MEMORY_MARKITECT_TOKEN" not in str(report)
|
||||
@@ -4,7 +4,7 @@ from pathlib import Path
|
||||
|
||||
from phase_memory.adapters import InMemorySemanticIndex
|
||||
from phase_memory.contracts import graph_from_markitect
|
||||
from phase_memory.evaluation import EVALUATION_REPORT_SCHEMA, evaluation_threshold_report
|
||||
from phase_memory.evaluation import EVALUATION_REPORT_SCHEMA, EVALUATION_TREND_SCHEMA, evaluation_threshold_report, evaluation_trend_artifact
|
||||
from phase_memory.models import ActivationPlan, MemoryPath
|
||||
from phase_memory.retrieval import activation_quality_report, select_event_path
|
||||
from phase_memory.runtime import PhaseMemoryRuntime
|
||||
@@ -102,6 +102,30 @@ def test_evaluation_threshold_report_summarizes_all_scenarios() -> None:
|
||||
assert report["diagnostics"] == []
|
||||
|
||||
|
||||
def test_evaluation_trend_artifact_tracks_threshold_and_metric_deltas() -> None:
|
||||
data = json.loads((FIXTURES / "evaluation-scenarios.json").read_text(encoding="utf-8"))
|
||||
report = evaluation_threshold_report(data)
|
||||
previous = {
|
||||
"id": "previous",
|
||||
"metrics": {
|
||||
**report["metrics"],
|
||||
"policy_denial_count": report["metrics"]["policy_denial_count"] + 1,
|
||||
},
|
||||
}
|
||||
|
||||
trend = evaluation_trend_artifact(
|
||||
report,
|
||||
previous_report=previous,
|
||||
run_metadata={"run_id": "pytest", "created_at": "2026-05-19T00:00:00+00:00"},
|
||||
)
|
||||
|
||||
assert trend["schema_version"] == EVALUATION_TREND_SCHEMA
|
||||
assert trend["run"]["run_id"] == "pytest"
|
||||
assert trend["threshold_deltas"]["policy_denial_count"] == 0.0
|
||||
assert trend["metric_deltas"]["policy_denial_count"] == -1.0
|
||||
assert trend["diagnostics"][0]["code"] == "evaluation_metric_regressed"
|
||||
|
||||
|
||||
def _activation_plan(response):
|
||||
data = response["data"]["activation_plan"]
|
||||
return ActivationPlan(
|
||||
|
||||
@@ -13,6 +13,10 @@ def test_public_api_snapshot_is_explicit() -> None:
|
||||
|
||||
assert sorted(phase_memory.__all__) == snapshot["exports"]
|
||||
assert sorted(SERVICE_OPERATIONS) == snapshot["service_operations"]
|
||||
release_note_template = Path(snapshot["compatibility"]["release_note_template"])
|
||||
template_text = release_note_template.read_text(encoding="utf-8")
|
||||
for heading in ("Changed Exports", "Changed Service Operations", "Migration Needs", "Operator Action"):
|
||||
assert heading in template_text
|
||||
|
||||
|
||||
def test_service_contract_catalog_matches_local_runner_supported_operations() -> None:
|
||||
|
||||
41
tests/test_service_app.py
Normal file
41
tests/test_service_app.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import json
|
||||
from io import BytesIO
|
||||
|
||||
from phase_memory.service_app import ServiceAppConfig, create_wsgi_app, main, service_app_metadata
|
||||
|
||||
|
||||
def test_service_app_metadata_exposes_deployable_routes_without_listener(tmp_path) -> None:
|
||||
config = ServiceAppConfig(host="127.0.0.1", port=8123, local_store_path=str(tmp_path))
|
||||
|
||||
metadata = service_app_metadata(config)
|
||||
|
||||
assert metadata["schema_version"] == "phase_memory.service.app.v1"
|
||||
assert metadata["config"]["port"] == 8123
|
||||
assert metadata["readiness"]["ok"] is True
|
||||
assert metadata["routes"]["operations"] == "/operations/{operation}"
|
||||
|
||||
|
||||
def test_service_wsgi_app_can_dispatch_without_opening_listener(tmp_path) -> None:
|
||||
app = create_wsgi_app(ServiceAppConfig(local_store_path=str(tmp_path)))
|
||||
statuses: list[str] = []
|
||||
|
||||
payload = json.dumps({"selection": {"schema_version": "markitect.memory.selection.v1", "id": "svc", "nodes": [], "events": []}}).encode("utf-8")
|
||||
body = b"".join(
|
||||
app(
|
||||
{
|
||||
"REQUEST_METHOD": "POST",
|
||||
"PATH_INFO": "/operations/package.compile",
|
||||
"CONTENT_LENGTH": str(len(payload)),
|
||||
"wsgi.input": BytesIO(payload),
|
||||
},
|
||||
lambda status, _headers: statuses.append(status),
|
||||
)
|
||||
)
|
||||
|
||||
response = json.loads(body.decode("utf-8"))
|
||||
assert statuses == ["200 OK"]
|
||||
assert response["operation"] == "package.compile"
|
||||
|
||||
|
||||
def test_service_main_check_builds_app_without_serving(tmp_path) -> None:
|
||||
assert main(["--check", "--store", str(tmp_path), "--port", "8124"]) == 0
|
||||
Reference in New Issue
Block a user