- authority_catalog.py: AuthorityCatalog + CatalogResource (schema aios.catalog.v1). resolve_worker/task/repository/generic; no write path (red line); UNKNOWN fields null, never fabricate live evidence; summary() feeds runtime_source_unknown metric. - Tests: test_authority.py (9) green incl. read-only invariant. Base: agent/annex-2.3-platform-r2-20260914.
194 lines
7.8 KiB
Python
194 lines
7.8 KiB
Python
"""Tests for the read-only Runtime / Authority Catalog (authority_catalog)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
ROOT = os.getcwd()
|
|
if os.path.join(ROOT, "active-runtime") not in sys.path:
|
|
sys.path.append(os.path.join(ROOT, "active-runtime"))
|
|
|
|
from app.task_plane.authority_catalog import AuthorityCatalog, CatalogResource, SCHEMA_VERSION
|
|
from app.task_plane.models import WorkerRegistration
|
|
from app.task_plane.store import TaskPlaneStore
|
|
|
|
WORKER_DICT = {
|
|
"worker_id": "worker-cat-1",
|
|
"worker_type": "codex.readonly",
|
|
"identity": "alice@example.test",
|
|
"capabilities": ["code.change.apply", "shell.exec"],
|
|
"trust_zone": "isolated-development",
|
|
"max_concurrency": 1,
|
|
"heartbeat_interval_seconds": 15,
|
|
"supported_protocols": ["aios-task-v1"],
|
|
}
|
|
|
|
|
|
def test_no_store_returns_complete_null_shape_without_exception():
|
|
catalog = AuthorityCatalog(store=None)
|
|
resource = catalog.resolve_worker("worker-whatever")
|
|
assert isinstance(resource, CatalogResource)
|
|
assert resource.schema_version == SCHEMA_VERSION
|
|
assert resource.resource_type == "worker"
|
|
assert resource.resource_id == "worker-whatever"
|
|
# Structurally complete: all required blocks present.
|
|
for key in ("authority", "runtime", "contracts", "conflicts", "evidence"):
|
|
assert key in resource.to_dict()
|
|
# Nothing fabricated: observation fields are null, evidence empty.
|
|
assert resource.authority["endpoint_or_path"] is None
|
|
assert resource.authority["revision"] is None
|
|
assert resource.runtime["service"] is None
|
|
assert resource.runtime["pid"] is None
|
|
assert resource.runtime["loaded_source_path"] is None
|
|
assert resource.runtime["source_commit"] is None
|
|
assert resource.runtime["artifact_sha256"] is None
|
|
assert resource.evidence == []
|
|
# It is recorded as unknown, not resolved.
|
|
summary = catalog.summary()
|
|
assert summary["unknown"].get("worker") == 1
|
|
assert "worker" not in summary["resolved"]
|
|
|
|
|
|
def test_resolve_worker_returns_worker_id_and_capabilities():
|
|
store = TaskPlaneStore()
|
|
reg = WorkerRegistration.from_dict(WORKER_DICT)
|
|
store.register_worker(reg)
|
|
catalog = AuthorityCatalog(store)
|
|
resource = catalog.resolve_worker("worker-cat-1")
|
|
assert resource.resource_type == "worker"
|
|
assert resource.resource_id == "worker-cat-1"
|
|
assert resource.authority["endpoint_or_path"] == "alice@example.test"
|
|
assert resource.authority["revision"] == 1
|
|
assert resource.runtime["service"] == "codex.readonly"
|
|
caps = [c["value"] for c in resource.contracts if c["field"] == "capabilities"][0]
|
|
assert "shell.exec" in caps
|
|
# Not flagged as runtime source unknown because authority resolved:
|
|
# but runtime source fields are still null for a registration (honest).
|
|
summary = catalog.summary()
|
|
assert summary["resolved"].get("worker") == 1
|
|
assert summary["runtime_source_unknown"] >= 1
|
|
|
|
|
|
def test_resolve_worker_missing_record_is_unknown_not_live():
|
|
store = TaskPlaneStore()
|
|
catalog = AuthorityCatalog(store)
|
|
resource = catalog.resolve_worker("does-not-exist")
|
|
assert resource.resource_id == "does-not-exist"
|
|
assert resource.authority["endpoint_or_path"] is None
|
|
assert resource.authority["revision"] is None
|
|
assert resource.evidence == []
|
|
assert catalog.summary()["unknown"].get("worker") == 1
|
|
|
|
|
|
def test_resolve_generic_unknown_type_is_empty_unknown():
|
|
catalog = AuthorityCatalog(store=None)
|
|
resource = catalog.resolve_generic("release", "rel-9")
|
|
assert resource.resource_type == "release"
|
|
assert resource.resource_id == "rel-9"
|
|
assert resource.authority["kind"] == "release"
|
|
assert resource.authority["endpoint_or_path"] is None
|
|
assert resource.authority["revision"] is None
|
|
assert resource.runtime["loaded_source_path"] is None
|
|
assert resource.evidence == []
|
|
assert catalog.summary()["unknown"].get("release") == 1
|
|
# No live state fabricated: nothing was provisioned as a runtime service.
|
|
assert resource.runtime["service"] is None
|
|
assert resource.runtime["state_root"] is None
|
|
|
|
|
|
def test_to_dict_is_json_serializable():
|
|
store = TaskPlaneStore()
|
|
store.register_worker(WorkerRegistration.from_dict(WORKER_DICT))
|
|
catalog = AuthorityCatalog(store)
|
|
resource = catalog.resolve_worker("worker-cat-1")
|
|
payload = resource.to_dict()
|
|
# Round-trips through JSON without error and preserves values.
|
|
text = json.dumps(payload, ensure_ascii=False)
|
|
restored = json.loads(text)
|
|
assert restored == payload
|
|
assert restored["schema_version"] == SCHEMA_VERSION
|
|
assert restored["resource_id"] == "worker-cat-1"
|
|
assert restored["authority"]["revision"] == 1
|
|
|
|
|
|
def test_resolve_is_read_only_no_store_write():
|
|
store = TaskPlaneStore()
|
|
store.register_worker(WorkerRegistration.from_dict(WORKER_DICT))
|
|
|
|
before_tasks = [t.to_dict() for t in store.list_tasks()]
|
|
before_events = {
|
|
t.task_id: store.list_events(t.task_id) for t in store.list_tasks()
|
|
}
|
|
|
|
catalog = AuthorityCatalog(store)
|
|
catalog.resolve_worker("worker-cat-1")
|
|
catalog.resolve_worker("missing-worker")
|
|
catalog.resolve_repository("repo/main", authority_ref="oid-abcd" if False else None)
|
|
catalog.resolve_generic("schema", "s1")
|
|
|
|
after_tasks = [t.to_dict() for t in store.list_tasks()]
|
|
after_events = {
|
|
t.task_id: store.list_events(t.task_id) for t in store.list_tasks()
|
|
}
|
|
assert before_tasks == after_tasks
|
|
assert before_events == after_events
|
|
|
|
|
|
def test_catalog_exposes_no_write_path():
|
|
write_primitives = {
|
|
"register_worker",
|
|
"create_task",
|
|
"claim_task",
|
|
"append_event",
|
|
"add_evidence",
|
|
"save_receipt",
|
|
"heartbeat_worker",
|
|
"disable_worker",
|
|
"restore_worker",
|
|
"update_task_status",
|
|
"record_progress",
|
|
"complete_claim",
|
|
}
|
|
catalog = AuthorityCatalog(store=None)
|
|
public = {name for name in vars(type(catalog)) if not name.startswith("_")}
|
|
# The catalog only exposes resolve + summary; it must not carry any
|
|
# store-write entry point of its own.
|
|
assert not (public & write_primitives)
|
|
assert public <= {"resolve_worker", "resolve_task", "resolve_repository", "resolve_generic", "summary"}
|
|
|
|
|
|
def test_repository_without_ref_is_unknown_with_ref_reflected():
|
|
catalog = AuthorityCatalog(store=None)
|
|
empty = catalog.resolve_repository("repo/main")
|
|
assert empty.authority["revision"] is None
|
|
# Original caller still gets the repository's identifier as an endpoint
|
|
# hint, but the OID (revision) is unknown until a live ref is supplied.
|
|
assert empty.authority["revision"] is None
|
|
|
|
catalog2 = AuthorityCatalog(store=None)
|
|
with_ref = catalog2.resolve_repository("repo/main", authority_ref="de44a3f01beef")
|
|
assert with_ref.authority["revision"] == "de44a3f01beef"
|
|
assert with_ref.authority["endpoint_or_path"] == "repo/main"
|
|
assert catalog2.summary()["resolved"].get("repository") == 1
|
|
|
|
|
|
def test_summary_tracks_runtime_source_unknown():
|
|
store = TaskPlaneStore()
|
|
store.register_worker(WorkerRegistration.from_dict(WORKER_DICT))
|
|
catalog = AuthorityCatalog(store)
|
|
catalog.resolve_worker("worker-cat-1") # resolved, but source fields null
|
|
catalog.resolve_worker("nope") # unknown
|
|
catalog.resolve_generic("release", "r1") # unknown
|
|
summary = catalog.summary()
|
|
assert summary["resolve_attempts"] == 3
|
|
assert summary["resolved"].get("worker") == 1
|
|
assert summary["unknown"].get("worker") == 1
|
|
assert summary["unknown"].get("release") == 1
|
|
# All three resolved/unknown entries lack loaded source fields.
|
|
assert summary["runtime_source_unknown"] == 3
|
|
assert summary["missing_fields"]["loaded_source_path"] == 3
|
|
assert summary["missing_fields"]["source_commit"] == 3
|
|
assert summary["missing_fields"]["artifact_sha256"] == 3
|