teleo-infrastructure/tests/test_apply_worker.py
twentyOne2x fed5cb0805 Add guarded canonical claim application
- Normalize rich proposals into atomic reviewed canonical graph bundles with exact row verification.
- Harden reviewer/apply roles, upgrade ACLs, and prove generic plus Helmer lifecycles in isolated PostgreSQL.
- Publish repo-native VPS/GCP/Cory skills and live-readonly GCP inventory without changing the live VPS runtime.

`.agents/skills/crabbox/SKILL.md`
`.agents/skills/teleo-gcp-parity-ops/SKILL.md`
`.agents/skills/teleo-kb-db-change-workflow/SKILL.md`
`.agents/skills/teleo-leo-onboarding/SKILL.md`
`.agents/skills/teleo-vps-runtime-ops/SKILL.md`
`.agents/skills/working-leo-cory-outcomes/SKILL.md`
`docs/reports/leo-working-state-20260709/approve-claim-clone-canary-current.json`
`docs/reports/leo-working-state-20260709/approve-claim-clone-canary-current.md`
`docs/reports/leo-working-state-20260709/current-truth-index.md`
`docs/reports/leo-working-state-20260709/gcp-cloud-sql-t3-live-readonly-current.json`
`docs/reports/leo-working-state-20260709/gcp-cloud-sql-t3-live-readonly-current.md`
`docs/reports/leo-working-state-20260709/gcp-cloudsql-studio-parity-gate-current.json`
`docs/reports/leo-working-state-20260709/gcp-cloudsql-studio-parity-gate-current.md`
`docs/reports/leo-working-state-20260709/gcp-parallel-delegation-current.json`
`docs/reports/leo-working-state-20260709/helmer-approve-claim-clone-canary-current.json`
`docs/reports/leo-working-state-20260709/helmer-approve-claim-normalization-current.json`
`docs/reports/leo-working-state-20260709/skill-pack-manifest.json`
`docs/reports/leo-working-state-20260709/skill-pack-readme.md`
`docs/reports/leo-working-state-20260709/working-leo-current-state-20260709.md`
`docs/reports/leo-working-state-20260709/working-leo-definition-20260709.md`
`docs/reports/leo-working-state-20260709/working-leo-execution-plan-current.md`
`scripts/apply_proposal.py`
`scripts/apply_worker.py`
`scripts/approve_proposal.py`
`scripts/kb_apply_prereqs.sql`
`scripts/kb_proposal_normalize.py`
`scripts/probe_gcp_db_parity.py`
`scripts/run_approve_claim_clone_canary.py`
`scripts/run_approve_claim_isolated_container_canary.sh`
`tests/test_apply_proposal.py`
`tests/test_apply_worker.py`
`tests/test_approve_proposal.py`
`tests/test_kb_apply_prereqs.py`
`tests/test_kb_proposal_normalize.py`
`tests/test_kb_proposal_routes.py`
`tests/test_probe_gcp_db_parity.py`
`tests/test_repo_skill_pack.py`
2026-07-10 17:49:37 +02:00

280 lines
9.3 KiB
Python

"""Unit tests for scripts/apply_worker.py.
Pure tests: query building, candidate parsing, render-hook expansion, and the
report-only enablement gate -- no live database. Runnable under pytest or
standalone (`python3 tests/test_apply_worker.py`).
"""
import argparse
import sys
from pathlib import Path
try:
import pytest
except ImportError: # standalone fallback so the file runs without pytest installed
import contextlib
import types
pytest = types.SimpleNamespace()
@contextlib.contextmanager
def _raises(exc):
try:
yield
except exc:
return
raise AssertionError(f"expected {exc.__name__} to be raised")
def _fixture(*_args, **_kwargs):
def decorator(func):
return func
return decorator
pytest.raises = _raises
pytest.fixture = _fixture
REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "scripts"))
import apply_worker as w # noqa: E402
@pytest.fixture(autouse=True)
def restore_apply_worker_dependencies():
original_load_password = w.ap.load_password
original_load_failure_state = w.load_failure_state
original_fetch_candidates = w.fetch_candidates
original_apply_one = w.apply_one
original_render_one = w.render_one
yield
w.ap.load_password = original_load_password
w.load_failure_state = original_load_failure_state
w.fetch_candidates = original_fetch_candidates
w.apply_one = original_apply_one
w.render_one = original_render_one
# --- candidate query ------------------------------------------------------ #
def test_candidate_query_filters_on_approved():
sql = w.build_candidate_query()
# The structural guarantee: worker can only ever act on approved proposals.
assert "status = 'approved'" in sql
# Never selects pending_review (no auto-approve possible).
assert "pending_review" not in sql
def test_candidate_query_requires_apply_payload():
sql = w.build_candidate_query()
assert "payload ? 'apply_payload'" in sql
def test_candidate_query_lists_worker_types_only():
sql = w.build_candidate_query()
for t in w.WORKER_TYPES:
assert f"'{t}'" in sql
# a non-applyable type must not appear
assert "reject_claim" not in sql
def test_candidate_query_can_exclude_poisoned_ids_before_limit():
sql = w.build_candidate_query(excluded_ids=("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",))
assert "id::text not in" in sql.lower()
assert "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa" in sql
assert sql.lower().index("id::text not in") < sql.lower().index("limit 20")
def test_worker_includes_approved_claim_bundles_without_unproven_render_hook():
assert "approve_claim" in w.WORKER_TYPES
assert "approve_claim" not in w.RENDER_TYPES
sql = w.build_candidate_query()
assert "'approve_claim'" in sql
# --- candidate parsing ---------------------------------------------------- #
def test_parse_candidates_skips_blank_lines():
out = '{"id": "a", "proposal_type": "add_edge", "agent_id": null}\n\n'
rows = w.parse_candidates(out)
assert len(rows) == 1
assert rows[0]["id"] == "a"
# --- render hook ---------------------------------------------------------- #
def test_render_command_none_when_unset():
assert w.build_render_command("", "agent-1") is None
def test_render_command_none_without_agent():
assert w.build_render_command("python3 render_soul.py --agent-id {agent_id}", None) is None
def test_render_command_expands_agent_id():
cmd = w.build_render_command("python3 render_soul.py --agent-id {agent_id}", "abc")
assert cmd == ["python3", "render_soul.py", "--agent-id", "abc"]
# --- enablement gate ------------------------------------------------------ #
def _args(**over):
base = dict(
enable=False, limit=20, max_per_tick=1, max_attempts=3,
failure_state_file=None, applied_by="kb-apply",
apply_script="apply_proposal.py", render_cmd="",
secrets_file="x", container="teleo-pg", db="teleo",
host="127.0.0.1", role="kb_apply",
)
base.update(over)
return argparse.Namespace(**base)
def test_report_only_gate_does_not_apply(monkeypatch=None):
calls = []
w.ap.load_password = lambda _f: "pw"
w.fetch_candidates = lambda a, p, excluded: [
{"id": "p1", "proposal_type": "revise_strategy", "agent_id": "ag"}
]
w.apply_one = lambda a, pid: calls.append(pid)
rc = w.run(_args(enable=False))
assert rc == 0
assert calls == [] # disabled worker performs NO writes
def test_enabled_worker_applies_and_renders():
applied, rendered = [], []
w.ap.load_password = lambda _f: "pw"
w.fetch_candidates = lambda a, p, excluded: [
{"id": "p1", "proposal_type": "revise_strategy", "agent_id": "ag"}
]
w.apply_one = lambda a, pid: applied.append(pid)
w.render_one = lambda a, agent_id: rendered.append(agent_id) or "ok"
rc = w.run(_args(enable=True))
assert rc == 0
assert applied == ["p1"]
assert rendered == ["ag"] # revise_strategy triggers a render
def test_enabled_worker_skips_render_for_add_edge():
applied, rendered = [], []
w.ap.load_password = lambda _f: "pw"
w.fetch_candidates = lambda a, p, excluded: [
{"id": "e1", "proposal_type": "add_edge", "agent_id": None}
]
w.apply_one = lambda a, pid: applied.append(pid)
w.render_one = lambda a, agent_id: rendered.append(agent_id) or "ok"
rc = w.run(_args(enable=True))
assert rc == 0
assert applied == ["e1"]
assert rendered == [] # add_edge changes the graph, not the rendered self
def test_enabled_worker_skips_render_for_approve_claim():
applied, rendered = [], []
w.ap.load_password = lambda _f: "pw"
w.fetch_candidates = lambda a, p, excluded: [
{"id": "c1", "proposal_type": "approve_claim", "agent_id": "ag"}
]
w.apply_one = lambda a, pid: applied.append(pid)
w.render_one = lambda a, agent_id: rendered.append(agent_id) or "ok"
rc = w.run(_args(enable=True))
assert rc == 0
assert applied == ["c1"]
assert rendered == [] # no proven agent-owned approve_claim render contract
# --- per-tick cap + poison-pill ceiling ----------------------------------- #
def _cands(*ids):
return [{"id": i, "proposal_type": "add_edge", "agent_id": None} for i in ids]
def test_partition_caps_to_max_per_tick():
split = w.partition_candidates(_cands("a", "b", "c"), {}, max_attempts=3, max_per_tick=1)
assert [c["id"] for c in split["to_apply"]] == ["a"] # only 1 applied per tick
assert split["poisoned"] == []
def test_partition_skips_poison_pill_over_ceiling():
split = w.partition_candidates(_cands("a", "b"), {"a": 3}, max_attempts=3, max_per_tick=5)
assert [c["id"] for c in split["poisoned"]] == ["a"] # a is poisoned, never retried
assert [c["id"] for c in split["to_apply"]] == ["b"] # b still eligible
def test_enabled_worker_caps_applies_at_one_per_tick():
applied = []
w.ap.load_password = lambda _f: "pw"
w.fetch_candidates = lambda a, p, excluded: _cands("e1", "e2", "e3")
w.apply_one = lambda a, pid: applied.append(pid)
rc = w.run(_args(enable=True, max_per_tick=1))
assert rc == 0
assert applied == ["e1"] # capped to 1 even with 3 approved candidates
def test_failure_state_roundtrip_and_ceiling(tmp_path=None):
import tempfile
d = tempfile.mkdtemp()
path = str(Path(d) / "failures.json")
w.save_failure_state(path, {"p1": 2})
assert w.load_failure_state(path) == {"p1": 2}
# p1 at 2 with max_attempts 3 is still eligible; at 3 it poisons
split = w.partition_candidates(_cands("p1"), {"p1": 3}, max_attempts=3, max_per_tick=1)
assert [c["id"] for c in split["poisoned"]] == ["p1"]
def test_apply_failure_increments_persisted_count():
import tempfile
path = str(Path(tempfile.mkdtemp()) / "failures.json")
w.ap.load_password = lambda _f: "pw"
w.fetch_candidates = lambda a, p, excluded: _cands("bad")
def _boom(a, pid):
raise RuntimeError("deterministic failure")
w.apply_one = _boom
rc = w.run(_args(enable=True, failure_state_file=path, max_per_tick=1))
assert rc == 1
assert w.load_failure_state(path).get("bad") == 1 # count persisted for next tick
def test_run_loads_failure_state_and_excludes_exhausted_ids_before_fetch():
events = []
poisoned_id = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"
w.ap.load_password = lambda _f: "pw"
w.load_failure_state = lambda _path: events.append("load") or {poisoned_id: 3}
def _fetch(args, password, excluded_ids):
events.append(("fetch", excluded_ids))
return []
w.fetch_candidates = _fetch
rc = w.run(_args(max_attempts=3))
assert rc == 0
assert events == ["load", ("fetch", (poisoned_id,))]
if __name__ == "__main__":
import traceback
failures = 0
for name, fn in sorted(globals().items()):
if name.startswith("test_") and callable(fn):
restore = restore_apply_worker_dependencies()
next(restore)
try:
fn()
print(f"PASS {name}")
except Exception:
failures += 1
print(f"FAIL {name}")
traceback.print_exc()
finally:
try:
next(restore)
except StopIteration:
pass
sys.exit(1 if failures else 0)