6.5 KiB
Operational Readiness Recipe
Updated: 2026-05-19
This recipe exercises the local operational surface without requiring live
Markitect, Kontextual, or telemetry services. It is the expected smoke path for
embedding phase-memory in another local agent runtime.
Local End-To-End Flow
import json
from pathlib import Path
from phase_memory import LocalServiceRunner
fixtures = Path("tests/fixtures")
profile = json.loads((fixtures / "memory-profile.json").read_text(encoding="utf-8"))
graph = json.loads((fixtures / "memory-graph.json").read_text(encoding="utf-8"))
runner = LocalServiceRunner()
profile_plan = runner.handle("profile.plan", {"profile": profile, "source_ref": "recipe:profile"})
graph_import = runner.handle("graph.import", {"graph": graph, "source_ref": "recipe:graph"})
lifecycle = runner.handle(
"graph.lifecycle.plan",
{
"profile": profile,
"graph": graph,
"parameters": {"refresh_digests": {"event.restart": "new-digest"}},
"source_ref": "recipe:lifecycle",
},
)
activation = runner.handle(
"graph.activation.plan",
{
"graph": graph,
"budget": {"max_items": 3, "max_tokens": 60},
"profile_id": profile["id"],
"source_ref": "recipe:activation",
},
)
package = runner.handle(
"package.compile",
{
"selection": activation["data"]["activation_plan"]["selection"],
"source_ref": "recipe:package",
},
)
audit = runner.handle("audit.query", {"filters": {"operation": "package.compile"}})
health = runner.handle("health.check")
Expected checks:
profile_plan["valid"],graph_import["valid"],activation["valid"], andpackage["valid"]are true.lifecycle["data"]["dry_run_actions"]contains the planned refresh action.audit["count"]is at least 1 andaudit["retention"]declares the active audit sink retention mode.health["ok"]is true.
Service Binding Drill
ServiceBinding wraps LocalServiceRunner in an HTTP-shaped API without
starting a listener:
from phase_memory import ServiceBinding
binding = ServiceBinding(runner)
health_response = binding.route("GET", "/health")
ready_response = binding.route("GET", "/ready")
contracts_response = binding.route("GET", "/contracts")
package_response = binding.route(
"POST",
"/operations/package.compile",
{"selection": activation["data"]["activation_plan"]["selection"]},
)
The WSGI adapter returned by binding.as_wsgi_app() is also callable in tests
without opening a socket. Use this for deployment wrappers so the core service
operation contract stays framework-neutral.
For the stdlib deployable entrypoint, use:
phase-memory-service --check --store .phase-memory-local
phase-memory-service --host 127.0.0.1 --port 8080 --store .phase-memory-local
See docs/operator-readiness-runbook.md for operator checks and rollback
guidance.
Review-Gated Apply
Lifecycle actions that require review are denied until an approval marker or matching review record is supplied:
denied = runner.handle("lifecycle.apply", {"actions": lifecycle["data"]["dry_run_actions"]})
approved = runner.handle(
"lifecycle.apply",
{
"actions": lifecycle["data"]["dry_run_actions"],
"approval_marker": "review:operator-approved",
},
)
Use audit.query with {"operation": "lifecycle.apply", "dry_run": False} to
trace denied and approved apply attempts.
Persistence Repair Drill
File-backed operation is configured through a profile or explicit
RuntimeConfig:
from phase_memory import RuntimeConfig, LocalServiceRunner
config = RuntimeConfig.from_profile(profile, local_store_path=".phase-memory-local")
runner = LocalServiceRunner(config=config)
repair = runner.runtime.repair_diagnostics(source_ref=config.local_store_path)
migration_plan = runner.runtime.plan_store_migration(source_ref=config.local_store_path)
migration_apply = runner.runtime.apply_store_migration(
migration_plan["data"]["migration_plan"],
actor="operator",
source_ref=config.local_store_path,
)
Repair diagnostics distinguish:
store_migration_requiredfor old or missing local-store schema metadata.planned_store_migrationswhen metadata declares pending migrations.corrupt_store_recordfor unreadable node, edge, or path JSON.missing_edge_source/missing_edge_targetfor graph reference damage.orphaned_path_eventwhen paths reference absent event-log records.
Migration apply is audited as store.migration.apply and updates metadata
atomically when changes are needed.
Audit Export And Retention Drill
Runtime audit behavior is inspectable beyond point queries:
export = runner.runtime.export_audit_events({"operation": "package.compile"})
retention = runner.runtime.audit_retention_plan(retention_days=30)
The export batch includes matching audit events and sink retention metadata.
The retention plan identifies eligible operation ids. Retention apply prunes
eligible records and records audit.retention.apply after pruning:
retention_apply = runner.runtime.apply_audit_retention(retention["plan"])
Adapter Pack Compatibility
Fake and future live adapter packs should publish a manifest with:
- declared capabilities;
- ownership boundaries for every adapter;
- required conformance helpers.
Validate fake or live-shaped packs before wiring them into the runtime:
from phase_memory import fake_external_adapter_pack, live_shaped_adapter_pack, validate_adapter_pack_manifest
diagnostics = validate_adapter_pack_manifest(fake_external_adapter_pack())
assert diagnostics == ()
live_diagnostics = validate_adapter_pack_manifest(live_shaped_adapter_pack())
assert live_diagnostics == ()
Missing capabilities are reported as missing_adapter_capability diagnostics
with the adapter and capability names attached.
API Compatibility Expectations
The stable embedding surface is:
PhaseMemoryRuntimemethods and JSON-serializable envelopes.LocalServiceRunner.handle(operation, payload)for every operation inservice_contracts()["operations"].RuntimeConfigandresolve_runtime_adaptersfor local/external adapter resolution.ServiceBindingandservice_binding_from_configfor optional service wrappers.- Adapter conformance helpers in
phase_memory.service. - External adapter pack manifests and validation helpers.
- Public export and service operation snapshots in
tests/fixtures/public-api-snapshot.json.
New public operations should be added to the service contract first, then to the local runner, runtime tests, and docs in the same change.