Files
phase-memory/docs/operational-readiness.md

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"], and package["valid"] are true.
  • lifecycle["data"]["dry_run_actions"] contains the planned refresh action.
  • audit["count"] is at least 1 and audit["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_required for old or missing local-store schema metadata.
  • planned_store_migrations when metadata declares pending migrations.
  • corrupt_store_record for unreadable node, edge, or path JSON.
  • missing_edge_source / missing_edge_target for graph reference damage.
  • orphaned_path_event when 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:

  • PhaseMemoryRuntime methods and JSON-serializable envelopes.
  • LocalServiceRunner.handle(operation, payload) for every operation in service_contracts()["operations"].
  • RuntimeConfig and resolve_runtime_adapters for local/external adapter resolution.
  • ServiceBinding and service_binding_from_config for 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.