228 lines
8.7 KiB
Python
228 lines
8.7 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
import pytest
|
|
|
|
from src.services.ai_agent_interaction_learning_proof import (
|
|
load_latest_ai_agent_interaction_learning_proof,
|
|
)
|
|
|
|
|
|
def test_load_latest_ai_agent_interaction_learning_proof_reads_committed_snapshot():
|
|
data = load_latest_ai_agent_interaction_learning_proof()
|
|
|
|
assert data["schema_version"] == "ai_agent_interaction_learning_proof_v1"
|
|
assert data["program_status"]["overall_completion_percent"] == 55
|
|
assert data["program_status"]["current_task_id"] == "P2-403B"
|
|
assert data["program_status"]["next_task_id"] == "P2-403C"
|
|
assert data["program_status"]["read_only_mode"] is True
|
|
assert data["program_status"]["runtime_authority"] == "proof_surface_only_no_live_worker"
|
|
assert data["live_truth"]["runtime_loop_enabled"] is False
|
|
assert data["live_truth"]["active_live_agent_sessions"] == 0
|
|
assert data["live_truth"]["live_learning_writes_24h"] == 0
|
|
assert data["frontend_redaction"]["operator_conversation_display_allowed"] is False
|
|
assert data["frontend_redaction"]["agent_private_reasoning_display_allowed"] is False
|
|
assert data["frontend_redaction"]["raw_prompt_display_allowed"] is False
|
|
assert data["approval_boundaries"]["runtime_worker_allowed"] is False
|
|
assert data["approval_boundaries"]["telegram_direct_send_allowed"] is False
|
|
assert data["rollups"]["proof_level_count"] == len(data["proof_ladder"]) == 7
|
|
assert data["rollups"]["signal_count"] == len(data["proof_signals"]) == 9
|
|
assert data["rollups"]["operator_surface_count"] == len(data["operator_surfaces"]) == 5
|
|
assert data["rollups"]["runtime_gate_count"] == len(data["runtime_gates"]) == 5
|
|
assert data["rollups"]["live_signal_count"] == 0
|
|
assert set(data["rollups"]["live_pending_level_ids"]) == {
|
|
"message_bus_receipts",
|
|
"handoff_receipts",
|
|
"learning_growth",
|
|
"telegram_receipts",
|
|
}
|
|
assert {lane["agent_id"] for lane in data["agent_lanes"]} == {
|
|
"openclaw",
|
|
"hermes",
|
|
"nemotron",
|
|
}
|
|
|
|
|
|
def test_load_latest_ai_agent_interaction_learning_proof_rejects_runtime_worker(tmp_path):
|
|
snapshot = _snapshot()
|
|
snapshot["approval_boundaries"]["runtime_worker_allowed"] = True
|
|
(tmp_path / "ai_agent_interaction_learning_proof_2026-06-11.json").write_text(
|
|
json.dumps(snapshot),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="approval boundaries"):
|
|
load_latest_ai_agent_interaction_learning_proof(tmp_path)
|
|
|
|
|
|
def test_load_latest_ai_agent_interaction_learning_proof_rejects_live_truth(tmp_path):
|
|
snapshot = _snapshot()
|
|
snapshot["live_truth"]["runtime_loop_enabled"] = True
|
|
(tmp_path / "ai_agent_interaction_learning_proof_2026-06-11.json").write_text(
|
|
json.dumps(snapshot),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="live truth flags"):
|
|
load_latest_ai_agent_interaction_learning_proof(tmp_path)
|
|
|
|
|
|
def test_load_latest_ai_agent_interaction_learning_proof_rejects_rollup_mismatch(tmp_path):
|
|
snapshot = _snapshot()
|
|
snapshot["rollups"]["signal_count"] = 99
|
|
(tmp_path / "ai_agent_interaction_learning_proof_2026-06-11.json").write_text(
|
|
json.dumps(snapshot),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="rollup counts"):
|
|
load_latest_ai_agent_interaction_learning_proof(tmp_path)
|
|
|
|
|
|
def test_load_latest_ai_agent_interaction_learning_proof_rejects_transcript_display(tmp_path):
|
|
snapshot = _snapshot()
|
|
snapshot["frontend_redaction"]["operator_conversation_display_allowed"] = True
|
|
(tmp_path / "ai_agent_interaction_learning_proof_2026-06-11.json").write_text(
|
|
json.dumps(snapshot),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="operator conversation display"):
|
|
load_latest_ai_agent_interaction_learning_proof(tmp_path)
|
|
|
|
|
|
def _snapshot() -> dict:
|
|
return {
|
|
"schema_version": "ai_agent_interaction_learning_proof_v1",
|
|
"generated_at": "2026-06-11T23:20:00+08:00",
|
|
"program_status": {
|
|
"overall_completion_percent": 55,
|
|
"current_priority": "P2",
|
|
"current_task_id": "P2-403B",
|
|
"next_task_id": "P2-403C",
|
|
"read_only_mode": True,
|
|
"runtime_authority": "proof_surface_only_no_live_worker",
|
|
},
|
|
"live_truth": {
|
|
"runtime_loop_enabled": False,
|
|
"live_agent_session_readback_enabled": False,
|
|
"redis_consumer_group_enabled": False,
|
|
"telegram_send_enabled": False,
|
|
"learning_writeback_enabled": False,
|
|
"active_live_agent_sessions": 0,
|
|
"live_agent_messages_24h": 0,
|
|
"live_handoffs_24h": 0,
|
|
"live_learning_writes_24h": 0,
|
|
"telegram_digest_receipts_24h": 0,
|
|
},
|
|
"proof_ladder": [
|
|
_proof_level("contract_surface", "contract_ready"),
|
|
_proof_level("proof_dashboard", "proof_surface_ready"),
|
|
_proof_level("live_read_model", "contract_ready"),
|
|
],
|
|
"agent_lanes": [
|
|
_agent_lane("openclaw"),
|
|
_agent_lane("hermes"),
|
|
_agent_lane("nemotron"),
|
|
],
|
|
"proof_signals": [
|
|
{
|
|
"signal_id": "agent_heartbeat",
|
|
"display_name": "Agent 心跳",
|
|
"category": "heartbeat",
|
|
"source_of_truth": "agent_sessions.last_seen_at",
|
|
"visible_surface": "governance",
|
|
"current_state": "live_pending",
|
|
"operator_interpretation": "測試。",
|
|
"next_gate": "P2-403B",
|
|
}
|
|
],
|
|
"operator_surfaces": [
|
|
{
|
|
"surface_id": "governance_agent_proof_panel",
|
|
"display_name": "治理頁 Agent 證據面板",
|
|
"route_or_channel": "/zh-TW/governance?tab=automation-inventory",
|
|
"operator_feel": "測試。",
|
|
"redaction_policy": "只顯示摘要。",
|
|
"current_state": "implemented_read_only",
|
|
}
|
|
],
|
|
"runtime_gates": [
|
|
{
|
|
"gate_id": "agent_session_read_model_gate",
|
|
"display_name": "AgentSession 唯讀 read model",
|
|
"status": "approval_required",
|
|
"required_before_green": "測試。",
|
|
"next_task_id": "P2-403B",
|
|
}
|
|
],
|
|
"learning_memory_stack": [
|
|
{
|
|
"layer_id": "hot_agent_session_memory",
|
|
"display_name": "Hot",
|
|
"storage_or_service": "agent_sessions",
|
|
"visible_growth_signal": "心跳",
|
|
"current_state": "pending",
|
|
}
|
|
],
|
|
"telegram_receipt_contract": {
|
|
"direct_send_allowed": False,
|
|
"gateway_queue_write_allowed": False,
|
|
"receipt_visible_to_operator": True,
|
|
},
|
|
"frontend_redaction": {
|
|
"operator_conversation_display_allowed": False,
|
|
"agent_private_reasoning_display_allowed": False,
|
|
"raw_prompt_display_allowed": False,
|
|
},
|
|
"approval_boundaries": {
|
|
"runtime_worker_allowed": False,
|
|
"db_migration_allowed": False,
|
|
"redis_consumer_group_allowed": False,
|
|
"telegram_direct_send_allowed": False,
|
|
"conversation_transcript_display_allowed": False,
|
|
"agent_private_reasoning_display_allowed": False,
|
|
"secret_plaintext_allowed": False,
|
|
"autonomous_self_modify_allowed": False,
|
|
},
|
|
"rollups": {
|
|
"proof_level_count": 3,
|
|
"contract_ready_level_count": 3,
|
|
"live_pending_level_ids": [],
|
|
"signal_count": 1,
|
|
"live_signal_count": 0,
|
|
"operator_surface_count": 1,
|
|
"runtime_gate_count": 1,
|
|
"blocked_gate_ids": ["agent_session_read_model_gate"],
|
|
"active_live_agent_sessions": 0,
|
|
"live_agent_messages_24h": 0,
|
|
"live_handoffs_24h": 0,
|
|
"live_learning_writes_24h": 0,
|
|
"telegram_digest_receipts_24h": 0,
|
|
},
|
|
}
|
|
|
|
|
|
def _proof_level(level_id: str, status: str) -> dict:
|
|
return {
|
|
"level_id": level_id,
|
|
"display_name": level_id,
|
|
"status": status,
|
|
"completion_percent": 100 if status != "live_pending" else 0,
|
|
"operator_meaning": "測試。",
|
|
"source_of_truth": "test",
|
|
"next_gate": "test",
|
|
}
|
|
|
|
|
|
def _agent_lane(agent_id: str) -> dict:
|
|
return {
|
|
"agent_id": agent_id,
|
|
"display_name": agent_id,
|
|
"primary_role": "測試。",
|
|
"current_visible_state": "contract_visible_live_runtime_pending",
|
|
"visible_signals": ["agent_heartbeat"],
|
|
"growth_metric": "測試。",
|
|
}
|