feat(ai): 新增 P2-406B receipt owner review
Some checks failed
Code Review / ai-code-review (push) Successful in 16s
CD Pipeline / tests (push) Successful in 1m52s
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-18 14:02:06 +08:00
parent a29896839e
commit 649552a130
13 changed files with 2118 additions and 9 deletions

View File

@@ -0,0 +1,314 @@
from __future__ import annotations
import json
import pytest
from src.services.ai_agent_receipt_readback_owner_review import (
load_latest_ai_agent_receipt_readback_owner_review,
)
def test_load_latest_ai_agent_receipt_readback_owner_review_reads_newest_file(tmp_path):
older = _snapshot(generated_at="2026-06-17T00:00:00+08:00")
newer = _snapshot(generated_at="2026-06-18T00:00:00+08:00")
(tmp_path / "ai_agent_receipt_readback_owner_review_2026-06-17.json").write_text(
json.dumps(older),
encoding="utf-8",
)
(tmp_path / "ai_agent_receipt_readback_owner_review_2026-06-18.json").write_text(
json.dumps(newer),
encoding="utf-8",
)
loaded = load_latest_ai_agent_receipt_readback_owner_review(tmp_path)
assert loaded["generated_at"] == "2026-06-18T00:00:00+08:00"
assert loaded["program_status"]["current_task_id"] == "P2-406B"
assert loaded["program_status"]["next_task_id"] == "P2-407"
assert loaded["receipt_readback_plan"]["receipt_owner"] == "hermes"
assert loaded["receipt_readback_plan"]["arbiter"] == "openclaw"
assert loaded["receipt_readback_plan"]["replay_owner"] == "nemotron"
assert loaded["activation_boundaries"]["telegram_send_enabled"] is False
assert loaded["activation_boundaries"]["gateway_queue_write_enabled"] is False
def test_ai_agent_receipt_readback_owner_review_requires_read_only_mode(tmp_path):
snapshot = _snapshot()
snapshot["program_status"]["read_only_mode"] = False
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="read_only_mode"):
load_latest_ai_agent_receipt_readback_owner_review(tmp_path)
def test_ai_agent_receipt_readback_owner_review_blocks_telegram_send(tmp_path):
snapshot = _snapshot()
snapshot["activation_boundaries"]["telegram_send_enabled"] = True
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="activation boundaries"):
load_latest_ai_agent_receipt_readback_owner_review(tmp_path)
def test_ai_agent_receipt_readback_owner_review_blocks_bot_api_call(tmp_path):
snapshot = _snapshot()
snapshot["telegram_policy"]["direct_bot_api_allowed"] = True
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="telegram_policy"):
load_latest_ai_agent_receipt_readback_owner_review(tmp_path)
def test_ai_agent_receipt_readback_owner_review_requires_rollup_consistency(tmp_path):
snapshot = _snapshot()
snapshot["rollups"]["owner_review_gate_count"] = 99
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="rollup counts"):
load_latest_ai_agent_receipt_readback_owner_review(tmp_path)
def test_ai_agent_receipt_readback_owner_review_requires_gate_evidence(tmp_path):
snapshot = _snapshot()
snapshot["owner_review_gates"][0]["evidence_refs"] = []
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="evidence_refs"):
load_latest_ai_agent_receipt_readback_owner_review(tmp_path)
def test_ai_agent_receipt_readback_owner_review_rejects_private_terms(tmp_path):
snapshot = _snapshot()
snapshot["owner_review_gates"][0]["next_action"] = "不要顯示工作視窗內容"
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="forbidden public terms"):
load_latest_ai_agent_receipt_readback_owner_review(tmp_path)
def test_ai_agent_receipt_readback_owner_review_fails_when_missing(tmp_path):
with pytest.raises(FileNotFoundError):
load_latest_ai_agent_receipt_readback_owner_review(tmp_path)
def _write_snapshot(tmp_path, payload: dict) -> None:
(tmp_path / "ai_agent_receipt_readback_owner_review_2026-06-18.json").write_text(
json.dumps(payload),
encoding="utf-8",
)
def _snapshot(*, generated_at: str = "2026-06-18T00:00:00+08:00") -> dict:
boundaries = {
"owner_review_required_before_canary": True,
"read_only_review_allowed": True,
"scheduler_enabled": False,
"gateway_queue_write_enabled": False,
"telegram_send_enabled": False,
"bot_api_call_enabled": False,
"delivery_receipt_write_enabled": False,
"report_receipt_write_enabled": False,
"receipt_production_write_enabled": False,
"ai_analysis_run_enabled": False,
"medium_low_auto_execution_enabled": False,
"production_optimization_write_enabled": False,
"production_write_enabled": False,
"secret_read_enabled": False,
"paid_api_enabled": False,
"host_write_enabled": False,
"kubectl_action_enabled": False,
"destructive_operation_enabled": False,
"external_lookup_enabled": False,
}
return {
"schema_version": "ai_agent_receipt_readback_owner_review_v1",
"generated_at": generated_at,
"program_status": {
"overall_completion_percent": 100,
"current_priority": "P2",
"current_task_id": "P2-406B",
"next_task_id": "P2-407",
"read_only_mode": True,
"runtime_authority": "receipt_readback_owner_review_only_no_send_or_write",
"status_note": "只讀 owner review。",
},
"source_refs": ["docs/evaluations/example.json"],
"source_readbacks": [
_source("status", "ai_agent_report_status_board_v1", "openclaw"),
_source("delivery", "ai_agent_report_live_delivery_approval_package_v1", "hermes"),
_source("receipt", "ai_agent_telegram_receipt_approval_package_v1", "hermes"),
_source("professional", "ai_agent_professional_task_expansion_v1", "nemotron"),
_source("drift", "dependency_supply_chain_drift_monitor_v1", "openclaw"),
_source("truth", "ai_agent_report_truth_actionability_review_v1", "openclaw"),
],
"rollups": {
"source_readback_count": 6,
"report_cadence_count": 3,
"owner_review_gate_count": 6,
"receipt_readback_check_count": 8,
"drift_candidate_count": 9,
"report_truth_blocker_count": 5,
"approval_required_count": 6,
"blocked_runtime_action_count": 17,
"live_write_count": 0,
"telegram_send_count": 0,
"gateway_queue_write_count": 0,
"bot_api_call_count": 0,
"production_write_count": 0,
"secret_read_count": 0,
"paid_api_call_count": 0,
"host_write_count": 0,
"kubectl_action_count": 0,
},
"report_owner_review": {
"cadences": [
_cadence("daily", "hermes"),
_cadence("weekly", "openclaw"),
_cadence("monthly", "nemotron"),
]
},
"receipt_readback_plan": {
"canonical_room": "AwoooI SRE 戰情室",
"canonical_room_env": "SRE_GROUP_CHAT_ID",
"gateway_owner": "telegram_ops",
"arbiter": "openclaw",
"receipt_owner": "hermes",
"replay_owner": "nemotron",
"dry_run_receipt_only": True,
"owner_review_required_before_canary": True,
"canary_send_approved": False,
"receipt_production_write_enabled": False,
"readback_checks": [_check(index) for index in range(8)],
},
"owner_review_gates": [
_gate("daily_report_receipt_owner_review", "hermes"),
_gate("weekly_report_truth_owner_review", "openclaw"),
_gate("monthly_report_owner_review", "nemotron"),
_gate("telegram_canary_receipt_owner_review", "hermes"),
_gate("supply_chain_drift_owner_review", "openclaw"),
_gate("report_truth_data_chain_owner_review", "openclaw"),
],
"drift_monitor_owner_review": {
"source_task_id": "P2-004",
"drift_candidate_count": 9,
"action_required_candidate_count": 9,
"stale_source_snapshot_count": 5,
"external_lookup_allowed": False,
"package_upgrade_allowed": False,
"owner_actions": ["prepare_packet"],
},
"report_truth_owner_review": {
"source_task_id": "P2-403J",
"all_zero_weekly_report_is_actionable_anomaly": True,
"all_zero_weekly_report_confidence": "low_trust_actionable_anomaly",
"zero_signal_finding_count": 5,
"critical_finding_count": 1,
"high_finding_count": 3,
"telegram_report_send_allowed": False,
"cronjob_change_allowed": False,
"freshness_gate_implemented": False,
"source_confidence_gate_implemented": False,
"actionability_score_implemented": False,
"owner_actions": ["keep_anomaly_visible"],
},
"activation_boundaries": boundaries,
"telegram_policy": {
"status": "owner_review_only_no_send",
"canonical_room": "AwoooI SRE 戰情室",
"canonical_room_env": "SRE_GROUP_CHAT_ID",
"gateway_queue_write_allowed": False,
"direct_bot_api_allowed": False,
"telegram_send_allowed": False,
"receipt_write_allowed": False,
},
"agent_roles": [
_role("openclaw"),
_role("hermes"),
_role("nemotron"),
],
"operator_decision": {
"status": "owner_review_required_before_canary",
"approval_packet_required": True,
"rollback_plan_required": True,
"mute_plan_required": True,
"required_fields": ["owner_identity"],
"stop_conditions": ["telegram_send_count 非 0"],
"next_decision_point": "P2-407",
},
"next_actions": [
{
"task_id": "P2-407",
"priority": "P2",
"summary": "下一步",
"gate": "no write",
}
],
}
def _source(readback_id: str, schema: str, owner: str) -> dict:
return {
"readback_id": readback_id,
"source_schema_version": schema,
"source_ref": f"docs/evaluations/{readback_id}.json",
"endpoint": f"GET /api/v1/agents/{readback_id}",
"owner_agent": owner,
"status": "readback_ready",
"evidence_status": "ready",
"key_readback": "zero live write",
"next_action": "owner review",
}
def _cadence(cadence_id: str, owner: str) -> dict:
return {
"cadence_id": cadence_id,
"display_name": cadence_id,
"owner_agent": owner,
"completion_percent": 100,
"delivery_state": "draft_only",
"source_confidence": "visible",
"live_delivery_count": 0,
"review_status": "owner_review_required_before_send",
"next_gate": f"{cadence_id}_gate",
}
def _check(index: int) -> dict:
return {
"check_id": f"check_{index}",
"owner_agent": "hermes",
"status": "ready_no_send",
"evidence_refs": ["GET /api/v1/agents/example"],
"blocked_runtime_action": "telegram_send",
}
def _gate(gate_id: str, owner: str) -> dict:
return {
"gate_id": gate_id,
"title": gate_id,
"owner_agent": owner,
"risk_tier": "high",
"status": "owner_review_required",
"approval_required": True,
"required_owner_fields": ["owner_identity"],
"acceptance_checks": ["check"],
"rejection_reasons": ["missing owner"],
"blocked_runtime_actions": ["telegram_send_enabled"],
"evidence_refs": ["GET /api/v1/agents/example"],
"next_action": "owner review",
}
def _role(agent_id: str) -> dict:
return {
"agent_id": agent_id,
"role": "role",
"specialty": "specialty",
"autonomy_level": "L2",
"approval_gate": "human",
"runtime_write_allowed": False,
"outputs": ["packet"],
}

View File

@@ -0,0 +1,55 @@
from __future__ import annotations
from fastapi import FastAPI
from fastapi.testclient import TestClient
from src.api.v1.agents import router
def test_ai_agent_receipt_readback_owner_review_endpoint_returns_committed_snapshot():
app = FastAPI()
app.include_router(router, prefix="/api/v1")
client = TestClient(app)
response = client.get("/api/v1/agents/agent-receipt-readback-owner-review")
assert response.status_code == 200
data = response.json()
assert data["schema_version"] == "ai_agent_receipt_readback_owner_review_v1"
assert data["program_status"]["current_task_id"] == "P2-406B"
assert data["program_status"]["next_task_id"] == "P2-407"
assert data["program_status"]["read_only_mode"] is True
assert data["rollups"]["source_readback_count"] == len(data["source_readbacks"]) == 6
assert data["rollups"]["report_cadence_count"] == 3
assert data["rollups"]["owner_review_gate_count"] == len(data["owner_review_gates"]) == 6
assert data["rollups"]["receipt_readback_check_count"] == 8
assert data["rollups"]["drift_candidate_count"] == 9
assert data["rollups"]["report_truth_blocker_count"] == 5
assert data["rollups"]["approval_required_count"] == 6
assert data["rollups"]["live_write_count"] == 0
assert data["rollups"]["telegram_send_count"] == 0
assert data["rollups"]["gateway_queue_write_count"] == 0
assert data["rollups"]["bot_api_call_count"] == 0
assert data["rollups"]["production_write_count"] == 0
assert data["rollups"]["secret_read_count"] == 0
assert data["rollups"]["paid_api_call_count"] == 0
assert data["rollups"]["host_write_count"] == 0
assert data["rollups"]["kubectl_action_count"] == 0
assert data["receipt_readback_plan"]["canonical_room"] == "AwoooI SRE 戰情室"
assert data["receipt_readback_plan"]["canonical_room_env"] == "SRE_GROUP_CHAT_ID"
assert data["receipt_readback_plan"]["arbiter"] == "openclaw"
assert data["receipt_readback_plan"]["receipt_owner"] == "hermes"
assert data["receipt_readback_plan"]["replay_owner"] == "nemotron"
assert data["receipt_readback_plan"]["canary_send_approved"] is False
assert data["activation_boundaries"]["gateway_queue_write_enabled"] is False
assert data["activation_boundaries"]["telegram_send_enabled"] is False
assert data["activation_boundaries"]["bot_api_call_enabled"] is False
assert data["activation_boundaries"]["receipt_production_write_enabled"] is False
assert data["activation_boundaries"]["production_write_enabled"] is False
assert data["activation_boundaries"]["secret_read_enabled"] is False
assert data["activation_boundaries"]["paid_api_enabled"] is False
assert data["activation_boundaries"]["host_write_enabled"] is False
assert data["activation_boundaries"]["kubectl_action_enabled"] is False
assert data["telegram_policy"]["telegram_send_allowed"] is False
assert data["telegram_policy"]["gateway_queue_write_allowed"] is False
assert data["telegram_policy"]["direct_bot_api_allowed"] is False