Files
awoooi/apps/api/src/api/v1/agents.py
Your Name aac2d95847
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 4s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 40s
CD Pipeline / build-and-deploy (push) Failing after 2m40s
CD Pipeline / post-deploy-checks (push) Has been skipped
feat(api): validate harbor registry recovery receipts
2026-06-30 20:11:17 +08:00

4993 lines
223 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Agent Teams API - Phase 9.5 多專家協作系統
==========================================
Endpoints:
- POST /api/v1/agents/analyze - 觸發 Agent Teams 分析
- GET /api/v1/agents/status/{task_id} - 查詢分析狀態
- GET /api/v1/agents/result/{task_id} - 取得分析結果
- GET /api/v1/agents/stream/{task_id} - SSE 串流進度
Phase 9.4-9.5 核心功能:
1. ConsensusEngine 整合多專家意見
2. BackgroundTasks 執行長時間分析
3. Redis Working Memory 儲存結果
4. SSE 推送即時進度
Phase 17 技術債修復 (2026-03-26):
- Router 層不再直接存取 Redis
- 所有業務邏輯封裝至 AgentService
- 符合 leWOOOgo 積木化原則
統帥鐵律:
- 所有分析任務必須可追蹤 (task_id)
- 超過 60 秒的分析必須用 BackgroundTasks
- 結果必須存入 Redis (7 天 TTL)
"""
import asyncio
import json
from typing import Any
from fastapi import APIRouter, BackgroundTasks, HTTPException, status
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
from src.core.logging import get_logger
from src.core.sse import get_publisher
from src.services.agent_market_governance_snapshot import (
load_latest_agent_market_governance_snapshot,
)
from src.services.agent_service import (
AgentService,
TaskState,
get_agent_service,
)
from src.services.ai_agent_12_agent_war_room import (
load_latest_ai_agent_12_agent_war_room,
)
from src.services.ai_agent_action_audit_ledger import (
load_latest_ai_agent_action_audit_ledger,
)
from src.services.ai_agent_action_owner_acceptance_event_bus import (
load_latest_ai_agent_action_owner_acceptance_event_bus,
)
from src.services.ai_agent_automation_backlog_snapshot import (
load_latest_ai_agent_automation_backlog_snapshot,
)
from src.services.ai_agent_automation_inventory_snapshot import (
load_latest_ai_agent_automation_inventory_snapshot,
)
from src.services.ai_agent_autonomous_runtime_control import (
build_ai_agent_autonomous_runtime_control_with_live_readback,
redact_autonomous_runtime_control_public_terms,
)
from src.services.ai_agent_candidate_operation_dry_run_evidence import (
load_latest_ai_agent_candidate_operation_dry_run_evidence,
)
from src.services.ai_agent_canonical_runtime_readback_owner_acceptance import (
load_latest_ai_agent_canonical_runtime_readback_owner_acceptance,
)
from src.services.ai_agent_communication_learning_contract import (
load_latest_ai_agent_communication_learning_contract,
)
from src.services.ai_agent_controlled_executor_handoff import (
load_latest_ai_agent_controlled_executor_handoff,
)
from src.services.ai_agent_critic_reviewer_result_capture import (
load_latest_ai_agent_critic_reviewer_result_capture,
)
from src.services.ai_agent_deployment_layout import (
load_latest_ai_agent_deployment_layout,
)
from src.services.ai_agent_failure_receipt_no_send_replay import (
load_latest_ai_agent_failure_receipt_no_send_replay,
)
from src.services.ai_agent_gitea_pr_draft_lane import (
load_latest_ai_agent_gitea_pr_draft_lane,
)
from src.services.ai_agent_high_risk_owner_review_queue import (
load_latest_ai_agent_high_risk_owner_review_queue,
)
from src.services.ai_agent_host_stateful_version_inventory import (
load_latest_ai_agent_host_stateful_version_inventory,
)
from src.services.ai_agent_interaction_learning_proof import (
load_latest_ai_agent_interaction_learning_proof,
)
from src.services.ai_agent_learning_writeback_approval_package import (
load_latest_ai_agent_learning_writeback_approval_package,
)
from src.services.ai_agent_live_read_model_gate import (
load_latest_ai_agent_live_read_model_gate,
)
from src.services.ai_agent_log_controlled_writeback_consumer_readback import (
load_latest_ai_agent_log_controlled_writeback_consumer_readback,
)
from src.services.ai_agent_log_controlled_writeback_dispatch import (
dispatch_latest_ai_agent_log_controlled_writeback,
)
from src.services.ai_agent_log_controlled_writeback_executor_readback import (
load_latest_ai_agent_log_controlled_writeback_executor_readback,
)
from src.services.ai_agent_log_controlled_writeback_plan_readback import (
load_latest_ai_agent_log_controlled_writeback_plan_readback,
)
from src.services.ai_agent_log_feedback_receipt_dry_run import (
load_latest_ai_agent_log_feedback_receipt_dry_run,
)
from src.services.ai_agent_log_intelligence_integration_readback import (
load_latest_ai_agent_log_intelligence_integration_readback,
)
from src.services.ai_agent_log_post_write_verifier_dry_run import (
load_latest_ai_agent_log_post_write_verifier_dry_run,
)
from src.services.ai_agent_low_medium_risk_whitelist import (
load_latest_ai_agent_low_medium_risk_whitelist,
)
from src.services.ai_agent_market_radar_readback import (
load_latest_ai_agent_market_radar_readback,
)
from src.services.ai_agent_matched_playbook_learning_gap import (
load_latest_ai_agent_matched_playbook_learning_gap,
)
from src.services.ai_agent_operation_permission_model import (
load_latest_ai_agent_operation_permission_model,
)
from src.services.ai_agent_owner_approved_fixture_dry_run import (
load_latest_ai_agent_owner_approved_fixture_dry_run,
)
from src.services.ai_agent_owner_approved_fixture_promotion_gate import (
load_latest_ai_agent_owner_approved_fixture_promotion_gate,
)
from src.services.ai_agent_owner_approved_learning_dry_run import (
load_latest_ai_agent_owner_approved_learning_dry_run,
)
from src.services.ai_agent_owner_approved_result_capture_dry_run import (
load_latest_ai_agent_owner_approved_result_capture_dry_run,
)
from src.services.ai_agent_owner_approved_result_capture_promotion_dry_run import (
load_latest_ai_agent_owner_approved_result_capture_promotion_dry_run,
)
from src.services.ai_agent_owner_approved_result_capture_readback import (
load_latest_ai_agent_owner_approved_result_capture_readback,
)
from src.services.ai_agent_post_write_verifier_package import (
load_latest_ai_agent_post_write_verifier_package,
)
from src.services.ai_agent_proactive_operations_contract import (
load_latest_ai_agent_proactive_operations_contract,
)
from src.services.ai_agent_professional_task_expansion import (
load_latest_ai_agent_professional_task_expansion,
)
from src.services.ai_agent_receipt_readback_owner_review import (
load_latest_ai_agent_receipt_readback_owner_review,
)
from src.services.ai_agent_redis_dry_run_gate import (
load_latest_ai_agent_redis_dry_run_gate,
)
from src.services.ai_agent_report_automation_review import (
load_latest_ai_agent_report_automation_review,
)
from src.services.ai_agent_report_live_delivery_approval_package import (
load_latest_ai_agent_report_live_delivery_approval_package,
)
from src.services.ai_agent_report_no_write_analysis_runtime import (
load_latest_ai_agent_report_no_write_analysis_runtime,
)
from src.services.ai_agent_report_runtime_dry_run import (
load_latest_ai_agent_report_runtime_dry_run,
)
from src.services.ai_agent_report_runtime_fixture_readback import (
load_latest_ai_agent_report_runtime_fixture_readback,
)
from src.services.ai_agent_report_runtime_readiness import (
load_latest_ai_agent_report_runtime_readiness,
)
from src.services.ai_agent_report_source_health import (
build_ai_agent_report_source_health,
)
from src.services.ai_agent_report_status_board import (
load_latest_ai_agent_report_status_board,
)
from src.services.ai_agent_report_truth_actionability_review import (
load_latest_ai_agent_report_truth_actionability_review,
)
from src.services.ai_agent_result_capture_final_release_candidate_readback import (
load_latest_ai_agent_result_capture_final_release_candidate_readback,
)
from src.services.ai_agent_result_capture_no_write_readback import (
load_latest_ai_agent_result_capture_no_write_readback,
)
from src.services.ai_agent_result_capture_owner_acceptance_maintenance_gate import (
load_latest_ai_agent_result_capture_owner_acceptance_maintenance_gate,
)
from src.services.ai_agent_result_capture_owner_acceptance_readback_preflight_hold import (
load_latest_ai_agent_result_capture_owner_acceptance_readback_preflight_hold,
)
from src.services.ai_agent_result_capture_owner_approved_execution_rehearsal import (
load_latest_ai_agent_result_capture_owner_approved_execution_rehearsal,
)
from src.services.ai_agent_result_capture_owner_approved_preflight_release_package import (
load_latest_ai_agent_result_capture_owner_approved_preflight_release_package,
)
from src.services.ai_agent_result_capture_owner_approved_release_readiness_readback import (
load_latest_ai_agent_result_capture_owner_approved_release_readiness_readback,
)
from src.services.ai_agent_result_capture_owner_promotion_review import (
load_latest_ai_agent_result_capture_owner_promotion_review,
)
from src.services.ai_agent_result_capture_owner_release_approval_gate import (
load_latest_ai_agent_result_capture_owner_release_approval_gate,
)
from src.services.ai_agent_result_capture_post_release_verifier_rollback_gate import (
load_latest_ai_agent_result_capture_post_release_verifier_rollback_gate,
)
from src.services.ai_agent_result_capture_promotion_approval_gate import (
load_latest_ai_agent_result_capture_promotion_approval_gate,
)
from src.services.ai_agent_result_capture_release_authorization_hold import (
load_latest_ai_agent_result_capture_release_authorization_hold,
)
from src.services.ai_agent_result_capture_release_authorization_readback_gate import (
load_latest_ai_agent_result_capture_release_authorization_readback_gate,
)
from src.services.ai_agent_result_capture_release_decision_hold import (
load_latest_ai_agent_result_capture_release_decision_hold,
)
from src.services.ai_agent_result_capture_release_decision_input_prep import (
load_latest_ai_agent_result_capture_release_decision_input_prep,
)
from src.services.ai_agent_result_capture_release_decision_next_handoff import (
load_latest_ai_agent_result_capture_release_decision_next_handoff,
)
from src.services.ai_agent_result_capture_release_decision_owner_response_acceptance_gate import (
load_latest_ai_agent_result_capture_release_decision_owner_response_acceptance_gate,
)
from src.services.ai_agent_result_capture_release_decision_owner_response_preflight import (
load_latest_ai_agent_result_capture_release_decision_owner_response_preflight,
)
from src.services.ai_agent_result_capture_release_decision_owner_response_readback import (
load_latest_ai_agent_result_capture_release_decision_owner_response_readback,
)
from src.services.ai_agent_result_capture_release_decision_readback import (
load_latest_ai_agent_result_capture_release_decision_readback,
)
from src.services.ai_agent_result_capture_release_verifier_owner_review_packet import (
load_latest_ai_agent_result_capture_release_verifier_owner_review_packet,
)
from src.services.ai_agent_result_capture_release_verifier_preflight_gate import (
load_latest_ai_agent_result_capture_release_verifier_preflight_gate,
)
from src.services.ai_agent_result_capture_write_gate_review import (
load_latest_ai_agent_result_capture_write_gate_review,
)
from src.services.ai_agent_result_capture_writer_dry_run_fixture import (
load_latest_ai_agent_result_capture_writer_dry_run_fixture,
)
from src.services.ai_agent_result_capture_writer_dry_run_readback import (
load_latest_ai_agent_result_capture_writer_dry_run_readback,
)
from src.services.ai_agent_result_capture_writer_implementation_review import (
load_latest_ai_agent_result_capture_writer_implementation_review,
)
from src.services.ai_agent_reviewer_queue_no_write_readback import (
load_latest_ai_agent_reviewer_queue_no_write_readback,
)
from src.services.ai_agent_runtime_readback_approval_package import (
load_latest_ai_agent_runtime_readback_approval_package,
)
from src.services.ai_agent_runtime_readback_fixture_approval import (
load_latest_ai_agent_runtime_readback_fixture_approval,
)
from src.services.ai_agent_runtime_readback_implementation_review import (
load_latest_ai_agent_runtime_readback_implementation_review,
)
from src.services.ai_agent_runtime_readback_promotion_gate import (
load_latest_ai_agent_runtime_readback_promotion_gate,
)
from src.services.ai_agent_runtime_verifier_evidence_review import (
load_latest_ai_agent_runtime_verifier_evidence_review,
)
from src.services.ai_agent_runtime_worker_shadow_gate import (
load_latest_ai_agent_runtime_worker_shadow_gate,
)
from src.services.ai_agent_runtime_write_gate_review import (
load_latest_ai_agent_runtime_write_gate_review,
)
from src.services.ai_agent_task_result_audit_trail import (
load_latest_ai_agent_task_result_audit_trail,
)
from src.services.ai_agent_telegram_action_required_digest_policy import (
load_latest_ai_agent_telegram_action_required_digest_policy,
)
from src.services.ai_agent_telegram_receipt_approval_package import (
load_latest_ai_agent_telegram_receipt_approval_package,
)
from src.services.ai_agent_tool_adoption_approval_package import (
load_latest_ai_agent_tool_adoption_approval_package,
)
from src.services.ai_agent_version_freshness_snapshot import (
load_latest_ai_agent_version_freshness_snapshot,
)
from src.services.ai_agent_version_lifecycle_update_proposal import (
load_latest_ai_agent_version_lifecycle_update_proposal,
)
from src.services.ai_provider_route_matrix import (
load_latest_ai_provider_route_matrix,
)
from src.services.ai_technology_radar_readback import (
load_latest_ai_technology_radar_readback,
)
from src.services.ai_technology_report_cadence_readback import (
load_latest_ai_technology_report_cadence_readback,
)
from src.services.awoooi_gitea_onboarding_warning_step_runtime_enablement_gate import (
load_latest_awoooi_gitea_onboarding_warning_step_runtime_enablement_gate,
)
from src.services.awoooi_gitea_onboarding_warning_step_template_copy_apply_gate import (
load_latest_awoooi_gitea_onboarding_warning_step_template_copy_apply_gate,
)
from src.services.awoooi_gitea_onboarding_warning_step_template_copy_execution_plan import (
load_latest_awoooi_gitea_onboarding_warning_step_template_copy_execution_plan,
)
from src.services.awoooi_gitea_onboarding_warning_step_template_copy_receipt import (
load_latest_awoooi_gitea_onboarding_warning_step_template_copy_receipt,
)
from src.services.awoooi_priority_work_order_readback import (
apply_harbor_registry_controlled_recovery_preflight,
apply_stockplatform_public_api_controlled_recovery_preflight,
apply_stockplatform_public_api_runtime_readback,
load_latest_awoooi_priority_work_order_readback,
)
from src.services.awoooi_status_cleanup_dashboard import (
load_latest_awoooi_status_cleanup_dashboard,
)
from src.services.backup_dr_readiness_matrix import (
load_latest_backup_dr_readiness_matrix,
)
from src.services.backup_dr_target_inventory import (
load_latest_backup_dr_target_inventory,
)
from src.services.backup_notification_policy import (
load_latest_backup_notification_policy,
)
from src.services.backup_restore_drill_approval_package_template import (
load_latest_backup_restore_drill_approval_package_template,
)
from src.services.credential_escrow_evidence_intake_readiness import (
load_latest_credential_escrow_evidence_intake_readiness,
validate_credential_escrow_evidence_owner_response,
validate_credential_escrow_evidence_refs,
)
from src.services.delivery_closure_workbench import (
load_delivery_closure_workbench,
)
from src.services.dependency_drift_check_plan import (
load_latest_dependency_drift_check_plan,
)
from src.services.dependency_risk_policy import (
load_latest_dependency_risk_policy,
)
from src.services.dependency_supply_chain_drift_monitor import (
load_latest_dependency_supply_chain_drift_monitor,
)
from src.services.dependency_upgrade_approval_package_template import (
load_latest_dependency_upgrade_approval_package_template,
)
from src.services.docker_build_surface_inventory import (
load_latest_docker_build_surface_inventory,
)
from src.services.gitea_authenticated_inventory_payload_validation import (
validate_gitea_authenticated_inventory_payload,
)
from src.services.gitea_owner_coverage_attestation_validation import (
validate_gitea_owner_coverage_attestation,
)
from src.services.gitea_private_inventory_closeout_validation import (
validate_gitea_private_inventory_controlled_closeout,
)
from src.services.gitea_private_inventory_p0_scorecard import (
load_latest_gitea_private_inventory_p0_scorecard,
)
from src.services.gitea_workflow_runner_health import (
load_latest_gitea_workflow_runner_health,
)
from src.services.gitea_workflow_runner_owner_attestation_request import (
load_latest_gitea_workflow_runner_owner_attestation_request,
)
from src.services.github_target_private_backup_evidence_gate import (
load_latest_github_target_controlled_execution_preflight,
load_latest_github_target_private_backup_evidence_gate,
preflight_github_target_owner_response_submission,
validate_github_target_safe_credential_evidence_refs,
)
from src.services.harbor_registry_controlled_recovery_preflight import (
load_latest_harbor_registry_controlled_recovery_preflight,
)
from src.services.harbor_registry_controlled_recovery_receipt import (
validate_harbor_registry_controlled_recovery_receipt,
)
from src.services.host_runaway_aiops_loop_readiness import (
load_latest_host_runaway_aiops_loop_readiness,
)
from src.services.javascript_package_inventory import (
load_latest_javascript_package_inventory,
)
from src.services.observability_contract_matrix import (
load_latest_observability_contract_matrix,
)
from src.services.offsite_escrow_readiness_status import (
load_latest_offsite_escrow_readiness_status,
)
from src.services.openclaw_live_ops_scene_state import (
load_openclaw_live_ops_scene_state,
)
from src.services.p0_cicd_baseline_source_readiness import (
load_latest_p0_cicd_baseline_source_readiness,
)
from src.services.package_supply_chain_inventory import (
load_latest_package_supply_chain_inventory,
)
from src.services.product_awoooi_manifest_standard import (
load_latest_product_awoooi_manifest_standard,
)
from src.services.product_code_review_gate import (
load_latest_product_code_review_gate,
)
from src.services.public_redaction import redact_public_lan_topology
from src.services.reboot_auto_recovery_drill_preflight import (
load_latest_reboot_auto_recovery_drill_preflight,
)
from src.services.reboot_auto_recovery_slo_scorecard import (
load_latest_reboot_auto_recovery_slo_scorecard,
)
from src.services.runtime_surface_inventory import (
load_latest_runtime_surface_inventory,
)
from src.services.service_health_failure_notification_policy import (
load_latest_service_health_failure_notification_policy,
)
from src.services.service_health_gap_matrix import (
load_latest_service_health_gap_matrix,
)
from src.services.stockplatform_public_api_controlled_recovery_preflight import (
load_latest_stockplatform_public_api_controlled_recovery_preflight,
)
from src.services.stockplatform_public_api_runtime_readback import (
load_latest_stockplatform_public_api_runtime_readback,
)
router = APIRouter(prefix="/agents", tags=["Agent Teams"])
logger = get_logger("awoooi.agents")
# =============================================================================
# Request/Response Models
# =============================================================================
class AnalyzeRequest(BaseModel):
"""分析請求"""
incident_id: str | None = Field(
None,
description="現有 Incident ID (二選一)"
)
# 或直接提供 Incident 資訊
severity: str | None = Field(
None,
description="事件嚴重度 (P0/P1/P2/P3)"
)
affected_services: list[str] | None = Field(
None,
description="受影響服務列表"
)
alert_names: list[str] | None = Field(
None,
description="告警名稱列表"
)
context: dict[str, Any] | None = Field(
None,
description="額外上下文"
)
class AnalyzeResponse(BaseModel):
"""分析回應"""
task_id: str
status: str
message: str
estimated_seconds: int = 30
class TaskStatusResponse(BaseModel):
"""任務狀態回應"""
task_id: str
state: str
progress: int # 0-100
current_step: str | None = None
agents_completed: int = 0
total_agents: int = 4
started_at: str | None = None
completed_at: str | None = None
error: str | None = None
class TaskResultResponse(BaseModel):
"""任務結果回應"""
task_id: str
state: str
consensus_id: str | None = None
incident_id: str | None = None
consensus_score: float | None = None
recommended_action: str | None = None
recommended_kubectl: str | None = None
risk_level: str | None = None
final_reasoning: str | None = None
opinions: list[dict[str, Any]] | None = None
dissenting_opinions: list[str] | None = None
created_at: str | None = None
# =============================================================================
# Background Task Wrapper
# =============================================================================
async def _run_analysis_task(
service: AgentService,
task_id: str,
incident_id: str,
) -> None:
"""
背景任務包裝器
從 AgentService 取得 Incident 並執行分析
"""
incident = await service.get_incident(incident_id)
if incident is None:
logger.error("background_task_incident_not_found", incident_id=incident_id)
return
await service.run_analysis(task_id, incident)
# =============================================================================
# API Endpoints
# =============================================================================
@router.post(
"/analyze",
response_model=AnalyzeResponse,
summary="觸發 Agent Teams 分析",
description="""
觸發多專家協作分析。
可提供:
- 現有 Incident ID (從 Redis 讀取)
- 或直接提供事件資訊 (severity, affected_services, alert_names)
分析在背景執行,使用 task_id 追蹤進度。
專家團隊:
- SRE Agent: 系統穩定性分析
- Security Agent: 資安風險評估
- Cost Agent: 成本效益分析
- Performance Agent: 效能優化建議
""",
)
async def analyze(
request: AnalyzeRequest,
background_tasks: BackgroundTasks,
) -> AnalyzeResponse:
"""
觸發 Agent Teams 分析
返回 task_id 用於追蹤進度
"""
service = get_agent_service()
# 取得或建立 Incident
if request.incident_id:
# 從 Redis 讀取現有 Incident
incident = await service.get_incident(request.incident_id)
if incident is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Incident not found: {request.incident_id}",
)
elif request.severity and request.affected_services:
# 建立臨時 Incident
incident = service.create_adhoc_incident(
severity=request.severity,
affected_services=request.affected_services,
alert_names=request.alert_names,
)
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Must provide either incident_id or (severity + affected_services)",
)
# 建立任務
task_id = await service.create_analysis_task(incident, trigger="manual")
# 加入背景任務
background_tasks.add_task(
service.run_analysis,
task_id,
incident,
)
logger.info(
"agent_analysis_started",
task_id=task_id,
incident_id=incident.incident_id,
severity=incident.severity.value,
)
return AnalyzeResponse(
task_id=task_id,
status="pending",
message="Agent Teams 分析已啟動",
estimated_seconds=30,
)
@router.get(
"/status/{task_id}",
response_model=TaskStatusResponse,
summary="查詢分析狀態",
description="查詢 Agent Teams 分析任務的目前狀態與進度。",
)
async def get_status(task_id: str) -> TaskStatusResponse:
"""
查詢任務狀態
返回進度百分比與目前步驟
"""
service = get_agent_service()
task_data = await service.get_task_status(task_id)
if task_data is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Task not found: {task_id}",
)
return TaskStatusResponse(
task_id=task_id,
state=task_data.get("state", "unknown"),
progress=task_data.get("progress", 0),
current_step=task_data.get("current_step"),
agents_completed=task_data.get("agents_completed", 0),
total_agents=task_data.get("total_agents", 4),
started_at=task_data.get("started_at"),
completed_at=task_data.get("completed_at"),
error=task_data.get("error"),
)
@router.get(
"/result/{task_id}",
response_model=TaskResultResponse,
summary="取得分析結果",
description="取得 Agent Teams 分析的完整結果,包含所有專家意見與共識決策。",
)
async def get_result(task_id: str) -> TaskResultResponse:
"""
取得分析結果
只有 COMPLETED 狀態才有完整結果
"""
service = get_agent_service()
task_data = await service.get_task_result(task_id)
if task_data is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Task not found: {task_id}",
)
return TaskResultResponse(
task_id=task_id,
state=task_data.get("state", "unknown"),
consensus_id=task_data.get("consensus_id"),
incident_id=task_data.get("incident_id"),
consensus_score=task_data.get("consensus_score"),
recommended_action=task_data.get("recommended_action"),
recommended_kubectl=task_data.get("recommended_kubectl"),
risk_level=task_data.get("risk_level"),
final_reasoning=task_data.get("final_reasoning"),
opinions=task_data.get("opinions"),
dissenting_opinions=task_data.get("dissenting_opinions"),
created_at=task_data.get("completed_at"),
)
@router.get(
"/stream/{task_id}",
summary="SSE 串流進度",
description="透過 Server-Sent Events 即時接收分析進度更新。",
)
async def stream_progress(task_id: str) -> StreamingResponse:
"""
SSE 串流分析進度
客戶端可訂閱此端點接收即時更新
"""
service = get_agent_service()
# 驗證任務存在
task_data = await service.get_task_status(task_id)
if task_data is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Task not found: {task_id}",
)
async def generate():
"""SSE 串流生成器"""
publisher = await get_publisher()
client = await publisher.subscribe(
topics=[f"agent_task:{task_id}"],
metadata={"task_id": task_id},
)
try:
# 發送初始狀態
current_data = await service.get_task_status(task_id)
if current_data:
payload = json.dumps(
{"type": "status", **current_data},
ensure_ascii=False,
)
yield f"data: {payload}\n\n"
# 串流後續更新
async for event_str in publisher.stream(client):
yield event_str
# 檢查是否完成或失敗
current_data = await service.get_task_status(task_id)
if current_data:
final_states = [TaskState.COMPLETED.value, TaskState.FAILED.value]
if current_data.get("state") in final_states:
break
except asyncio.CancelledError:
logger.info("agent_stream_cancelled", task_id=task_id)
raise
finally:
await publisher.unsubscribe(client.id)
return StreamingResponse(
generate(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"X-Accel-Buffering": "no",
},
)
@router.get(
"/market-governance-snapshot",
response_model=dict[str, Any],
summary="取得 AI Agent 市場治理快照",
description=(
"讀取最新已提交的 Agent market governance snapshot"
"此 endpoint 不呼叫外部來源、不批准 SDK/API/replay/shadow/canary/production change。"
),
)
async def get_market_governance_snapshot() -> dict[str, Any]:
"""Return the latest read-only Agent market governance snapshot."""
try:
return await asyncio.to_thread(load_latest_agent_market_governance_snapshot)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("agent_market_governance_snapshot_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Agent market governance snapshot is invalid",
) from exc
@router.get(
"/ai-agent-market-radar-readback",
response_model=dict[str, Any],
summary="取得 AI Agent 市場雷達與近期變更盤點",
description=(
"讀取最新已提交的 AI Agent 市場雷達 readback"
"此端點只呈現近期治理變更、市場主流 Agent 技術來源、候選角色、優先工作清單與封鎖 gate。"
"它不呼叫外部來源、不安裝 SDK、不呼叫付費 API、不跑 replay、不進 shadow/canary、"
"不送 Telegram、不改主機、不修改 workflow、不替換 OpenClaw。"
),
)
async def get_ai_agent_market_radar_readback() -> dict[str, Any]:
"""回傳最新 AI Agent 市場雷達與近期變更盤點只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_market_radar_readback)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_market_radar_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 市場雷達 readback 無效",
) from exc
@router.get(
"/ai-technology-radar-readback",
response_model=dict[str, Any],
summary="取得 AI 技術雷達與滾動更新讀回",
description=(
"讀取最新已提交的 AI 技術雷達 readback"
"此端點只呈現 AI 技術 primary sources、技術領域、審核佇列、Agent 分工與滾動更新 Gate。"
"它不呼叫外部來源、不安裝 SDK、不呼叫付費 API、不切換模型、不送 Telegram、"
"不改主機、不修改 production routing、不替換 OpenClaw。"
),
)
async def get_ai_technology_radar_readback() -> dict[str, Any]:
"""回傳最新 AI 技術雷達與滾動更新只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_technology_radar_readback)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_technology_radar_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI 技術雷達 readback 無效",
) from exc
@router.get(
"/ai-technology-report-cadence-readback",
response_model=dict[str, Any],
summary="取得 AI 技術雷達日週月報與報告後分析讀回",
description=(
"讀取最新已提交的 AI 技術雷達日報、週報、月報 readback"
"此端點只呈現報告節奏、Agent 工作狀態、圖表化摘要、報告後 AI 分析包、"
"低中高風險處理邊界與 Telegram no-send 審核包。"
"它不送 Telegram、不寫 receipt、不呼叫 Bot API、不執行低中風險 runtime write、"
"不安裝 SDK、不呼叫付費 API、不切換模型、不改主機、不修改 production routing、不替換 OpenClaw。"
),
)
async def get_ai_technology_report_cadence_readback() -> dict[str, Any]:
"""回傳 AI 技術雷達日週月報與報告後分析只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_technology_report_cadence_readback)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_technology_report_cadence_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI 技術雷達日週月報 readback 無效",
) from exc
@router.get(
"/automation-inventory-snapshot",
response_model=dict[str, Any],
summary="取得 AI Agent 自動化盤點快照",
description=(
"讀取最新已提交的 AI Agent 自動化盤點快照;"
"此端點不呼叫外部來源、不碰 DB/Redis、不批准 SDK/API/shadow/canary/生產變更。"
),
)
async def get_automation_inventory_snapshot() -> dict[str, Any]:
"""Return the latest read-only AI Agent automation inventory snapshot."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_automation_inventory_snapshot)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_automation_inventory_snapshot_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent automation inventory snapshot is invalid",
) from exc
@router.get(
"/agent-autonomous-runtime-control",
response_model=dict[str, Any],
summary="取得 AI Agent 目前有效自主化控制層",
description=(
"回傳目前有效的 AI Agent 自主化控制層;此端點明確覆寫舊 no-send / no-live "
"歷史快照,宣告 low / medium / high 風險可在 allowlist、Ansible check-mode、"
"controlled apply、post-apply verifier、KM 與 Telegram Gateway receipt 下受控自動處理。"
"它不讀 secret、不呼叫 Bot API、不暴露 chat id、不執行 runtime 動作runtime 動作由既有 worker / Gateway 接手。"
),
)
async def get_agent_autonomous_runtime_control() -> dict[str, Any]:
"""回傳目前有效 AI Agent 自主化控制層。"""
try:
payload = await build_ai_agent_autonomous_runtime_control_with_live_readback()
return redact_autonomous_runtime_control_public_terms(payload)
except ValueError as exc:
logger.error("ai_agent_autonomous_runtime_control_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 目前有效自主化控制層無效",
) from exc
@router.get(
"/openclaw-live-ops-scene-state",
response_model=dict[str, Any],
summary="取得 OpenClaw Live Ops Space 場景狀態",
description=(
"從 AI Agent autonomous runtime control 的 public-safe trace ledger / "
"work item progress 產生 OpenClaw 持續動畫工作室 scene state。"
"此端點不讀 raw session / SQLite、不讀 secret、不暴露 Telegram 原始 payload、"
"不執行 runtime action、不寫 host/K8s。"
),
)
async def get_openclaw_live_ops_scene_state() -> dict[str, Any]:
"""Return public-safe OpenClaw live ops animation scene state."""
try:
return await load_openclaw_live_ops_scene_state()
except ValueError as exc:
logger.error("openclaw_live_ops_scene_state_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="OpenClaw Live Ops Space 場景狀態無效",
) from exc
@router.get(
"/automation-backlog-snapshot",
response_model=dict[str, Any],
summary="取得 AI Agent 自動化待辦快照",
description=(
"讀取最新已提交的 AI Agent 自動化待辦快照;"
"此端點不呼叫外部來源、不碰 DB/Redis、不批准 SDK/API/shadow/canary/生產變更。"
),
)
async def get_automation_backlog_snapshot() -> dict[str, Any]:
"""Return the latest read-only AI Agent automation backlog snapshot."""
try:
return await asyncio.to_thread(load_latest_ai_agent_automation_backlog_snapshot)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_automation_backlog_snapshot_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent automation backlog snapshot is invalid",
) from exc
@router.get(
"/agent-deployment-layout",
response_model=dict[str, Any],
summary="取得 AI Agent 佈建布局快照",
description=(
"讀取最新已提交的 OpenClaw / Hermes / NemoTron 佈建布局快照;"
"此端點不部署 Agent、不呼叫外部模型、不送 Telegram、不碰 DB/Redis、不讀 Secret payload、"
"不批准 SDK/API/shadow/canary/生產路由或主機變更。"
),
)
async def get_agent_deployment_layout() -> dict[str, Any]:
"""Return the latest read-only AI Agent deployment layout snapshot."""
try:
return await asyncio.to_thread(load_latest_ai_agent_deployment_layout)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_deployment_layout_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 佈建布局快照無效",
) from exc
@router.get(
"/awoooi-status-cleanup-dashboard",
response_model=dict[str, Any],
summary="取得 AWOOOI 狀態清理儀表板",
description=(
"讀取最新已提交的 AWOOOI Status Cleanup Dashboard 只讀快照;"
"此端點只呈現狀態清理完成度、owner gate、apply gate、artifact sync 與 Wazuh handoff 邊界。"
"它不更新 project_current_status / memory、不同步 raw Codex App DB / auth / conversations / sessions、"
"不呼叫 Wazuh live API、不執行 active response、不改主機、不修改 workflow / repo refs、"
"不執行 backup / restore / migration。"
),
)
async def get_awoooi_status_cleanup_dashboard() -> dict[str, Any]:
"""回傳最新 AWOOOI 狀態清理儀表板只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_awoooi_status_cleanup_dashboard)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("awoooi_status_cleanup_dashboard_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AWOOOI 狀態清理儀表板快照無效",
) from exc
@router.get(
"/delivery-closure-workbench",
response_model=dict[str, Any],
summary="取得交付閉環工作台彙總",
description=(
"彙總 AWOOOI 狀態清理、Gitea private inventory、CI/CD baseline、"
"Gitea runner、Runtime surface "
"與 Backup / DR 的既有只讀快照,回傳前端工作台可直接使用的交付主線、"
"完成度、阻擋數與下一步。此端點不呼叫 GitHub / Gitea / Wazuh / K8s live API、"
"不建立 repo、不改 visibility、不同步 refs、不觸發 workflow、不執行備份或還原、"
"不讀 secret、不做 runtime writeGitHub 僅保留 stopped / do_not_use 背景狀態,"
"不進 active P0 blocker math。"
),
)
async def get_delivery_closure_workbench() -> dict[str, Any]:
"""回傳 AWOOOI 交付閉環工作台只讀彙總。"""
try:
payload = await asyncio.to_thread(load_delivery_closure_workbench)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("delivery_closure_workbench_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AWOOOI 交付閉環工作台彙總無效",
) from exc
@router.get(
"/awoooi-priority-work-order-readback",
response_model=dict[str, Any],
summary="取得 AWOOOI 主線工作優先順序讀回",
description=(
"讀取已提交的 AWOOOI P0/P1 主線工作順序快照;此端點只回傳"
"目前 active P0、已關閉 P0、下一步順序、禁止事項與 evidence refs。"
"它會讀取 StockPlatform public HTTPS health/freshness/ingestion live "
"readback不讀 raw sessions / SQLite、不呼叫 GitHub / Gitea live API、"
"不讀 secret、不註冊 runner、不觸發 workflow、不操作 host / Docker / K8s / DB / firewall。"
),
)
async def get_awoooi_priority_work_order_readback() -> dict[str, Any]:
"""回傳 AWOOOI 主線工作優先順序只讀快照。"""
try:
payload = await asyncio.to_thread(
load_latest_awoooi_priority_work_order_readback
)
stockplatform_runtime = await asyncio.to_thread(
load_latest_stockplatform_public_api_runtime_readback
)
apply_stockplatform_public_api_runtime_readback(payload, stockplatform_runtime)
stockplatform_recovery = await asyncio.to_thread(
load_latest_stockplatform_public_api_controlled_recovery_preflight,
runtime_readback=stockplatform_runtime,
)
apply_stockplatform_public_api_controlled_recovery_preflight(
payload,
stockplatform_recovery,
)
harbor_recovery = await asyncio.to_thread(
load_latest_harbor_registry_controlled_recovery_preflight
)
apply_harbor_registry_controlled_recovery_preflight(
payload,
harbor_recovery,
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("awoooi_priority_work_order_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AWOOOI 主線工作優先順序快照無效",
) from exc
@router.get(
"/stockplatform-public-api-runtime-readback",
response_model=dict[str, Any],
summary="取得 StockPlatform public API runtime readback",
description=(
"讀取 StockPlatform public web/API health、freshness 與 ingestion live "
"readback並與 P0-006 committed scorecard 比對。此端點只做 public HTTPS "
"probe不 SSH、不 Docker、不 restart、不寫 DB、不讀 secret、不觸發 workflow。"
),
)
async def get_stockplatform_public_api_runtime_readback() -> dict[str, Any]:
"""回傳 StockPlatform public API runtime live readback。"""
try:
payload = await asyncio.to_thread(
load_latest_stockplatform_public_api_runtime_readback
)
return redact_public_lan_topology(payload)
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"stockplatform_public_api_runtime_readback_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="StockPlatform public API runtime readback 無效",
) from exc
@router.get(
"/stockplatform-public-api-controlled-recovery-preflight",
response_model=dict[str, Any],
summary="取得 StockPlatform public API controlled recovery preflight",
description=(
"讀取 StockPlatform public API runtime drift並產生 AI controlled "
"recovery preflighttarget selector、source-of-truth diff、bounded "
"action candidates、rollback/verifier 與 KM/RAG/MCP/PlayBook writeback "
"contract。此端點不 SSH、不 Docker、不 restart、不寫 DB、不讀 secret、"
"不觸發 workflow。"
),
)
async def get_stockplatform_public_api_controlled_recovery_preflight() -> dict[str, Any]:
"""回傳 StockPlatform public API controlled recovery preflight。"""
try:
payload = await asyncio.to_thread(
load_latest_stockplatform_public_api_controlled_recovery_preflight
)
return redact_public_lan_topology(payload)
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"stockplatform_public_api_controlled_recovery_preflight_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="StockPlatform public API controlled recovery preflight 無效",
) from exc
@router.get(
"/harbor-registry-controlled-recovery-preflight",
response_model=dict[str, Any],
summary="取得 Harbor registry controlled recovery preflight",
description=(
"讀取 Harbor / registry public 與 110 internal /v2/ readback並產生 "
"AI controlled recovery preflighttarget selector、watchdog executor "
"contract、bounded action candidates、post-verifier 與 "
"KM/RAG/MCP/PlayBook writeback contract。此端點不 SSH、不 Docker、"
"不 restart、不讀 secret、不觸發 workflow、不寫 runtime。"
),
)
async def get_harbor_registry_controlled_recovery_preflight() -> dict[str, Any]:
"""回傳 Harbor registry controlled recovery preflight。"""
try:
payload = await asyncio.to_thread(
load_latest_harbor_registry_controlled_recovery_preflight
)
return redact_public_lan_topology(payload)
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"harbor_registry_controlled_recovery_preflight_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Harbor registry controlled recovery preflight 無效",
) from exc
@router.post(
"/harbor-registry-controlled-recovery-receipt",
response_model=dict[str, Any],
summary="驗證 Harbor registry controlled recovery receipt",
description=(
"驗證 110 local SSH repair / Harbor watchdog check / repair-once 的"
"非秘密輸出與 registry /v2/ verifier回傳可供 KM/RAG/MCP/PlayBook "
"metadata writeback 的 receipt。此端點不回傳 raw log、不 SSH、不 Docker、"
"不 restart、不讀 secret、不觸發 workflow、不寫 runtime。"
),
)
async def validate_harbor_registry_controlled_recovery_receipt_packet(
receipt_payload: dict[str, Any],
) -> dict[str, Any]:
"""驗證 Harbor registry controlled recovery receipt。"""
try:
payload = await asyncio.to_thread(
validate_harbor_registry_controlled_recovery_receipt,
receipt_payload,
)
return redact_public_lan_topology(payload)
except ValueError as exc:
logger.error(
"harbor_registry_controlled_recovery_receipt_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail=str(exc),
) from exc
@router.get(
"/product-awoooi-manifest-standard",
response_model=dict[str, Any],
summary="取得 P0-002 product.awoooi.yaml manifest standard readiness",
description=(
"讀取已提交的 P0-002 product.awoooi.yaml manifest standard readiness"
"此端點只檢查 AWOOOI manifest、schema 與 Data/Security/Runtime contract refs。"
"它不建立 repo、不同步 refs、不觸發 workflow、不呼叫 GitHub、"
"不讀 secret、不操作 host / K8s。"
),
)
async def get_product_awoooi_manifest_standard() -> dict[str, Any]:
"""回傳 P0-002 product.awoooi.yaml manifest standard readiness 只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_product_awoooi_manifest_standard)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("product_awoooi_manifest_standard_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-002 product.awoooi.yaml manifest standard 快照無效",
) from exc
@router.get(
"/p0-cicd-baseline-source-readiness",
response_model=dict[str, Any],
summary="取得 P0-004 CI/CD baseline source readiness",
description=(
"讀取已提交的 P0-004 dev/prod CI/CD baseline source readiness"
"此端點只檢查 baseline / warning step / apply gate 的 committed source 是否存在。"
"它不修改 `.gitea/workflows`、不觸發 workflow、不建立 repo、不同步 refs、"
"不呼叫 GitHub、不讀 secret、不操作 host / K8s。"
),
)
async def get_p0_cicd_baseline_source_readiness() -> dict[str, Any]:
"""回傳 P0-004 CI/CD baseline source readiness 只讀快照。"""
try:
payload = await asyncio.to_thread(
load_latest_p0_cicd_baseline_source_readiness
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("p0_cicd_baseline_source_readiness_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-004 CI/CD baseline source readiness 快照無效",
) from exc
@router.get(
"/awoooi-gitea-onboarding-warning-step-template-copy-apply-gate",
response_model=dict[str, Any],
summary="取得 AWOOOI Gitea onboarding warning-step template copy apply gate",
description=(
"讀取 P0-004 warning-step template copy 的受控 apply gate"
"此端點只回傳 controlled template-copy package readiness。"
"它不複製 workflow、不觸發 workflow、不建立 repo、不同步 refs、"
"不呼叫 GitHub、不讀 secret、不操作 host / K8s。"
),
)
async def get_awoooi_gitea_onboarding_warning_step_template_copy_apply_gate() -> dict[str, Any]:
"""回傳 P0-004 warning-step template copy apply gate 只讀讀回。"""
try:
payload = await asyncio.to_thread(
load_latest_awoooi_gitea_onboarding_warning_step_template_copy_apply_gate
)
return redact_public_lan_topology(payload)
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"awoooi_gitea_onboarding_warning_step_template_copy_apply_gate_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-004 warning-step template copy apply gate 無效",
) from exc
@router.get(
"/awoooi-gitea-onboarding-warning-step-template-copy-execution-plan",
response_model=dict[str, Any],
summary="取得 AWOOOI Gitea onboarding warning-step template copy execution plan",
description=(
"讀取 P0-004 warning-step template copy 的受控 execution plan"
"此端點只回傳 committed template-copy plan readiness。"
"它不複製 workflow、不觸發 workflow、不建立 repo、不同步 refs、"
"不呼叫 GitHub、不讀 secret、不操作 host / K8s。"
),
)
async def get_awoooi_gitea_onboarding_warning_step_template_copy_execution_plan() -> dict[
str, Any
]:
"""回傳 P0-004 warning-step template copy execution plan 只讀讀回。"""
try:
payload = await asyncio.to_thread(
load_latest_awoooi_gitea_onboarding_warning_step_template_copy_execution_plan
)
return redact_public_lan_topology(payload)
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"awoooi_gitea_onboarding_warning_step_template_copy_execution_plan_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-004 warning-step template copy execution plan 無效",
) from exc
@router.get(
"/awoooi-gitea-onboarding-warning-step-template-copy-receipt",
response_model=dict[str, Any],
summary="取得 AWOOOI Gitea onboarding warning-step template copy receipt",
description=(
"讀取 P0-004 warning-step template copy 的受控 receipt"
"此端點檢查 template 已提交、workflow 已複製且 fail-closed、"
"無 branch auto trigger、無泛用 runner label並回傳 rollback / verifier / "
"post-copy boundary。它不觸發 workflow、不建立 repo、不同步 refs、"
"不呼叫 GitHub、不讀 secret、不操作 host / K8s。"
),
)
async def get_awoooi_gitea_onboarding_warning_step_template_copy_receipt() -> dict[str, Any]:
"""回傳 P0-004 warning-step template copy receipt 只讀讀回。"""
try:
payload = await asyncio.to_thread(
load_latest_awoooi_gitea_onboarding_warning_step_template_copy_receipt
)
return redact_public_lan_topology(payload)
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"awoooi_gitea_onboarding_warning_step_template_copy_receipt_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-004 warning-step template copy receipt 無效",
) from exc
@router.get(
"/awoooi-gitea-onboarding-warning-step-runtime-enablement-gate",
response_model=dict[str, Any],
summary="取得 AWOOOI Gitea onboarding warning-step runtime enablement gate",
description=(
"讀取 P0-004 warning-step runtime enablement 的受控 gate"
"此端點只回傳 enablement target selector、source diff、check-mode、"
"rollback 與 post-apply verifier。它不修改 workflow、不觸發 workflow、"
"不建立 repo、不同步 refs、不呼叫 GitHub、不讀 secret、不操作 host / K8s。"
),
)
async def get_awoooi_gitea_onboarding_warning_step_runtime_enablement_gate() -> dict[
str, Any
]:
"""回傳 P0-004 warning-step runtime enablement gate 只讀讀回。"""
try:
payload = await asyncio.to_thread(
load_latest_awoooi_gitea_onboarding_warning_step_runtime_enablement_gate
)
return redact_public_lan_topology(payload)
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"awoooi_gitea_onboarding_warning_step_runtime_enablement_gate_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-004 warning-step runtime enablement gate 無效",
) from exc
@router.get(
"/reboot-auto-recovery-slo-scorecard",
response_model=dict[str, Any],
summary="取得 P0-006 reboot auto-recovery SLO scorecard",
description=(
"讀取已提交的 P0-006 reboot auto-recovery 10-minute SLO scorecard"
"此端點只回傳 host boot probe、post-reboot readiness、StockPlatform freshness / "
"ingestion readback、retry window 與 controlled recovery gate 狀態。"
"它不重啟主機、不 restart service、不寫資料庫、不偽造 freshness marker、"
"不讀 secret、不觸發 workflow、不呼叫 GitHub。"
),
)
async def get_reboot_auto_recovery_slo_scorecard() -> dict[str, Any]:
"""回傳 P0-006 reboot auto-recovery SLO scorecard 只讀快照。"""
try:
payload = await asyncio.to_thread(
load_latest_reboot_auto_recovery_slo_scorecard
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("reboot_auto_recovery_slo_scorecard_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-006 reboot auto-recovery SLO scorecard 快照無效",
) from exc
@router.get(
"/reboot-auto-recovery-drill-preflight",
response_model=dict[str, Any],
summary="取得 P0-006 reboot drill preflight",
description=(
"讀取 P0-006 reboot auto-recovery SLO scorecard產生 approved reboot "
"drill 的只讀 preflight contract此端點只回傳 target selector、"
"preconditions、verify-only、rollback/post-verifier 與 break-glass 邊界。"
"它不重啟主機、不 restart service、不寫資料庫、不觸發 workflow、"
"不讀 secret、不呼叫 GitHub也不授權 runtime execution。"
),
)
async def get_reboot_auto_recovery_drill_preflight() -> dict[str, Any]:
"""回傳 P0-006 reboot drill 只讀 preflight contract。"""
try:
payload = await asyncio.to_thread(
load_latest_reboot_auto_recovery_drill_preflight
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("reboot_auto_recovery_drill_preflight_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-006 reboot drill preflight 快照無效",
) from exc
@router.get(
"/gitea-private-inventory-p0-scorecard",
response_model=dict[str, Any],
summary="取得 P0-003 Gitea private inventory scorecard",
description=(
"讀取已提交的 P0-003 Gitea-only private/internal inventory scorecard"
"此端點只回傳 Gitea inventory metadata、redacted import acceptance 狀態、"
"owner coverage attestation 狀態與產品列覆蓋度。"
"它不呼叫 Gitea / GitHub live API、不收 token value、不建立 repo、"
"不改 visibility、不同步 refs、不觸發 workflow、不讀 secret、"
"不讀 raw session/SQLite。GitHub 僅保留 stopped / do_not_use 背景狀態,"
"不進 active P0 blocker math。"
),
)
async def get_gitea_private_inventory_p0_scorecard() -> dict[str, Any]:
"""回傳 P0-003 Gitea-only private inventory scorecard 只讀快照。"""
try:
payload = await asyncio.to_thread(
load_latest_gitea_private_inventory_p0_scorecard
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("gitea_private_inventory_p0_scorecard_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-003 Gitea private inventory scorecard 快照無效",
) from exc
@router.post(
"/gitea-private-inventory-p0-scorecard/validate-authenticated-inventory-payload",
response_model=dict[str, Any],
summary="驗證 P0-003 Gitea authenticated/admin inventory 脫敏 payload",
description=(
"針對單次 owner-provided redacted Gitea authenticated/admin inventory "
"payload 進行 no-persist validation此端點只回傳 private inventory "
"reviewer readiness / needs supplement / quarantined / rejected execution "
"分流,不保存 payload、不呼叫 Gitea/GitHub、不收 token value、"
"不建立 repo、不改 visibility、不同步 refs、不觸發 workflow、"
"不讀 secret、不讀 raw session/SQLite。"
),
)
async def validate_gitea_authenticated_inventory_payload_packet(
inventory_payload: dict[str, Any],
) -> dict[str, Any]:
"""Return no-persist validation for one P0-003 redacted inventory payload."""
try:
payload = await asyncio.to_thread(
validate_gitea_authenticated_inventory_payload,
inventory_payload,
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("gitea_authenticated_inventory_payload_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-003 Gitea authenticated inventory payload 驗證器無效",
) from exc
@router.post(
"/gitea-private-inventory-p0-scorecard/validate-owner-coverage-attestation",
response_model=dict[str, Any],
summary="驗證 P0-003 Gitea owner coverage attestation 脫敏回覆",
description=(
"針對單次 owner-provided redacted Gitea coverage attestation response "
"packet 進行 no-persist validation此端點只回傳 owner attestation "
"reviewer readiness / needs supplement / quarantined / rejected execution "
"分流,不保存 payload、不呼叫 Gitea/GitHub、不收 token value、"
"不建立 repo、不改 visibility、不同步 refs、不觸發 workflow、"
"不讀 secret、不讀 raw session/SQLite。"
),
)
async def validate_gitea_owner_coverage_attestation_packet(
owner_response: dict[str, Any],
) -> dict[str, Any]:
"""Return no-persist validation for one P0-003 owner attestation packet."""
try:
payload = await asyncio.to_thread(
validate_gitea_owner_coverage_attestation,
owner_response,
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("gitea_owner_coverage_attestation_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-003 Gitea owner coverage attestation 驗證器無效",
) from exc
@router.post(
"/gitea-private-inventory-p0-scorecard/validate-controlled-closeout",
response_model=dict[str, Any],
summary="驗證 P0-003 Gitea private inventory controlled closeout 脫敏收斂包",
description=(
"同時驗證 owner-provided redacted authenticated/admin inventory payload "
"與 owner coverage attestation response回傳 P0-003 controlled closeout "
"readiness此端點不保存 payload、不寫 source scorecard、不呼叫 Gitea/GitHub、"
"不收 token value、不建立 repo、不改 visibility、不同步 refs、不觸發 workflow、"
"不讀 secret、不讀 raw session/SQLite。"
),
)
async def validate_gitea_private_inventory_controlled_closeout_packet(
closeout_packet: dict[str, Any],
) -> dict[str, Any]:
"""Return no-persist closeout validation for paired P0-003 redacted inputs."""
try:
payload = await asyncio.to_thread(
validate_gitea_private_inventory_controlled_closeout,
closeout_packet,
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("gitea_private_inventory_controlled_closeout_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-003 Gitea private inventory controlled closeout 驗證器無效",
) from exc
@router.get(
"/github-target-private-backup-evidence-gate",
response_model=dict[str, Any],
summary="取得 GitHub 私有備援證據閘門",
description=(
"彙整既有 GitHub target decision、owner response、approval package 與 probe snapshot"
"用只讀方式判定 GitHub 備援是否具備 private visibility、safe credential 與 owner evidence。"
"此端點不呼叫 GitHub live API、不建立 repo、不改 visibility、不同步 refs、不觸發 workflow、"
"不收 private clone URL credential 或任何 secret value。"
),
)
async def get_github_target_private_backup_evidence_gate() -> dict[str, Any]:
"""回傳 GitHub 私有備援 evidence gate 只讀彙總。"""
try:
payload = await asyncio.to_thread(load_latest_github_target_private_backup_evidence_gate)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("github_target_private_backup_evidence_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="GitHub 私有備援證據閘門無效",
) from exc
@router.get(
"/github-target-controlled-execution-preflight",
response_model=dict[str, Any],
summary="取得 GitHub target controlled execution preflight",
description=(
"讀取已提交的 GitHub target controlled execution preflight明確區分 owner authorization "
"與實際 GitHub create/sync write channel、canonical source、dry-run verifier 是否 ready。"
"此端點不呼叫 GitHub live API、不建立 repo、不改 visibility、不同步 refs、不觸發 workflow、"
"不收 private clone URL credential 或任何 secret value。"
),
)
async def get_github_target_controlled_execution_preflight() -> dict[str, Any]:
"""回傳 GitHub target controlled execution preflight 只讀彙總。"""
try:
payload = await asyncio.to_thread(
load_latest_github_target_controlled_execution_preflight
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"github_target_controlled_execution_preflight_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="GitHub target controlled execution preflight 無效",
) from exc
@router.post(
"/github-target-owner-response-intake-preflight",
response_model=dict[str, Any],
summary="預檢 GitHub target owner response candidate",
description=(
"只驗證一份 GitHub target owner response candidate 是否符合 read-only intake 規則;"
"此端點不持久化 submission、不呼叫 GitHub live API、不建立 repo、不改 visibility、不同步 refs、"
"不觸發 workflow、不收 private clone URL credential 或任何 secret value。"
),
)
async def preflight_github_target_owner_response_intake(
submission: dict[str, Any],
) -> dict[str, Any]:
"""Validate a GitHub target owner response candidate without persisting it."""
try:
payload = await asyncio.to_thread(
preflight_github_target_owner_response_submission,
submission,
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"github_target_owner_response_intake_preflight_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="GitHub target owner response intake preflight 無效",
) from exc
@router.post(
"/github-target-safe-credential-evidence-reviewer-validation/validate-redacted-refs",
response_model=dict[str, Any],
summary="驗證 GitHub target safe credential 脫敏 evidence refs",
description=(
"針對單次 owner-provided redacted safe credential evidence refs 進行 no-persist "
"reviewer validation回傳 accepted / needs supplement / quarantined / rejected runtime "
"action 分流。此端點不保存 payload、不呼叫 GitHub live API、不建立 repo、不改 visibility、"
"不同步 refs、不觸發 workflow、不收 private clone URL credential 或任何 secret value也不更新 "
"safe credential accepted evidence 總帳。"
),
)
async def validate_github_target_safe_credential_evidence_review(
submission: dict[str, Any],
) -> dict[str, Any]:
"""回傳單次 GitHub safe credential 脫敏 evidence refs 公開安全驗證結果。"""
try:
payload = await asyncio.to_thread(
validate_github_target_safe_credential_evidence_refs,
submission,
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"github_target_safe_credential_evidence_review_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="GitHub target safe credential evidence review 無效",
) from exc
@router.get(
"/agent-12-agent-war-room",
response_model=dict[str, Any],
summary="取得 AI Agent 12-Agent War Room 快照",
description=(
"讀取最新已提交的 12-Agent War Room 只讀快照;"
"此端點只呈現 OpenClaw、Hermes、NemoTron、SRE、Security、DevOps、Data/DR、"
"Supply Chain、Product/UI、QA、Market Scout、Telegram Ops 的分工、工作量、阻擋項與批准邊界,"
"不開 runtime writer、不送 Telegram、不呼叫 Bot API、不安裝 SDK、不呼叫付費 API、"
"不讀 secret、不執行 production write。"
),
)
async def get_agent_12_agent_war_room() -> dict[str, Any]:
"""回傳最新 12-Agent War Room 只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_12_agent_war_room)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_12_agent_war_room_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 12-Agent War Room 快照無效",
) from exc
@router.get(
"/agent-professional-task-expansion",
response_model=dict[str, Any],
summary="取得 AI Agent 專業任務擴展與 Telegram Runtime Bridge 快照",
description=(
"讀取最新已提交的 P2-405F AI Agent 專業任務擴展與 Telegram Runtime Bridge 只讀快照;"
"此端點只呈現 OpenClaw、Hermes、NemoTron 與專責 Agent 可承接的專業任務、MCP/RAG、"
"風險分層、Telegram no-send preview 與後續 canary gate"
"不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不讀 secret、不執行 production write、"
"不改主機、不執行 kubectl。"
),
)
async def get_agent_professional_task_expansion() -> dict[str, Any]:
"""回傳最新 AI Agent 專業任務擴展與 Telegram Runtime Bridge 只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_professional_task_expansion)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_professional_task_expansion_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 專業任務擴展與 Telegram Runtime Bridge 快照無效",
) from exc
@router.get(
"/agent-receipt-readback-owner-review",
response_model=dict[str, Any],
summary="取得 P2-406B AI Agent receipt readback owner review",
description=(
"讀取最新已提交的 P2-406B receipt readback owner review 只讀快照;"
"此端點只呈現日報 / 週報 / 月報、Telegram receipt、P2-004 供應鏈漂移與報表真相 gate 的 owner review"
"不啟用排程、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 receipt production target、"
"不啟動 AI analysis worker、不執行中低風險自動處理、不寫 production、不讀 secret、"
"不呼叫付費 API、不改主機、不執行 kubectl 或不可逆操作。"
),
)
async def get_agent_receipt_readback_owner_review() -> dict[str, Any]:
"""回傳最新 P2-406B receipt readback owner review 只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_receipt_readback_owner_review)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_receipt_readback_owner_review_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P2-406B AI Agent receipt readback owner review 快照無效",
) from exc
@router.get(
"/agent-report-no-write-analysis-runtime",
response_model=dict[str, Any],
summary="取得 P2-407 AI Agent 報表 no-write 分析 runtime",
description=(
"讀取最新已提交的 P2-407 AI Agent 報表 no-write 分析快照;此端點只呈現 "
"OpenClaw、Hermes、NemoTron 讀取日報 / 週報 / 月報、P2-406B receipt owner review、"
"P2-004 供應鏈漂移與 P2-403J 報表真相後產生的分析草稿與風險分級。"
"它不啟動 live AI worker、不排程實發、不寫 Gateway queue、不送 Telegram、"
"不呼叫 Bot API、不寫 receipt production target、不寫 production、不讀 secret、"
"不呼叫付費 API、不改主機、不執行 kubectl 或不可逆操作。"
),
)
async def get_agent_report_no_write_analysis_runtime() -> dict[str, Any]:
"""回傳最新 P2-407 report no-write analysis runtime 只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_report_no_write_analysis_runtime)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_report_no_write_analysis_runtime_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P2-407 AI Agent 報表 no-write 分析 runtime 快照無效",
) from exc
@router.get(
"/agent-low-medium-risk-whitelist",
response_model=dict[str, Any],
summary="取得 P2-408 AI Agent 中低風險自動處理白名單",
description=(
"讀取最新已提交的 P2-408 AI Agent 中 / 低風險候選白名單快照;此端點只呈現 "
"low / medium action policy、dry-run verifier、rollback proof、audit reason 與高風險分流。"
"它不啟動 auto worker、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、"
"不寫 receipt production target、不寫 production、不讀 secret、不呼叫付費 API、"
"不改主機、不執行 kubectl 或不可逆操作。"
),
)
async def get_agent_low_medium_risk_whitelist() -> dict[str, Any]:
"""回傳最新 P2-408 low / medium risk whitelist 只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_low_medium_risk_whitelist)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_low_medium_risk_whitelist_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P2-408 AI Agent 中低風險自動處理白名單快照無效",
) from exc
@router.get(
"/agent-high-risk-owner-review-queue",
response_model=dict[str, Any],
summary="取得 P2-409 AI Agent 高風險受控執行 / Break-glass 佇列",
description=(
"讀取最新已提交的 P2-409 AI Agent 高風險受控執行 / critical break-glass 只讀快照;"
"此端點呈現 high controlled apply queue、critical break-glass queue、packet、"
"rejection guard、reviewer checklist、Telegram policy 與執行邊界。"
"它不自行啟動 auto worker、不執行 live action、不寫 Gateway queue、不送 Telegram、"
"不呼叫 Bot API、不寫 receipt production target、不寫 production、不讀 secret、"
"不呼叫付費 API、不改主機、不執行 kubectl 或不可逆操作。"
),
)
async def get_agent_high_risk_owner_review_queue() -> dict[str, Any]:
"""回傳最新 P2-409 high-risk controlled apply queue 只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_high_risk_owner_review_queue)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_high_risk_owner_review_queue_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P2-409 AI Agent 高風險受控執行 / Break-glass 佇列快照無效",
) from exc
@router.get(
"/agent-controlled-executor-handoff",
response_model=dict[str, Any],
summary="取得 P2-415 AI Agent 受控 Executor 交接跑道",
description=(
"讀取最新已提交的 P2-415 AI Agent controlled executor handoff 只讀快照;"
"此端點呈現 high risk packet 是否具備 allowlist、Ansible check-mode、rollback、"
"post-action verifier、Telegram evidence、KM / PlayBook trust writeback 條件,"
"以及 critical break-glass 邊界。它不 dispatch executor、不執行 live apply、"
"不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 KM、不更新 PlayBook trust、"
"不寫 production、不讀 secret、不呼叫付費 API、不改主機、不執行 kubectl 或不可逆操作。"
),
)
async def get_agent_controlled_executor_handoff() -> dict[str, Any]:
"""回傳最新 P2-415 controlled executor handoff 只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_controlled_executor_handoff)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_controlled_executor_handoff_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P2-415 AI Agent 受控 Executor 交接跑道快照無效",
) from exc
@router.get(
"/agent-action-audit-ledger",
response_model=dict[str, Any],
summary="取得 P2-410 AI Agent 行動審計帳本",
description=(
"讀取最新已提交的 P2-410 AI Agent 行動審計帳本快照;此端點只呈現 "
"immutable audit event template、source readback、verifier receipt gate、redaction contract "
"與 no-write activation boundary。它不寫 audit DB、不寫 timeline、不寫 KM、不更新 PlayBook trust、"
"不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production、不讀 secret、"
"不呼叫付費 API、不改主機、不執行 kubectl 或不可逆操作。"
),
)
async def get_agent_action_audit_ledger() -> dict[str, Any]:
"""回傳最新 P2-410 action audit ledger 只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_action_audit_ledger)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_action_audit_ledger_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P2-410 AI Agent 行動審計帳本快照無效",
) from exc
@router.get(
"/agent-action-owner-acceptance-event-bus",
response_model=dict[str, Any],
summary="取得 P2-411 AI Agent Owner Acceptance / Handoff Event Bus",
description=(
"讀取最新已提交的 P2-411 AI Agent owner acceptance / handoff event bus "
"no-write 快照;此端點只呈現 owner acceptance lane、handoff event template、"
"RAG memory proposal、verifier gate 與 no-write activation boundary。它不 publish event bus、"
"不寫 audit DB、不寫 timeline、不寫 KM、不更新 PlayBook trust、不寫 Gateway queue、"
"不送 Telegram、不呼叫 Bot API、不 dispatch worker、不寫 production、不讀 secret、"
"不呼叫付費 API、不改主機、不執行 kubectl 或不可逆操作。"
),
)
async def get_agent_action_owner_acceptance_event_bus() -> dict[str, Any]:
"""回傳最新 P2-411 owner acceptance / handoff event bus 只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_action_owner_acceptance_event_bus)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_action_owner_acceptance_event_bus_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P2-411 AI Agent Owner Acceptance / Handoff Event Bus 快照無效",
) from exc
@router.get(
"/agent-host-runaway-aiops-loop-readiness",
response_model=dict[str, Any],
summary="取得 P3-009 Host runaway AIOps loop readiness",
description=(
"讀取最新已提交的 P3-009 Host runaway AIOps loop readiness 只讀快照;"
"此端點只呈現 110 runaway process 的監控、告警、AI event packet、PlayBook、KM / Verifier "
"與 gated remediation 合約,不送 Telegram、不寫 Gateway queue、不呼叫 Bot API、不讀 secret、"
"不 kill process、不重啟 Docker / systemd / Nginx、不改 firewall、不執行 kubectl、不寫 production。"
),
)
async def get_agent_host_runaway_aiops_loop_readiness() -> dict[str, Any]:
"""回傳最新 P3-009 Host runaway AIOps loop readiness 只讀快照。"""
try:
payload = await asyncio.to_thread(load_latest_host_runaway_aiops_loop_readiness)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("host_runaway_aiops_loop_readiness_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P3-009 Host runaway AIOps loop readiness 快照無效",
) from exc
@router.get(
"/agent-communication-learning-contract",
response_model=dict[str, Any],
summary="取得 AI Agent 主動溝通與學習契約",
description=(
"讀取最新已提交的 OpenClaw / Hermes / NemoTron 主動溝通、學習、記錄、MCP 與 RAG 契約;"
"此端點不啟動 worker、不建立 DB migration、不送 Telegram、不安裝 SDK、不呼叫付費服務、"
"不修改生產路由或主機。"
),
)
async def get_agent_communication_learning_contract() -> dict[str, Any]:
"""Return the latest read-only AI Agent communication learning contract."""
try:
return await asyncio.to_thread(load_latest_ai_agent_communication_learning_contract)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_communication_learning_contract_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 主動溝通與學習契約無效",
) from exc
@router.get(
"/agent-interaction-learning-proof",
response_model=dict[str, Any],
summary="取得 AI Agent 互動與學習證據面",
description=(
"讀取最新已提交的 OpenClaw / Hermes / NemoTron 互動、接手、學習、成長與 Telegram 收據證據面;"
"此端點不啟動 worker、不讀寫 Redis consumer group、不建立 DB migration、不送 Telegram、"
"不回傳內部協作逐字稿、提示詞、私有推理或機密值。"
),
)
async def get_agent_interaction_learning_proof() -> dict[str, Any]:
"""Return the latest read-only AI Agent interaction and learning proof surface."""
try:
return await asyncio.to_thread(load_latest_ai_agent_interaction_learning_proof)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_interaction_learning_proof_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 互動與學習證據面無效",
) from exc
@router.get(
"/agent-live-read-model-gate",
response_model=dict[str, Any],
summary="取得 AI Agent live read model gate",
description=(
"讀取最新已提交的 AgentSession / Redis Streams live read model gate"
"此端點不連 DB、不讀寫 Redis、不啟動 worker、不建立 DB migration、不送 Telegram、"
"不回傳內部協作逐字稿、Agent 原始輸出、提示詞、私有推理或機密值。"
),
)
async def get_agent_live_read_model_gate() -> dict[str, Any]:
"""Return the latest read-only AI Agent live read model gate snapshot."""
try:
return await asyncio.to_thread(load_latest_ai_agent_live_read_model_gate)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_live_read_model_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent live read model gate 無效",
) from exc
@router.get(
"/agent-redis-dry-run-gate",
response_model=dict[str, Any],
summary="取得 AI Agent Redis dry-run gate",
description=(
"讀取最新已提交的 Redis Streams consumer group dry-run、handoff envelope、"
"ack / dead-letter / replay gate此端點不連 Redis、不建立 consumer group、不 XADD、"
"不 XREADGROUP、不 ACK、不寫 dead-letter、不 replay、不送 Telegram、不做 learning writeback、"
"不回傳未核准內部細節。"
),
)
async def get_agent_redis_dry_run_gate() -> dict[str, Any]:
"""Return the latest read-only AI Agent Redis dry-run gate snapshot."""
try:
return await asyncio.to_thread(load_latest_ai_agent_redis_dry_run_gate)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_redis_dry_run_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent Redis dry-run gate 無效",
) from exc
@router.get(
"/agent-learning-writeback-approval-package",
response_model=dict[str, Any],
summary="取得 AI Agent learning writeback approval package",
description=(
"讀取最新已提交的 KM / PlayBook trust / timeline learning / replay score 回寫批准包;"
"此端點不寫 KM、不更新 PlayBook trust、不寫 timeline、不寫 replay score、不送 Telegram、"
"不啟動 runtime worker、不回傳未核准內部細節。"
),
)
async def get_agent_learning_writeback_approval_package() -> dict[str, Any]:
"""Return the latest read-only AI Agent learning writeback approval package."""
try:
return await asyncio.to_thread(load_latest_ai_agent_learning_writeback_approval_package)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_learning_writeback_approval_package_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent learning writeback approval package 無效",
) from exc
@router.get(
"/agent-log-intelligence-integration-readback",
response_model=dict[str, Any],
summary="取得 AI Agent LOG / KM / RAG / MCP / PlayBook 整合 readback",
description=(
"讀取目前 API image 內已提交的 LOG intelligence source refs彙總服務日誌、"
"分類摘要、KM/RAG、MCP audit、PlayBook learning 與 AI Agent 決策 runtime 的串接面。"
"此端點不查 live log、不寫 KM、不寫 RAG index、不更新 PlayBook trust、不呼叫 MCP tool、"
"不執行修復、不觸發 workflow、不讀 secret、不讀 raw session / SQLite、不呼叫 GitHub。"
),
)
async def get_agent_log_intelligence_integration_readback() -> dict[str, Any]:
"""Return the read-only LOG intelligence integration matrix."""
try:
payload = await asyncio.to_thread(
load_latest_ai_agent_log_intelligence_integration_readback
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_log_intelligence_integration_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent LOG / KM / RAG / MCP / PlayBook 整合 readback 無效",
) from exc
@router.get(
"/agent-log-feedback-receipt-dry-run",
response_model=dict[str, Any],
summary="取得 AI Agent LOG feedback receipt dry-run",
description=(
"把 LOG intelligence runtime sample 轉成 KM、RAG、PlayBook、MCP audit、"
"post-apply verifier 與 AI Agent 決策上下文的 dry-run receipt 候選。"
"此端點不寫 KM、不寫 RAG index、不更新 PlayBook trust、不呼叫 MCP tool、"
"不執行 verifier、不觸發 runtime action、不保存 raw log payload、不讀 secret、不呼叫 GitHub。"
),
)
async def get_agent_log_feedback_receipt_dry_run() -> dict[str, Any]:
"""Return LOG feedback receipt dry-run candidates for AI automation."""
try:
payload = await asyncio.to_thread(
load_latest_ai_agent_log_feedback_receipt_dry_run
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_log_feedback_receipt_dry_run_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent LOG feedback receipt dry-run 無效",
) from exc
@router.get(
"/agent-log-post-write-verifier-dry-run",
response_model=dict[str, Any],
summary="取得 AI Agent LOG post-write verifier dry-run",
description=(
"驗證 LOG feedback receipt 候選是否已具備 KM、RAG、PlayBook、MCP audit、"
"post-apply verifier 與 AI Agent 決策上下文回寫前的必要標籤、redaction 與 no-write 邊界。"
"此端點不寫 KM、不寫 RAG index、不更新 PlayBook trust、不呼叫 MCP tool、"
"不執行 runtime action、不保存 raw log payload、不讀 secret、不呼叫 GitHub。"
),
)
async def get_agent_log_post_write_verifier_dry_run() -> dict[str, Any]:
"""Return LOG feedback post-write verifier dry-run readback."""
try:
payload = await asyncio.to_thread(
load_latest_ai_agent_log_post_write_verifier_dry_run
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_log_post_write_verifier_dry_run_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent LOG post-write verifier dry-run 無效",
) from exc
@router.get(
"/agent-log-controlled-writeback-plan-readback",
response_model=dict[str, Any],
summary="取得 AI Agent LOG controlled writeback plan readback",
description=(
"把已驗證的 LOG feedback receipt 轉成 KM、RAG、PlayBook、MCP audit、"
"post-apply verifier 與 AI Agent 決策上下文的受控回寫計畫,包含 target selector、"
"source-of-truth diff、check-mode、rollback 與 post-apply verifier。"
"此端點只輸出 plan readback不寫 KM、不寫 RAG index、不更新 PlayBook trust、"
"不呼叫 MCP tool、不執行 runtime action、不保存 raw log payload、不讀 secret、不呼叫 GitHub。"
),
)
async def get_agent_log_controlled_writeback_plan_readback() -> dict[str, Any]:
"""Return LOG feedback controlled writeback plan readback."""
try:
payload = await asyncio.to_thread(
load_latest_ai_agent_log_controlled_writeback_plan_readback
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_log_controlled_writeback_plan_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent LOG controlled writeback plan readback 無效",
) from exc
@router.get(
"/agent-log-controlled-writeback-executor-readback",
response_model=dict[str, Any],
summary="取得 AI Agent LOG controlled writeback executor readback",
description=(
"把 LOG controlled writeback plan 轉成 AI Agent 可消費的 executor batch、"
"next action queue、check-mode、rollback 與 post-apply verifier readback。"
"低中高風險 metadata writeback 採 AI controlled applycritical 仍需 break-glass。"
"此端點只輸出 executor readback不 dispatch executor、不寫 KM、不寫 RAG index、"
"不更新 PlayBook trust、不呼叫 MCP tool、不保存 raw log payload、不讀 secret、不呼叫 GitHub。"
),
)
async def get_agent_log_controlled_writeback_executor_readback() -> dict[str, Any]:
"""Return LOG feedback controlled writeback executor and consumption readback."""
try:
payload = await asyncio.to_thread(
load_latest_ai_agent_log_controlled_writeback_executor_readback
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_log_controlled_writeback_executor_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent LOG controlled writeback executor readback 無效",
) from exc
@router.post(
"/agent-log-controlled-writeback-dispatch",
response_model=dict[str, Any],
summary="執行 AI Agent LOG controlled writeback metadata dispatch",
description=(
"把已通過 selector / diff / check-mode / rollback / post-apply verifier 的 "
"LOG feedback batches 寫入 automation_operation_log形成 metadata-only "
"dispatch receipt。此端點不寫 KM、不寫 RAG index、不更新 PlayBook trust、"
"不呼叫 MCP tool、不發 Telegram、不觸發 workflow、不保存 raw log payload、"
"不讀 secret、不呼叫 GitHub。"
),
)
async def post_agent_log_controlled_writeback_dispatch() -> dict[str, Any]:
"""Persist metadata-only LOG controlled writeback dispatch receipts."""
try:
payload = await dispatch_latest_ai_agent_log_controlled_writeback()
return redact_public_lan_topology(payload)
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_log_controlled_writeback_dispatch_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent LOG controlled writeback dispatch 無效",
) from exc
@router.get(
"/agent-log-controlled-writeback-consumer-readback",
response_model=dict[str, Any],
summary="取得 AI Agent LOG controlled writeback consumer readback",
description=(
"讀取 automation_operation_log 中的 LOG metadata-only dispatch receipts"
"並投影成 KM / RAG / PlayBook / MCP / verifier / AI Agent consumer "
"context binding。此端點不寫 KM、不寫 RAG index、不更新 PlayBook trust、"
"不呼叫 MCP tool、不發 Telegram、不觸發 workflow、不保存 raw log payload、"
"不讀 secret、不呼叫 GitHub。"
),
)
async def get_agent_log_controlled_writeback_consumer_readback() -> dict[str, Any]:
"""Read live metadata-only LOG controlled writeback consumer bindings."""
try:
payload = await load_latest_ai_agent_log_controlled_writeback_consumer_readback()
return redact_public_lan_topology(payload)
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"ai_agent_log_controlled_writeback_consumer_readback_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent LOG controlled writeback consumer readback 無效",
) from exc
@router.get(
"/agent-telegram-receipt-approval-package",
response_model=dict[str, Any],
summary="取得 AI Agent Telegram receipt approval package",
description=(
"讀取最新已提交的 Telegram receipt / queue / delivery / ack / failure / retry 批准包;"
"此端點不寫 Gateway queue、不呼叫 Telegram Bot API、不改 receiver route、不發送通知、"
"不啟動 runtime worker、不回傳 Telegram token、raw chat id 或未脫敏 payload。"
),
)
async def get_agent_telegram_receipt_approval_package() -> dict[str, Any]:
"""Return the latest read-only AI Agent Telegram receipt approval package."""
try:
return await asyncio.to_thread(load_latest_ai_agent_telegram_receipt_approval_package)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_telegram_receipt_approval_package_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent Telegram receipt approval package 無效",
) from exc
@router.get(
"/agent-owner-approved-learning-dry-run",
response_model=dict[str, Any],
summary="取得 AI Agent owner-approved learning dry-run contract",
description=(
"讀取最新已提交的 owner-approved learning writeback dry-run 契約;"
"此端點只回傳 dry-run preview、人工操作選項、驗證與 rollback 契約,"
"不寫 KM、不更新 PlayBook trust、不寫 timeline、不寫 replay score、不發 Telegram、"
"不啟動 runtime worker、不回傳未脫敏 payload。"
),
)
async def get_agent_owner_approved_learning_dry_run() -> dict[str, Any]:
"""Return the latest read-only AI Agent owner-approved learning dry-run contract."""
try:
return await asyncio.to_thread(load_latest_ai_agent_owner_approved_learning_dry_run)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_owner_approved_learning_dry_run_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent owner-approved learning dry-run 無效",
) from exc
@router.get(
"/agent-runtime-write-gate-review",
response_model=dict[str, Any],
summary="取得 AI Agent runtime write gate review",
description=(
"讀取最新已提交的 runtime write gate review 契約;此端點只回傳雙重批准、"
"dry-run hash、post-write verifier 與 redaction 欄位檢查,"
"不寫 KM、不更新 PlayBook trust、不寫 timeline、不寫 replay score、不發 Telegram、"
"不啟動 runtime worker、不回傳未脫敏 payload。"
),
)
async def get_agent_runtime_write_gate_review() -> dict[str, Any]:
"""Return the latest read-only AI Agent runtime write gate review."""
try:
return await asyncio.to_thread(load_latest_ai_agent_runtime_write_gate_review)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_runtime_write_gate_review_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent runtime write gate review 無效",
) from exc
@router.get(
"/agent-post-write-verifier-package",
response_model=dict[str, Any],
summary="取得 AI Agent post-write verifier package",
description=(
"讀取最新已提交的 post-write verifier implementation package此端點只回傳 verifier package、"
"rollback lane、failure lane 與人工操作選項,"
"不寫 KM、不更新 PlayBook trust、不寫 timeline、不寫 replay score、不發 Telegram、"
"不啟動 runtime worker、不讀 canonical target、不回傳未脫敏 payload。"
),
)
async def get_agent_post_write_verifier_package() -> dict[str, Any]:
"""Return the latest read-only AI Agent post-write verifier package."""
try:
return await asyncio.to_thread(load_latest_ai_agent_post_write_verifier_package)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_post_write_verifier_package_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent post-write verifier package 無效",
) from exc
@router.get(
"/agent-runtime-verifier-evidence-review",
response_model=dict[str, Any],
summary="取得 AI Agent runtime verifier evidence review",
description=(
"讀取最新已提交的 runtime verifier evidence implementation review此端點只回傳 "
"evidence checks、implementation review lanes、redaction policy 與人工操作選項,"
"不實作或執行 verifier、不讀 canonical target、不寫 rollback work item、不發 Telegram、"
"不寫 KM / PlayBook trust / timeline / replay score、不啟動 runtime worker。"
),
)
async def get_agent_runtime_verifier_evidence_review() -> dict[str, Any]:
"""Return the latest read-only AI Agent runtime verifier evidence review."""
try:
return await asyncio.to_thread(load_latest_ai_agent_runtime_verifier_evidence_review)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_runtime_verifier_evidence_review_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent runtime verifier evidence review 無效",
) from exc
@router.get(
"/agent-report-truth-actionability-review",
response_model=dict[str, Any],
summary="取得 AI Agent 報表真相與告警可處置性審查",
description=(
"讀取最新已提交的日報 / 週報 / 月報真相與告警可處置性審查;此端點只回傳 "
"zero-signal findings、cadence contracts、actionability lanes 與人工操作選項,"
"不發 Telegram、不修改 CronJob、不改 Prometheus / Alertmanager、不建立 work item、"
"不寫 KM / PlayBook trust、不啟動 runtime worker。"
),
)
async def get_agent_report_truth_actionability_review() -> dict[str, Any]:
"""Return the latest read-only AI Agent report truth actionability review."""
try:
return await asyncio.to_thread(load_latest_ai_agent_report_truth_actionability_review)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_report_truth_actionability_review_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 報表真相與告警可處置性審查無效",
) from exc
@router.get(
"/agent-report-automation-review",
response_model=dict[str, Any],
summary="取得 AI Agent 日週月報與風險自動化 review",
description=(
"讀取最新已提交的 AI Agent 日報、週報、月報、Agent 工作量、圖表化報告、"
"AI 分析建議與高/中/低風險自動化政策;此端點不排程實發、不送 Telegram、"
"不啟動中低風險自動執行器、不執行生產優化、不讀 secret、不回傳內部工作視窗對話。"
),
)
async def get_agent_report_automation_review() -> dict[str, Any]:
"""Return the latest read-only AI Agent report automation review."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_report_automation_review)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_report_automation_review_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 日週月報與風險自動化 review 無效",
) from exc
@router.get(
"/agent-report-status-board",
response_model=dict[str, Any],
summary="取得 AI Agent 日週月報與工作狀態總覽",
description=(
"讀取最新已提交的 P2-108 AI Agent 日報、週報、月報完成狀態、"
"OpenClaw / Hermes / NemoTron 工作量、圖表化狀態、Telegram 草案與自動優化邊界;"
"此端點不排程實發、不送 Telegram、不寫 Gateway queue、不寫讀報回執、"
"不啟動 AI 分析 worker、不執行生產優化、不讀 secret、不回傳內部協作內容。"
),
)
async def get_agent_report_status_board() -> dict[str, Any]:
"""Return the latest read-only AI Agent report status board."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_report_status_board)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_report_status_board_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 日週月報與工作狀態總覽無效",
) from exc
@router.get(
"/agent-report-source-health",
response_model=dict[str, Any],
summary="取得 AI Agent 報表資料源健康與 no-send preview",
description=(
"回傳日報 / 週報 / 月報資料源健康、全 0 判讀、no-send preview、"
"KM / PlayBook / 腳本 / 排程 / Verifier 沉澱與 report-source-gap 工作項;"
"此端點只做 redacted readback不送 Telegram、不寫 Gateway queue、不改排程、"
"不啟動 AI runtime、不執行中低風險自動修復、不讀 secret。"
),
)
async def get_agent_report_source_health() -> dict[str, Any]:
"""Return the read-only AI Agent report source health model."""
try:
payload = await build_ai_agent_report_source_health()
return redact_public_lan_topology(payload)
except Exception as exc:
logger.error("ai_agent_report_source_health_failed", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 報表資料源健康讀取失敗",
) from exc
@router.get(
"/agent-report-runtime-readiness",
response_model=dict[str, Any],
summary="取得 AI Agent 報表 runtime 啟動前閘門",
description=(
"讀取最新已提交的 P2-403L 日週月報派送、Telegram Gateway queue、讀報回執、"
"AI 讀報後分析、中低風險自動處理、高風險審核與 post-action verifier 啟動前閘門;"
"此端點不排程實發、不送 Telegram、不寫 Gateway queue、不啟動 AI runtime worker、"
"不啟動中低風險 auto worker、不執行生產優化、不讀 secret、不回傳內部對話內容。"
),
)
async def get_agent_report_runtime_readiness() -> dict[str, Any]:
"""Return the latest read-only AI Agent report runtime readiness gate."""
try:
return await asyncio.to_thread(load_latest_ai_agent_report_runtime_readiness)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_report_runtime_readiness_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 報表 runtime 啟動前閘門無效",
) from exc
@router.get(
"/agent-report-runtime-dry-run",
response_model=dict[str, Any],
summary="取得 AI Agent 報表 runtime no-write dry-run 證據包",
description=(
"讀取最新已提交的 P2-403M 報表 runtime no-write dry-run、Telegram Gateway queue 草案、"
"讀報回執 redaction 與 readback verifier 草案;此端點不排程實發、不送 Telegram、"
"不寫 Gateway queue、不寫讀報回執、不啟動 AI runtime worker、不啟動中低風險 auto worker、"
"不執行 verifier live readback、不讀 secret、不回傳內部對話內容。"
),
)
async def get_agent_report_runtime_dry_run() -> dict[str, Any]:
"""Return the latest read-only AI Agent report runtime dry-run package."""
try:
return await asyncio.to_thread(load_latest_ai_agent_report_runtime_dry_run)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_report_runtime_dry_run_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 報表 runtime no-write dry-run 證據包無效",
) from exc
@router.get(
"/agent-report-runtime-fixture-readback",
response_model=dict[str, Any],
summary="取得 AI Agent 報表 runtime fixture readback 證據包",
description=(
"讀取最新已提交的 P2-403N fixture smoke、Telegram Gateway queue preview readback "
"與 verifier dry-run 證據包;此端點不排程實發、不送 Telegram、不呼叫 Bot API、"
"不寫 Gateway queue、不寫讀報回執、不啟動 AI runtime worker、不啟動中低風險 auto worker、"
"不執行 verifier live readback、不寫 production target、不讀 secret、不回傳內部對話內容。"
),
)
async def get_agent_report_runtime_fixture_readback() -> dict[str, Any]:
"""Return the latest read-only AI Agent fixture readback package."""
try:
return await asyncio.to_thread(load_latest_ai_agent_report_runtime_fixture_readback)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_report_runtime_fixture_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 報表 runtime fixture readback 證據包無效",
) from exc
@router.get(
"/agent-runtime-worker-shadow-gate",
response_model=dict[str, Any],
summary="取得 AI Agent runtime worker shadow/no-write 證據閘門",
description=(
"讀取最新已提交的 P2-404 runtime worker shadow / no-write execution evidence gate"
"此端點只回傳 shadow candidate、no-write replay、verifier shadow case 與 operator checkpoint"
"不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫讀報回執、不啟動 live AI runtime worker、"
"不啟動中低風險 auto worker、不執行 verifier live readback、不寫 production target、不讀 secret。"
),
)
async def get_agent_runtime_worker_shadow_gate() -> dict[str, Any]:
"""Return the latest read-only AI Agent runtime worker shadow gate."""
try:
return await asyncio.to_thread(load_latest_ai_agent_runtime_worker_shadow_gate)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_runtime_worker_shadow_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent runtime worker shadow/no-write 證據閘門無效",
) from exc
@router.get(
"/agent-operation-permission-model",
response_model=dict[str, Any],
summary="取得 AI Agent 操作類別權限模型",
description=(
"讀取最新已提交的 P2-101 操作類別權限模型;此端點只回傳 permission lane、"
"operation category、Agent responsibility、gate transition 與 operator template"
"不啟動 runtime worker、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、"
"不寫讀報回執、不執行 verifier live readback、不寫 production target、不讀 secret。"
),
)
async def get_agent_operation_permission_model() -> dict[str, Any]:
"""Return the latest read-only AI Agent operation permission model."""
try:
return await asyncio.to_thread(load_latest_ai_agent_operation_permission_model)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_operation_permission_model_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 操作類別權限模型無效",
) from exc
@router.get(
"/agent-candidate-operation-dry-run-evidence",
response_model=dict[str, Any],
summary="取得 AI Agent 候選操作 dry-run 證據",
description=(
"讀取最新已提交的 P2-102 候選操作 dry-run 證據;此端點只回傳 candidate operation、"
"dry-run evidence hash、side-effect count、verifier plan、gate requirement 與 operator handoff"
"不啟動 runtime worker、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、"
"不寫讀報回執、不執行 verifier live readback、不寫 production target、不讀 secret。"
),
)
async def get_agent_candidate_operation_dry_run_evidence() -> dict[str, Any]:
"""Return the latest read-only AI Agent candidate operation dry-run evidence."""
try:
return await asyncio.to_thread(load_latest_ai_agent_candidate_operation_dry_run_evidence)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_candidate_operation_dry_run_evidence_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 候選操作 dry-run 證據無效",
) from exc
@router.get(
"/agent-task-result-audit-trail",
response_model=dict[str, Any],
summary="取得 AI Agent 任務結果稽核軌跡",
description=(
"讀取最新已提交的 P2-103 任務結果稽核軌跡;此端點只回傳 result route、"
"KM / LOGBOOK / audit / timeline writeback contract、operator handoff 與 redaction boundary"
"不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不寫 timeline、不更新 PlayBook trust、"
"不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production target、不讀 secret。"
),
)
async def get_agent_task_result_audit_trail() -> dict[str, Any]:
"""Return the latest read-only AI Agent task result audit trail contract."""
try:
return await asyncio.to_thread(load_latest_ai_agent_task_result_audit_trail)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_task_result_audit_trail_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 任務結果稽核軌跡無效",
) from exc
@router.get(
"/agent-matched-playbook-learning-gap",
response_model=dict[str, Any],
summary="取得 AI Agent matched PlayBook 學習缺口",
description=(
"讀取最新已提交的 P2-104 matched PlayBook 學習缺口;此端點只回傳 production DB 只讀回查摘要、"
"learning gap、gate、writeback candidate 與 redaction boundary"
"不寫 learning、不更新 PlayBook trust、不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不寫 timeline、"
"不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production target、不讀 secret。"
),
)
async def get_agent_matched_playbook_learning_gap() -> dict[str, Any]:
"""Return the latest read-only AI Agent matched PlayBook learning gap contract."""
try:
return await asyncio.to_thread(load_latest_ai_agent_matched_playbook_learning_gap)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_matched_playbook_learning_gap_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent matched PlayBook 學習缺口無效",
) from exc
@router.get(
"/agent-critic-reviewer-result-capture",
response_model=dict[str, Any],
summary="取得 AI Agent critic / reviewer result capture 契約",
description=(
"讀取最新已提交的 P2-105 critic / reviewer 評分與 result capture 契約;"
"此端點只回傳 scorecard、result capture contract、promotion gate、candidate route 與 redaction boundary"
"不寫 learning、不更新 PlayBook trust、不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不寫 timeline、"
"不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production target、不讀 secret。"
),
)
async def get_agent_critic_reviewer_result_capture() -> dict[str, Any]:
"""Return the latest read-only critic / reviewer result capture contract."""
try:
return await asyncio.to_thread(load_latest_ai_agent_critic_reviewer_result_capture)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_critic_reviewer_result_capture_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent critic / reviewer result capture 契約無效",
) from exc
@router.get(
"/agent-owner-approved-result-capture-dry-run",
response_model=dict[str, Any],
summary="取得 AI Agent owner-approved result capture dry-run",
description=(
"讀取最新已提交的 P2-106 owner-approved result capture dry-run"
"此端點只回傳 owner approval packet、no-write dry-run template、score fixture、"
"dry-run gate 與 operator action"
"不寫 score、不寫 result capture、不寫 learning、不更新 PlayBook trust、不寫 KM、"
"不寫 audit DB、不寫 timeline、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、"
"不寫 production target、不讀 secret。"
),
)
async def get_agent_owner_approved_result_capture_dry_run() -> dict[str, Any]:
"""Return the latest read-only owner-approved result capture dry-run contract."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_owner_approved_result_capture_dry_run)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_owner_approved_result_capture_dry_run_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent owner-approved result capture dry-run 無效",
) from exc
@router.get(
"/agent-owner-approved-result-capture-readback",
response_model=dict[str, Any],
summary="取得 AI Agent owner-approved result capture readback",
description=(
"讀取最新已提交的 P2-107 owner-approved result capture readback"
"此端點只回傳 result capture readback digest、promotion readiness review、failure lane、"
"reviewer queue preview 與 operator action"
"不讀 canonical runtime target、不寫 score、不寫 result capture、不寫 learning、不更新 PlayBook trust、"
"不寫 reviewer queue、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production target、不讀 secret。"
),
)
async def get_agent_owner_approved_result_capture_readback() -> dict[str, Any]:
"""Return the latest read-only owner-approved result capture readback contract."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_owner_approved_result_capture_readback)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_owner_approved_result_capture_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent owner-approved result capture readback 無效",
) from exc
@router.get(
"/agent-runtime-readback-approval-package",
response_model=dict[str, Any],
summary="取得 AI Agent runtime readback 批准包",
description=(
"讀取最新已提交的 P2-109 runtime readback approval package"
"此端點只回傳 approval packet、canonical readback plan、rollback drill、"
"Telegram 失敗收據 gate 與 operator action"
"不讀 canonical runtime target、不寫 score、不寫 result capture、不寫 learning、不更新 PlayBook trust、"
"不寫 reviewer queue、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 rollback work item、"
"不寫 production target、不讀 secret。"
),
)
async def get_agent_runtime_readback_approval_package() -> dict[str, Any]:
"""Return the latest read-only runtime readback approval package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_runtime_readback_approval_package)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_runtime_readback_approval_package_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent runtime readback approval package 無效",
) from exc
@router.get(
"/agent-runtime-readback-implementation-review",
response_model=dict[str, Any],
summary="取得 AI Agent runtime readback 實作審查",
description=(
"讀取最新已提交的 P2-110 runtime readback implementation review"
"此端點只回傳 implementation review card、no-write verifier、阻塞原因與 operator action"
"不讀 canonical runtime target、不做 live query、不寫 score、不寫 result capture、不寫 learning、"
"不更新 PlayBook trust、不寫 reviewer queue、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、"
"不寫 rollback work item、不寫 production target、不讀 secret。"
),
)
async def get_agent_runtime_readback_implementation_review() -> dict[str, Any]:
"""Return the latest read-only runtime readback implementation review."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_runtime_readback_implementation_review)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_runtime_readback_implementation_review_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent runtime readback implementation review 無效",
) from exc
@router.get(
"/agent-report-live-delivery-approval-package",
response_model=dict[str, Any],
summary="取得 AI Agent report live delivery 批准包",
description=(
"讀取最新已提交的 P2-111 report live delivery approval package"
"此端點只回傳日報、週報、月報、失敗限定摘要與讀報回執的實發批准包、"
"route lock、payload redaction、no-send receipt 與 operator action"
"不排程、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 report receipt、"
"不啟動 AI analysis、不做中低風險自動優化、不寫 production target、不讀 secret。"
),
)
async def get_agent_report_live_delivery_approval_package() -> dict[str, Any]:
"""Return the latest read-only report live delivery approval package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_report_live_delivery_approval_package)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_report_live_delivery_approval_package_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent report live delivery approval package 無效",
) from exc
@router.get(
"/agent-runtime-readback-fixture-approval",
response_model=dict[str, Any],
summary="取得 AI Agent runtime readback fixture 批准包",
description=(
"讀取最新已提交的 P2-112 runtime readback fixture approval package"
"此端點只回傳 fixture approval card、adapter contract、verifier fixture、"
"blocker mapping 與 operator action不讀 canonical runtime target、不做 live query、"
"不執行 runtime readback、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、"
"不寫 report receipt、不寫 result capture、不寫 production target、不讀 secret。"
),
)
async def get_agent_runtime_readback_fixture_approval() -> dict[str, Any]:
"""Return the latest read-only runtime readback fixture approval package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_runtime_readback_fixture_approval)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_runtime_readback_fixture_approval_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent runtime readback fixture approval 無效",
) from exc
@router.get(
"/agent-runtime-readback-promotion-gate",
response_model=dict[str, Any],
summary="取得 AI Agent runtime readback promotion gate",
description=(
"讀取最新已提交的 P2-113 runtime readback promotion gate"
"此端點只回傳 failure receipt、reviewer queue、result capture 的 no-write promotion "
"lane、preview、verifier 與 blocker不讀 canonical runtime target、不做 live query、"
"不寫 reviewer queue、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、"
"不寫 report receipt、不寫 result capture、不寫 learning / PlayBook trust、不讀 secret。"
),
)
async def get_agent_runtime_readback_promotion_gate() -> dict[str, Any]:
"""Return the latest read-only runtime readback promotion gate."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_runtime_readback_promotion_gate)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_runtime_readback_promotion_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent runtime readback promotion gate 無效",
) from exc
@router.get(
"/agent-owner-approved-fixture-promotion-gate",
response_model=dict[str, Any],
summary="取得 AI Agent owner-approved fixture promotion gate",
description=(
"讀取最新已提交的 P2-114 owner-approved fixture promotion gate"
"此端點只回傳 owner approval packet、acceptance template、fixture review、"
"no-write verifier 與 blocked promotion不讀 canonical runtime target、不做 live query、"
"不寫 reviewer queue、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、"
"不寫 report receipt、不寫 result capture、不寫 learning / PlayBook trust、不讀 secret。"
),
)
async def get_agent_owner_approved_fixture_promotion_gate() -> dict[str, Any]:
"""Return the latest read-only owner-approved fixture promotion gate."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_owner_approved_fixture_promotion_gate)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_owner_approved_fixture_promotion_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent owner-approved fixture promotion gate 無效",
) from exc
@router.get(
"/agent-canonical-runtime-readback-owner-acceptance",
response_model=dict[str, Any],
summary="取得 AI Agent canonical runtime readback owner acceptance",
description=(
"讀取最新已提交的 P2-115 canonical runtime readback owner acceptance"
"此端點只回傳 owner acceptance package、canonical target scope、no-live verifier、"
"blocked acceptance 與 operator handoff不讀 canonical runtime target、不做 live query、"
"不寫 acceptance record、不寫 reviewer queue、不寫 Gateway queue、不送 Telegram、"
"不呼叫 Bot API、不寫 result capture、不寫 learning / PlayBook trust、不讀 secret。"
),
)
async def get_agent_canonical_runtime_readback_owner_acceptance() -> dict[str, Any]:
"""Return the latest read-only canonical runtime readback owner acceptance."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_canonical_runtime_readback_owner_acceptance)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_canonical_runtime_readback_owner_acceptance_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent canonical runtime readback owner acceptance 無效",
) from exc
@router.get(
"/agent-failure-receipt-no-send-replay",
response_model=dict[str, Any],
summary="取得 AI Agent failure receipt no-send replay",
description=(
"讀取最新已提交的 P2-116 failure receipt no-send replay"
"此端點只回傳 no-send replay fixture、SRE 戰情室 route lock、redaction verifier、"
"blocked send 與 operator handoff不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、"
"不寫 reviewer queue、不寫 report receipt、不寫 result capture、不寫 learning / PlayBook trust、"
"不讀 canonical runtime target、不讀 secret。"
),
)
async def get_agent_failure_receipt_no_send_replay() -> dict[str, Any]:
"""Return the latest read-only failure receipt no-send replay package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_failure_receipt_no_send_replay)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_failure_receipt_no_send_replay_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent failure receipt no-send replay 無效",
) from exc
@router.get(
"/agent-reviewer-queue-no-write-readback",
response_model=dict[str, Any],
summary="取得 AI Agent reviewer queue no-write readback",
description=(
"讀取最新已提交的 P2-117 reviewer queue no-write readback"
"此端點只回傳 reviewer queue preview fixture、queue item mapping、no-write verifier、"
"blocked queue write 與 operator handoff不寫 reviewer queue、不寫 Gateway queue、"
"不送 Telegram、不呼叫 Bot API、不寫 report receipt / result capture / learning / PlayBook trust、"
"不讀 canonical runtime target、不讀 secret。"
),
)
async def get_agent_reviewer_queue_no_write_readback() -> dict[str, Any]:
"""Return the latest read-only reviewer queue no-write readback package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_reviewer_queue_no_write_readback)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_reviewer_queue_no_write_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent reviewer queue no-write readback 無效",
) from exc
@router.get(
"/agent-result-capture-no-write-readback",
response_model=dict[str, Any],
summary="取得 AI Agent result capture no-write readback",
description=(
"讀取最新已提交的 P2-118 result capture no-write readback"
"此端點只回傳 result capture preview fixture、capture field mapping、no-write verifier、"
"blocked result capture write 與 operator handoff不寫 result capture、learning、"
"PlayBook trust、Gateway queue不送 Telegram、不呼叫 Bot API、不讀 canonical runtime target、"
"不讀 secret。"
),
)
async def get_agent_result_capture_no_write_readback() -> dict[str, Any]:
"""Return the latest read-only result capture no-write readback package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_no_write_readback)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_no_write_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture no-write readback 無效",
) from exc
@router.get(
"/agent-result-capture-promotion-approval-gate",
response_model=dict[str, Any],
summary="取得 AI Agent result capture promotion approval gate",
description=(
"讀取最新已提交的 P2-119 result capture promotion approval gate"
"此端點只回傳 promotion approval packet、acceptance template、verifier、"
"blocked promotion write 與 operator handoff不寫 result capture、learning、"
"PlayBook trust、Gateway queue不送 Telegram、不呼叫 Bot API、不讀 canonical runtime target、"
"不讀 secret。"
),
)
async def get_agent_result_capture_promotion_approval_gate() -> dict[str, Any]:
"""Return the latest read-only result capture promotion approval gate package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_promotion_approval_gate)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_promotion_approval_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture promotion approval gate 無效",
) from exc
@router.get(
"/agent-owner-approved-result-capture-promotion-dry-run",
response_model=dict[str, Any],
summary="取得 AI Agent owner-approved result capture promotion dry-run",
description=(
"讀取最新已提交的 P2-120 owner-approved result capture promotion dry-run"
"此端點只回傳 dry-run template、owner acceptance fixture、verifier、blocked runtime promotion "
"與 operator handoff不寫 result capture、learning、PlayBook trust、Gateway queue"
"不送 Telegram、不呼叫 Bot API、不讀 canonical runtime target、不讀 secret。"
),
)
async def get_agent_owner_approved_result_capture_promotion_dry_run() -> dict[str, Any]:
"""Return the latest read-only owner-approved result capture promotion dry-run package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_owner_approved_result_capture_promotion_dry_run)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_owner_approved_result_capture_promotion_dry_run_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent owner-approved result capture promotion dry-run 無效",
) from exc
@router.get(
"/agent-result-capture-write-gate-review",
response_model=dict[str, Any],
summary="取得 AI Agent result capture write gate review",
description=(
"讀取最新已提交的 P2-121 result capture write gate review"
"此端點只回傳 writer gate、approval gate、post-write verifier、blocked live write "
"與 operator handoff不寫 result capture、learning、PlayBook trust、reviewer queue、"
"Gateway queue不送 Telegram、不呼叫 Bot API、不讀 canonical runtime target、不讀 secret。"
),
)
async def get_agent_result_capture_write_gate_review() -> dict[str, Any]:
"""Return the latest read-only result capture write gate review package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_write_gate_review)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_write_gate_review_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture write gate review 無效",
) from exc
@router.get(
"/agent-result-capture-writer-implementation-review",
response_model=dict[str, Any],
summary="取得 AI Agent result capture writer implementation review",
description=(
"讀取最新已提交的 P2-122 result capture writer implementation review"
"此端點只回傳 writer implementation、implementation gate、post-implementation verifier、"
"blocked runtime change 與 operator handoff不套用 writer、不寫 result capture、learning、"
"PlayBook trust、reviewer queue、Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_writer_implementation_review() -> dict[str, Any]:
"""Return the latest read-only result capture writer implementation review package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_writer_implementation_review)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_writer_implementation_review_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture writer implementation review 無效",
) from exc
@router.get(
"/agent-result-capture-writer-dry-run-fixture",
response_model=dict[str, Any],
summary="取得 AI Agent result capture writer dry-run fixture",
description=(
"讀取最新已提交的 P2-123 result capture writer dry-run fixture"
"此端點只回傳 writer dry-run fixture、receipt preview、idempotency replay、"
"rollback rehearsal、blocked runtime write 與 operator handoff不套用 writer、"
"不寫 result capture、learning、PlayBook trust、reviewer queue、Gateway queue"
"不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_writer_dry_run_fixture() -> dict[str, Any]:
"""Return the latest read-only result capture writer dry-run fixture package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_writer_dry_run_fixture)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_writer_dry_run_fixture_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture writer dry-run fixture 無效",
) from exc
@router.get(
"/agent-result-capture-writer-dry-run-readback",
response_model=dict[str, Any],
summary="取得 AI Agent result capture writer dry-run readback",
description=(
"讀取最新已提交的 P2-124 result capture writer dry-run readback"
"此端點只回傳 dry-run readback、receipt verifier、promotion readiness、"
"blocked promotion write 與 operator handoff不套用 writer、不執行 dry-run、"
"不寫 receipt、不寫 result capture、learning、PlayBook trust、reviewer queue、"
"Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_writer_dry_run_readback() -> dict[str, Any]:
"""Return the latest read-only result capture writer dry-run readback package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_writer_dry_run_readback)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_writer_dry_run_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture writer dry-run readback 無效",
) from exc
@router.get(
"/agent-result-capture-owner-promotion-review",
response_model=dict[str, Any],
summary="取得 AI Agent result capture owner promotion review",
description=(
"讀取最新已提交的 P2-125 result capture owner promotion review"
"此端點只回傳 owner promotion packet、execution gate、rollback owner review、"
"blocked execution write 與 operator handoff不套用 writer、不執行 live apply、"
"不寫 receipt、不寫 result capture、learning、PlayBook trust、reviewer queue、"
"Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_owner_promotion_review() -> dict[str, Any]:
"""Return the latest read-only result capture owner promotion review package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_owner_promotion_review)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_owner_promotion_review_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture owner promotion review 無效",
) from exc
@router.get(
"/agent-result-capture-owner-approved-execution-rehearsal",
response_model=dict[str, Any],
summary="取得 AI Agent result capture owner-approved execution rehearsal",
description=(
"讀取最新已提交的 P2-126 owner-approved execution rehearsal"
"此端點只回傳 no-write execution rehearsal、apply gate、verifier rehearsal、"
"rollback drill、blocked live apply 與 operator handoff不套用 writer、不執行 live apply、"
"不寫 receipt、不寫 result capture、learning、PlayBook trust、reviewer queue、"
"Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_owner_approved_execution_rehearsal() -> dict[str, Any]:
"""Return the latest read-only owner-approved execution rehearsal package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_owner_approved_execution_rehearsal)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_owner_approved_execution_rehearsal_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture owner-approved execution rehearsal 無效",
) from exc
@router.get(
"/agent-result-capture-owner-acceptance-maintenance-gate",
response_model=dict[str, Any],
summary="取得 AI Agent result capture owner acceptance maintenance gate",
description=(
"讀取最新已提交的 P2-127 owner acceptance / maintenance gate"
"此端點只回傳 owner acceptance packet、maintenance window、rollback owner、"
"post-apply verifier gate、blocked live write 與 operator handoff不套用 writer、"
"不執行 live apply、不寫 receipt、不寫 result capture、learning、PlayBook trust、"
"reviewer queue、Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_owner_acceptance_maintenance_gate() -> dict[str, Any]:
"""Return the latest read-only owner acceptance / maintenance gate package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_owner_acceptance_maintenance_gate)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_owner_acceptance_maintenance_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture owner acceptance maintenance gate 無效",
) from exc
@router.get(
"/agent-result-capture-owner-acceptance-readback-preflight-hold",
response_model=dict[str, Any],
summary="取得 AI Agent result capture owner acceptance readback preflight hold",
description=(
"讀取最新已提交的 P2-128 owner acceptance readback / preflight hold"
"此端點只回傳 owner acceptance readback、live-apply preflight hold、"
"live apply hold gate、rollback preflight、blocked apply transition 與 operator handoff"
"不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、learning、PlayBook trust、"
"reviewer queue、Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_owner_acceptance_readback_preflight_hold() -> dict[str, Any]:
"""Return the latest read-only owner acceptance readback / preflight hold package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_owner_acceptance_readback_preflight_hold)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_owner_acceptance_readback_preflight_hold_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture owner acceptance readback preflight hold 無效",
) from exc
@router.get(
"/agent-result-capture-owner-approved-preflight-release-package",
response_model=dict[str, Any],
summary="取得 AI Agent result capture owner-approved preflight release package",
description=(
"讀取最新已提交的 P2-129 owner-approved preflight release package"
"此端點只回傳 owner-approved release package、release preflight check、"
"live apply release gate、rollback release check、blocked release transition 與 operator handoff"
"不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、learning、PlayBook trust、"
"reviewer queue、Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_owner_approved_preflight_release_package() -> dict[str, Any]:
"""Return the latest read-only owner-approved preflight release package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_owner_approved_preflight_release_package)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_owner_approved_preflight_release_package_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture owner-approved preflight release package 無效",
) from exc
@router.get(
"/agent-result-capture-owner-approved-release-readiness-readback",
response_model=dict[str, Any],
summary="取得 AI Agent result capture owner-approved release readiness readback",
description=(
"讀取最新已提交的 P2-130 owner-approved release readiness readback"
"此端點只回傳 release readiness readback、owner release readiness check、"
"live apply readiness gate、rollback readiness check、blocked readiness transition 與 operator handoff"
"不批准 owner release、不批准 maintenance window、不釋放 live apply、不套用 writer、不寫 receipt、"
"不寫 result capture、learning、PlayBook trust、reviewer queue、Gateway queue不送 Telegram、"
"不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_owner_approved_release_readiness_readback() -> dict[str, Any]:
"""Return the latest read-only owner-approved release readiness readback."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_owner_approved_release_readiness_readback)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_owner_approved_release_readiness_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture owner-approved release readiness readback 無效",
) from exc
@router.get(
"/agent-result-capture-owner-release-approval-gate",
response_model=dict[str, Any],
summary="取得 AI Agent result capture owner release approval gate",
description=(
"讀取最新已提交的 P2-131 owner release approval gate"
"此端點只回傳 owner release approval packet、maintenance window gate、"
"live apply approval gate、rollback owner approval check、blocked approval transition 與 operator handoff"
"不批准 owner release、不批准 maintenance window、不釋放 live apply、不套用 writer、不寫 receipt、"
"不寫 result capture、learning、PlayBook trust、reviewer queue、Gateway queue不送 Telegram、"
"不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_owner_release_approval_gate() -> dict[str, Any]:
"""Return the latest read-only owner release approval gate."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_owner_release_approval_gate)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_owner_release_approval_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture owner release approval gate 無效",
) from exc
@router.get(
"/agent-result-capture-post-release-verifier-rollback-gate",
response_model=dict[str, Any],
summary="取得 AI Agent result capture post-release verifier rollback gate",
description=(
"讀取最新已提交的 P2-132 post-release verifier / rollback gate"
"此端點只回傳 post-release verifier gate、rollback release gate、release verification hold、"
"live apply post-release gate、blocked post-release transition 與 operator handoff"
"不批准 owner release、不批准 maintenance window、不確認 rollback owner、不釋放 live apply、"
"不套用 writer、不寫 receipt、不寫 result capture、learning、PlayBook trust、reviewer queue、"
"Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_post_release_verifier_rollback_gate() -> dict[str, Any]:
"""Return the latest read-only post-release verifier / rollback gate."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_post_release_verifier_rollback_gate)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_post_release_verifier_rollback_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture post-release verifier rollback gate 無效",
) from exc
@router.get(
"/agent-result-capture-final-release-candidate-readback",
response_model=dict[str, Any],
summary="取得 AI Agent result capture final release candidate readback",
description=(
"讀取最新已提交的 P2-133 final release candidate readback"
"此端點只回傳 final release candidate readback、rollback candidate readback、candidate acceptance hold、"
"live apply candidate hold、blocked final candidate transition 與 operator handoff"
"不批准 owner release、不批准 maintenance window、不確認 rollback owner、不通過 final candidate、"
"不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、learning、PlayBook trust、"
"reviewer queue、Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_final_release_candidate_readback() -> dict[str, Any]:
"""Return the latest read-only final release candidate readback."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_final_release_candidate_readback)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_final_release_candidate_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture final release candidate readback 無效",
) from exc
@router.get(
"/agent-result-capture-release-authorization-hold",
response_model=dict[str, Any],
summary="取得 AI Agent result capture release authorization hold",
description=(
"讀取最新已提交的 P2-134 release authorization hold"
"此端點只回傳 release authorization hold、rollback authorization hold、release window hold、"
"live apply authorization hold、blocked authorization transition 與 operator handoff"
"不授權 owner release、不批准 maintenance window、不確認 rollback owner、不通過 release authorization、"
"不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、learning、PlayBook trust、"
"reviewer queue、Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_release_authorization_hold() -> dict[str, Any]:
"""Return the latest read-only release authorization hold."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_release_authorization_hold)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_release_authorization_hold_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture release authorization hold 無效",
) from exc
@router.get(
"/agent-result-capture-release-authorization-readback-gate",
response_model=dict[str, Any],
summary="取得 AI Agent result capture release authorization readback gate",
description=(
"讀取最新已提交的 P2-135 release authorization readback gate"
"此端點只回傳 release authorization readback、rollback release readback、maintenance window readback hold、"
"live apply release readback hold、blocked release readback transition 與 operator handoff"
"不授權 owner release、不批准 maintenance window、不確認 rollback owner、不通過 release authorization、"
"不釋放 rollback release 或 live apply、不套用 writer、不寫 receipt、不寫 result capture、learning、PlayBook trust、"
"reviewer queue、Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_release_authorization_readback_gate() -> dict[str, Any]:
"""Return the latest read-only release authorization readback gate."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_release_authorization_readback_gate)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_release_authorization_readback_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture release authorization readback gate 無效",
) from exc
@router.get(
"/agent-result-capture-release-verifier-preflight-gate",
response_model=dict[str, Any],
summary="取得 AI Agent result capture release verifier preflight gate",
description=(
"讀取最新已提交的 P2-136 release verifier preflight gate"
"此端點只回傳 release verifier preflight、rollback verifier preflight、maintenance window verifier hold、"
"live apply verifier hold、blocked verifier preflight transition 與 operator handoff"
"不授權 owner release、不批准 maintenance window、不確認 rollback owner、不通過 release authorization、"
"不釋放 rollback release 或 live apply、不套用 writer、不寫 receipt、不寫 result capture、learning、PlayBook trust、"
"reviewer queue、Gateway queue不送 Telegram、不呼叫 Bot API、不讀 secret。"
),
)
async def get_agent_result_capture_release_verifier_preflight_gate() -> dict[str, Any]:
"""Return the latest read-only release verifier preflight gate."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_release_verifier_preflight_gate)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_release_verifier_preflight_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture release verifier preflight gate 無效",
) from exc
@router.get(
"/agent-result-capture-release-verifier-owner-review-packet",
response_model=dict[str, Any],
summary="取得 AI Agent result capture release verifier owner review packet",
description=(
"讀取最新已提交的 P2-137 release verifier owner review packet"
"此端點只回傳 owner review packet、verifier review packet、rollback owner review、maintenance window review hold、"
"live apply owner review hold、blocked owner review transition 與 operator action"
"不授權 owner release、不批准維護窗口、不確認 rollback owner、不通過 post-release verifier、"
"不核發或通過 release authorization、不釋放 rollback release 或 live apply、不套用 writer、"
"不寫 receipt、result capture、learning、PlayBook trust、reviewer queue 或 Gateway queue"
"不送 Telegram、不呼叫 Bot API、不讀 secret、不執行 production 寫入。"
),
)
async def get_agent_result_capture_release_verifier_owner_review_packet() -> dict[str, Any]:
"""Return the latest read-only release verifier owner review packet."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_release_verifier_owner_review_packet)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_release_verifier_owner_review_packet_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture release verifier owner review packet 無效",
) from exc
@router.get(
"/agent-result-capture-release-decision-hold",
response_model=dict[str, Any],
summary="取得 AI Agent result capture release decision hold",
description=(
"讀取最新已提交的 P2-138 release decision hold"
"此端點只回傳 release decision hold、owner / verifier / rollback / live apply decision hold、"
"blocked decision transition 與 operator action"
"不把 owner review packet 視為決策通過、不授權 owner release、不通過 release decision、"
"不核發或通過 release authorization、不釋放 rollback release 或 live apply、不套用 writer、"
"不寫 reviewer queue、Gateway queue、receipt、result capture、learning 或 PlayBook trust"
"不送 Telegram、不呼叫 Bot API、不讀 secret、不執行 production 寫入。"
),
)
async def get_agent_result_capture_release_decision_hold() -> dict[str, Any]:
"""Return the latest read-only release decision hold."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_release_decision_hold)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_release_decision_hold_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture release decision hold 無效",
) from exc
@router.get(
"/agent-result-capture-release-decision-readback",
response_model=dict[str, Any],
summary="取得 AI Agent result capture release decision readback",
description=(
"讀取最新已提交的 P2-139 release decision readback"
"此端點只回讀 P2-138 release decision hold 後的釋出、負責人、驗證器、回滾、"
"維護窗口與正式套用決策狀態,"
"不把 hold 視為決策通過、不授權 owner release、不核發 release authorization、"
"不寫 reviewer queue、Gateway queue、receipt、result capture、learning 或 PlayBook trust"
"不送 Telegram、不呼叫 Bot API、不讀 secret、不執行 production 寫入。"
),
)
async def get_agent_result_capture_release_decision_readback() -> dict[str, Any]:
"""Return the latest read-only release decision readback."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_release_decision_readback)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_release_decision_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture release decision readback 無效",
) from exc
@router.get(
"/agent-result-capture-release-decision-next-handoff",
response_model=dict[str, Any],
summary="取得 AI Agent result capture release decision next handoff",
description=(
"讀取最新已提交的 P2-140 release decision next handoff"
"此端點只回讀 P2-139 release decision readback 的下一關交接,隔離 P2-139 自我迴圈提示,"
"不把 handoff 視為 owner approval、不核發 release authorization、"
"不寫 reviewer queue、Gateway queue、receipt、result capture、learning 或 PlayBook trust"
"不送 Telegram、不呼叫 Bot API、不讀 secret、不執行 production 寫入。"
),
)
async def get_agent_result_capture_release_decision_next_handoff() -> dict[str, Any]:
"""Return the latest read-only release decision next-handoff readback."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_release_decision_next_handoff)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_release_decision_next_handoff_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture release decision next handoff 無效",
) from exc
@router.get(
"/agent-result-capture-release-decision-input-prep",
response_model=dict[str, Any],
summary="取得 AI Agent result capture release decision input prep",
description=(
"讀取最新已提交的 P2-141 release decision input prep"
"此端點只把 P2-140 next handoff 轉成 owner / verifier 決策輸入準備包,"
"不把準備包視為 owner approval、不核發 release authorization、"
"不寫 reviewer queue、Gateway queue、receipt、result capture、learning 或 PlayBook trust"
"不送 Telegram、不呼叫 Bot API、不讀 secret、不執行 production 寫入。"
),
)
async def get_agent_result_capture_release_decision_input_prep() -> dict[str, Any]:
"""Return the latest read-only release decision input-prep package."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_release_decision_input_prep)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_release_decision_input_prep_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture release decision input prep 無效",
) from exc
@router.get(
"/agent-result-capture-release-decision-owner-response-preflight",
response_model=dict[str, Any],
summary="取得 AI Agent result capture release decision owner response preflight",
description=(
"讀取最新已提交的 P2-143 release decision owner response preflight"
"此端點只把 P2-141 決策輸入準備包轉成 owner response 預檢與拒收邊界,"
"不把預檢視為正式收件或批准、不核發 release authorization、"
"不寫 reviewer queue、Gateway queue、receipt、result capture、learning 或 PlayBook trust"
"不送 Telegram、不呼叫 Bot API、不讀 secret、不執行 production 寫入。"
),
)
async def get_agent_result_capture_release_decision_owner_response_preflight() -> dict[str, Any]:
"""Return the latest read-only release decision owner-response preflight."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_release_decision_owner_response_preflight)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_release_decision_owner_response_preflight_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture release decision owner response preflight 無效",
) from exc
@router.get(
"/agent-result-capture-release-decision-owner-response-readback",
response_model=dict[str, Any],
summary="取得 AI Agent result capture release decision owner response readback",
description=(
"讀取最新已提交的 P2-144 release decision owner response readback"
"此端點只讀回 P2-143 預檢後的外部 owner response 狀態,"
"不把未收到回覆視為正式收件或批准、不核發 release authorization、"
"不寫 reviewer queue、Gateway queue、receipt、result capture、learning 或 PlayBook trust"
"不送 Telegram、不呼叫 Bot API、不讀 secret、不執行 production 寫入。"
),
)
async def get_agent_result_capture_release_decision_owner_response_readback() -> dict[str, Any]:
"""Return the latest read-only release decision owner-response readback."""
try:
payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_release_decision_owner_response_readback)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_release_decision_owner_response_readback_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture release decision owner response readback 無效",
) from exc
@router.get(
"/agent-result-capture-release-decision-owner-response-acceptance-gate",
response_model=dict[str, Any],
summary="取得 AI Agent result capture release decision owner response acceptance gate",
description=(
"讀取最新已提交的 P2-145 release decision owner response acceptance gate"
"此端點只建立 P2-144 readback 後的驗收門檻,"
"不把未收到或未遮罩回覆視為正式收件、接受、拒絕或 release authorization"
"不寫 reviewer queue、Gateway queue、receipt、result capture、learning 或 PlayBook trust"
"不送 Telegram、不呼叫 Bot API、不讀 secret、不執行 production 寫入。"
),
)
async def get_agent_result_capture_release_decision_owner_response_acceptance_gate() -> dict[str, Any]:
"""Return the latest read-only release decision owner-response acceptance gate."""
try:
payload = await asyncio.to_thread(
load_latest_ai_agent_result_capture_release_decision_owner_response_acceptance_gate
)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_result_capture_release_decision_owner_response_acceptance_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent result capture release decision owner response acceptance gate 無效",
) from exc
@router.get(
"/agent-owner-approved-fixture-dry-run",
response_model=dict[str, Any],
summary="取得 AI Agent owner-approved fixture dry-run 批准包",
description=(
"讀取最新已提交的 owner-approved fixture dry-run 批准包;此端點只回傳 fixture-only dry-run 證據,"
"不寫 KM、不更新 PlayBook trust、不寫 timeline / replay score、不寫 Gateway queue、不呼叫 Telegram Bot API、"
"不啟動 runtime worker、不開 Redis consumer group、不執行 DB migration、不觸發 workflow、"
"不執行主機或 cluster 指令、不使用 secrets 或付費 API、不回傳未核准內部細節。"
),
)
async def get_agent_owner_approved_fixture_dry_run() -> dict[str, Any]:
"""Return the latest read-only AI Agent owner-approved fixture dry-run package."""
try:
return await asyncio.to_thread(load_latest_ai_agent_owner_approved_fixture_dry_run)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_owner_approved_fixture_dry_run_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent owner-approved fixture dry-run 批准包無效",
) from exc
@router.get(
"/agent-proactive-operations-contract",
response_model=dict[str, Any],
summary="取得 AI Agent 主動營運委派與版本生命週期契約",
description=(
"讀取最新已提交的 AI Agent 主動營運、版本生命週期、可委派能力、MCP、RAG 與 Telegram 邊界契約;"
"此端點不啟用排程、不升級套件、不更新主機、不 pull image、不 auto merge、不送 Telegram、"
"不呼叫付費服務、不修改生產路由。"
),
)
async def get_agent_proactive_operations_contract() -> dict[str, Any]:
"""Return the latest read-only AI Agent proactive operations contract."""
try:
return await asyncio.to_thread(load_latest_ai_agent_proactive_operations_contract)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_proactive_operations_contract_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 主動營運委派與版本生命週期契約無效",
) from exc
@router.get(
"/agent-version-lifecycle-update-proposal",
response_model=dict[str, Any],
summary="取得 AI Agent 版本生命週期更新提案佇列",
description=(
"讀取最新已提交的 AI Agent / 套件 / 工具 / 服務 / 主機版本生命週期更新提案;"
"此端點只回傳已脫敏治理資料與批准 gate不啟用排程、不外查 registry/CVE/市場來源、"
"不升級套件、不寫 lockfile、不 pull/build/push image、不操作 host/K3s/stateful、"
"不建立 PR、不 auto merge、不送 Telegram、不讀取機密、不切換 provider、"
"不替換 OpenClaw、不修改生產路由。"
),
)
async def get_agent_version_lifecycle_update_proposal() -> dict[str, Any]:
"""Return the latest read-only AI Agent version lifecycle update proposal."""
try:
return await asyncio.to_thread(load_latest_ai_agent_version_lifecycle_update_proposal)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_version_lifecycle_update_proposal_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 版本生命週期更新提案無效",
) from exc
@router.get(
"/agent-version-freshness-snapshot",
response_model=dict[str, Any],
summary="取得 AI Agent repo-only 版本新鮮度快照",
description=(
"讀取最新已提交的 AI Agent repo-only 版本新鮮度快照;此端點不啟用每日排程、"
"不查外部 registry/CVE、不安裝或升級套件、不寫 lockfile、不 build/pull image、"
"不 probe 主機、不建立 PR、不發 Telegram、不呼叫付費服務、不修改生產路由。"
),
)
async def get_agent_version_freshness_snapshot() -> dict[str, Any]:
"""Return the latest read-only AI Agent version freshness snapshot."""
try:
return await asyncio.to_thread(load_latest_ai_agent_version_freshness_snapshot)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_version_freshness_snapshot_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 版本新鮮度快照無效",
) from exc
@router.get(
"/agent-tool-adoption-approval-package",
response_model=dict[str, Any],
summary="取得 AI Agent 工具採用批准包",
description=(
"讀取最新已提交的 Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包;"
"此端點不安裝工具、不寫 CI workflow、不下載漏洞資料庫、不查外部 registry、不升級套件、"
"不寫 lockfile、不 build/pull image、不建立 Gitea PR、不 auto merge、不發 Telegram、"
"不呼叫付費服務、不修改生產路由。"
),
)
async def get_agent_tool_adoption_approval_package() -> dict[str, Any]:
"""Return the latest read-only AI Agent tool adoption approval package."""
try:
return await asyncio.to_thread(load_latest_ai_agent_tool_adoption_approval_package)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_tool_adoption_approval_package_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent 工具採用批准包無效",
) from exc
@router.get(
"/agent-telegram-action-required-digest-policy",
response_model=dict[str, Any],
summary="取得 AI Agent Telegram action-required digest policy",
description=(
"讀取最新已提交的 AI Agent Telegram action-required digest policy"
"此端點只回傳 critical / action-required / failure-only digest 規則與 redaction 邊界,"
"不送 Telegram、不寫 Telegram Gateway queue、不改 Alertmanager route / receiver、"
"不寫 AwoooP event、不觸發 workflow、不查外部掃描、不執行 runtime、不讀取 secret、"
"不回傳內部協作逐字稿。"
),
)
async def get_agent_telegram_action_required_digest_policy() -> dict[str, Any]:
"""Return the latest read-only AI Agent Telegram action-required digest policy."""
try:
return await asyncio.to_thread(load_latest_ai_agent_telegram_action_required_digest_policy)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_telegram_action_required_digest_policy_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent Telegram action-required digest policy 無效",
) from exc
@router.get(
"/agent-gitea-pr-draft-lane",
response_model=dict[str, Any],
summary="取得 AI Agent Gitea PR 草案 lane",
description=(
"讀取最新已提交的 AI Agent Gitea PR 草案 lane"
"此端點只回傳 grouping、automerge=false、測試證據、rollback、owner response 與 redaction 邊界,"
"不 push branch、不建立或更新 Gitea PR、不留言、不 auto merge、不觸發 workflow、不改 CI、"
"不寫 lockfile、不升級套件、不 build/pull image、不改 production route、不發 Telegram、"
"不讀取 secret、不回傳內部協作逐字稿。"
),
)
async def get_agent_gitea_pr_draft_lane() -> dict[str, Any]:
"""Return the latest read-only AI Agent Gitea PR draft lane policy."""
try:
return await asyncio.to_thread(load_latest_ai_agent_gitea_pr_draft_lane)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_gitea_pr_draft_lane_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent Gitea PR 草案 lane 無效",
) from exc
@router.get(
"/agent-host-stateful-version-inventory",
response_model=dict[str, Any],
summary="取得 AI Agent host / K3s / stateful 版本只讀盤點",
description=(
"讀取最新已提交的 AI Agent host OS / K3s / stateful services 版本只讀盤點與 "
"maintenance window 批准包;此端點不 SSH、不執行 host command、不執行 kubectl、"
"不 apt upgrade、不升級 kernel/K3s、不 drain node、不 reboot、不 restart stateful service、"
"不做 DB migration、不刪備份、不 restore、不 pull image、不安裝套件、不查外部版本來源、"
"不 active scan、不發 Telegram、不讀取 secret、不回傳內部協作逐字稿。"
),
)
async def get_agent_host_stateful_version_inventory() -> dict[str, Any]:
"""Return the latest read-only host / K3s / stateful version inventory."""
try:
return await asyncio.to_thread(load_latest_ai_agent_host_stateful_version_inventory)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_host_stateful_version_inventory_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent host / K3s / stateful 版本只讀盤點無效",
) from exc
@router.get(
"/runtime-surface-inventory",
response_model=dict[str, Any],
summary="取得 Runtime surface 只讀盤點",
description=(
"讀取最新已提交的 API / Web / Worker / K8s runtime surface 盤點;"
"此端點不呼叫 live cluster、不碰 DB/Redis、不讀 Secret payload、"
"不執行 rollout/restart/scale/delete、不 patch K8s、不改 workflow、不改生產路由。"
),
)
async def get_runtime_surface_inventory() -> dict[str, Any]:
"""Return the latest read-only runtime surface inventory."""
try:
payload = await asyncio.to_thread(load_latest_runtime_surface_inventory)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("runtime_surface_inventory_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Runtime surface 盤點快照無效",
) from exc
@router.get(
"/gitea-workflow-runner-health",
response_model=dict[str, Any],
summary="取得 Gitea 工作流程與 runner 健康合約",
description=(
"讀取最新已提交的 Gitea workflow / runner health contract"
"此端點不呼叫 Gitea API、不修改 workflow、不重啟 runner、不停止 container、"
"不讀 Secret payload、不送 Telegram 測試通知、不觸發 deploy 或 migration。"
),
)
async def get_gitea_workflow_runner_health() -> dict[str, Any]:
"""Return the latest read-only Gitea workflow / runner health contract."""
try:
return await asyncio.to_thread(load_latest_gitea_workflow_runner_health)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("gitea_workflow_runner_health_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Gitea 工作流程與 runner 健康合約快照無效",
) from exc
@router.get(
"/gitea-workflow-runner-owner-attestation-request",
response_model=dict[str, Any],
summary="取得 Gitea workflow runner owner attestation request",
description=(
"從 Gitea workflow / runner health contract 產生 runner label owner "
"attestation request packet此端點只回傳脫敏 metadata 欄位、驗收規則與禁止事項。"
"它不送出 request、不呼叫 Gitea API、不修改 workflow、不重啟或註冊 runner、"
"不改 runner label、不讀 Secret 或 runner token、不觸發 workflow。"
),
)
async def get_gitea_workflow_runner_owner_attestation_request() -> dict[str, Any]:
"""Return the read-only Gitea runner owner attestation request packet."""
try:
return await asyncio.to_thread(
load_latest_gitea_workflow_runner_owner_attestation_request
)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error(
"gitea_workflow_runner_owner_attestation_request_invalid",
error=str(exc),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Gitea workflow runner owner attestation request 無效",
) from exc
@router.get(
"/observability-contract-matrix",
response_model=dict[str, Any],
summary="取得監控合約與降噪機會矩陣",
description=(
"讀取最新已提交的 Prometheus / Alertmanager / Grafana / SigNoz / ClickHouse / Sentry "
"只讀 observability matrix此端點不修改 alert rules、不呼叫 silence API、"
"不建立 Grafana dashboard、不改 SigNoz / Sentry 設定、不讀 Secret payload、"
"不送 Telegram 測試通知、不觸發 monitoring deploy。"
),
)
async def get_observability_contract_matrix() -> dict[str, Any]:
"""Return the latest read-only observability contract matrix."""
try:
return await asyncio.to_thread(load_latest_observability_contract_matrix)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("observability_contract_matrix_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="監控合約與降噪機會矩陣快照無效",
) from exc
@router.get(
"/ai-provider-route-matrix",
response_model=dict[str, Any],
summary="取得 AI Provider 路由只讀矩陣",
description=(
"讀取最新已提交的 AI Router / Ollama / OpenClaw / Nemotron / Gemini provider route matrix"
"此端點不切換 provider、不呼叫 Gemini / NVIDIA / Claude、不改 USE_AI_ROUTER、"
"不修改 fallback order、不讀 Secret payload、不進 shadow / canary、"
"不觸發 workflow / deploy / reload / runtime execution。"
),
)
async def get_ai_provider_route_matrix() -> dict[str, Any]:
"""Return the latest read-only AI provider route matrix."""
try:
return await asyncio.to_thread(load_latest_ai_provider_route_matrix)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_provider_route_matrix_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Provider 路由只讀矩陣快照無效",
) from exc
@router.get(
"/service-health-gap-matrix",
response_model=dict[str, Any],
summary="取得服務健康缺口與過期端點矩陣",
description=(
"讀取最新已提交的 service health gap matrix此端點不做 live probe、"
"不重啟服務、不修改 endpoint / ConfigMap、不讀 Secret/Redis/DB payload、"
"不發通知、不觸發 workflow/deploy/reload/runtime execution。"
),
)
async def get_service_health_gap_matrix() -> dict[str, Any]:
"""Return the latest read-only service health gap matrix."""
try:
payload = await asyncio.to_thread(load_latest_service_health_gap_matrix)
return redact_public_lan_topology(payload)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("service_health_gap_matrix_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="服務健康缺口矩陣快照無效",
) from exc
@router.get(
"/backup-dr-target-inventory",
response_model=dict[str, Any],
summary="取得 Backup / DR 目標盤點",
description=(
"讀取最新已提交的 Backup / DR 目標盤點;"
"此端點不呼叫外部來源、不執行備份/restore/offsite sync、"
"不寫 credential marker、不改排程、不批准任何破壞性操作。"
),
)
async def get_backup_dr_target_inventory() -> dict[str, Any]:
"""Return the latest read-only Backup / DR target inventory."""
try:
return await asyncio.to_thread(load_latest_backup_dr_target_inventory)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("backup_dr_target_inventory_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Backup / DR target inventory is invalid",
) from exc
@router.get(
"/backup-dr-readiness-matrix",
response_model=dict[str, Any],
summary="取得 Backup / DR 準備度矩陣",
description=(
"讀取最新已提交的 Backup / DR 準備度矩陣;"
"此端點不呼叫外部來源、不執行備份/restore/offsite sync、"
"不寫 credential marker、不改排程、不批准任何破壞性操作。"
),
)
async def get_backup_dr_readiness_matrix() -> dict[str, Any]:
"""Return the latest read-only Backup / DR readiness matrix."""
try:
return await asyncio.to_thread(load_latest_backup_dr_readiness_matrix)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("backup_dr_readiness_matrix_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Backup / DR readiness matrix is invalid",
) from exc
@router.get(
"/credential-escrow-evidence-intake-readiness",
response_model=dict[str, Any],
summary="取得 P0-005 credential escrow evidence intake readiness",
description=(
"讀取已提交的 P0-005 credential escrow evidence intake 只讀投影;"
"此端點只回傳 redacted evidence-ref metadata 與目前缺項,"
"不讀 credential、不寫 escrow marker、不執行 backup/restore/offsite sync、"
"不觸發 workflow、不碰 host/K8s、不讀 raw session/SQLite。"
),
)
async def get_credential_escrow_evidence_intake_readiness() -> dict[str, Any]:
"""Return P0-005 credential escrow evidence intake readiness."""
try:
return await asyncio.to_thread(
load_latest_credential_escrow_evidence_intake_readiness
)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("credential_escrow_evidence_intake_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-005 credential escrow evidence intake readiness 快照無效",
) from exc
@router.post(
"/credential-escrow-evidence-intake-readiness/validate-owner-response",
response_model=dict[str, Any],
summary="驗證 P0-005 credential escrow 脫敏 owner response",
description=(
"針對單次 owner-provided redacted non-secret credential escrow evidence "
"response 進行 no-persist validation此端點只回傳 independent reviewer "
"readiness / needs supplement / quarantined / rejected runtime action 分流,"
"不保存 payload、不讀 credential、不寫 escrow marker、不執行 backup / restore / "
"offsite sync、不觸發 workflow、不碰 host/K8s、不讀 raw session/SQLite。"
),
)
async def validate_credential_escrow_evidence_owner_response_packet(
owner_response: dict[str, Any],
) -> dict[str, Any]:
"""Return no-persist validation for one P0-005 redacted owner response."""
try:
return await asyncio.to_thread(
validate_credential_escrow_evidence_owner_response,
owner_response,
)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("credential_escrow_evidence_owner_response_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-005 credential escrow owner response 驗證器無效",
) from exc
@router.post(
"/credential-escrow-evidence-intake-readiness/validate-evidence-refs",
response_model=dict[str, Any],
summary="驗證 P0-005 credential escrow 脫敏 evidence refs",
description=(
"接收五個 credential escrow item 的 redacted non-secret evidence refs"
"自動轉成既有 owner response preflight 結構並回傳 reviewer readiness"
"此端點不保存 payload、不讀 credential、不寫 escrow marker、不執行 backup / "
"restore / offsite sync、不觸發 workflow、不碰 host/K8s、不讀 raw session/SQLite。"
),
)
async def validate_credential_escrow_evidence_refs_packet(
evidence_refs_payload: dict[str, Any],
) -> dict[str, Any]:
"""Return no-persist validation for simplified P0-005 redacted refs."""
try:
return await asyncio.to_thread(
validate_credential_escrow_evidence_refs,
evidence_refs_payload,
)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("credential_escrow_evidence_refs_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P0-005 credential escrow evidence refs 驗證器無效",
) from exc
@router.get(
"/backup-notification-policy",
response_model=dict[str, Any],
summary="取得備份通知政策",
description=(
"讀取最新已提交的備份通知政策;此端點只回傳 success-noise suppression、"
"failure/action-required 升級與每日摘要合約,不送通知、不執行備份/restore/offsite sync、"
"不寫 credential marker、不改排程、不寫 workflow、不發 Telegram 測試訊息。"
),
)
async def get_backup_notification_policy() -> dict[str, Any]:
"""Return the latest read-only backup notification policy."""
try:
return await asyncio.to_thread(load_latest_backup_notification_policy)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("backup_notification_policy_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="備份通知政策快照無效",
) from exc
@router.get(
"/service-health-failure-notification-policy",
response_model=dict[str, Any],
summary="取得服務健康失敗限定通知合約",
description=(
"讀取最新已提交的 service health failure-only Telegram / AwoooP 通知合約;"
"此端點只回傳成功降噪、action-required 與 failure escalation 規則,"
"不送通知、不做 live probe、不重啟服務、不改 endpoint、不觸發 workflow / runtime execution、"
"不讀取 secret payload、不回傳內部協作逐字稿或提示詞。"
),
)
async def get_service_health_failure_notification_policy() -> dict[str, Any]:
"""Return the latest read-only service health failure-only notification policy."""
try:
return await asyncio.to_thread(load_latest_service_health_failure_notification_policy)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("service_health_failure_notification_policy_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="服務健康失敗限定通知合約快照無效",
) from exc
@router.get(
"/backup-restore-drill-approval-package-template",
response_model=dict[str, Any],
summary="取得 Backup / DR 復原演練批准包模板",
description=(
"讀取最新已提交的 Backup / DR restore drill、credential escrow review、"
"K8s resource recovery、observability recovery 與 route reconstruction 批准包模板;"
"此端點只回傳 read-only template不執行 backup、restore、offsite sync、"
"不寫 credential marker、不改排程、不寫 workflow、不送 Telegram 測試通知、"
"不輸出 secret 明文、不做破壞性 prune、不呼叫付費 API、不建立 shadow/canary、不改生產路由。"
),
)
async def get_backup_restore_drill_approval_package_template() -> dict[str, Any]:
"""Return the latest read-only Backup / DR restore drill approval package template."""
try:
return await asyncio.to_thread(load_latest_backup_restore_drill_approval_package_template)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("backup_restore_drill_approval_package_template_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Backup / DR 復原演練批准包模板快照無效",
) from exc
@router.get(
"/offsite-escrow-readiness-status",
response_model=dict[str, Any],
summary="取得異地 / Escrow 準備度狀態",
description=(
"讀取最新已提交的異地備份、credential escrow 與 K8s resource offsite readiness 狀態;"
"此端點只回傳 read-only status不執行 backup、restore、offsite sync、"
"不寫 credential marker、不讀 credential、不輸出 secret 明文、不改排程、不寫 workflow、"
"不送 Telegram 測試通知、不做破壞性 prune、不改生產路由。"
),
)
async def get_offsite_escrow_readiness_status() -> dict[str, Any]:
"""Return the latest read-only offsite / escrow readiness status."""
try:
return await asyncio.to_thread(load_latest_offsite_escrow_readiness_status)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("offsite_escrow_readiness_status_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="異地 / Escrow 準備度狀態快照無效",
) from exc
@router.get(
"/package-supply-chain-inventory",
response_model=dict[str, Any],
summary="取得套件 / 供應鏈盤點",
description=(
"讀取最新已提交的套件 / 供應鏈盤點;"
"此端點不呼叫外部來源、不安裝依賴、不升級套件、"
"不寫 lockfile、不查外部 CVE、不重建 image、不改生產路由。"
),
)
async def get_package_supply_chain_inventory() -> dict[str, Any]:
"""Return the latest read-only package supply-chain inventory."""
try:
return await asyncio.to_thread(load_latest_package_supply_chain_inventory)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("package_supply_chain_inventory_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="套件 / 供應鏈盤點快照無效",
) from exc
@router.get(
"/javascript-package-inventory",
response_model=dict[str, Any],
summary="取得 JavaScript 套件盤點",
description=(
"讀取最新已提交的 JavaScript / pnpm 套件盤點;"
"此端點不呼叫外部來源、不安裝套件、不升級套件、"
"不寫 lockfile、不執行 npm audit、不改生產路由。"
),
)
async def get_javascript_package_inventory() -> dict[str, Any]:
"""Return the latest read-only JavaScript package inventory."""
try:
return await asyncio.to_thread(load_latest_javascript_package_inventory)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("javascript_package_inventory_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="JavaScript 套件盤點快照無效",
) from exc
@router.get(
"/docker-build-surface-inventory",
response_model=dict[str, Any],
summary="取得 Docker build surface 盤點",
description=(
"讀取最新已提交的 Docker base image 與 build surface 盤點;"
"此端點不執行 docker build、不 pull image、不推 registry、"
"不查外部 CVE、不安裝套件、不改生產路由。"
),
)
async def get_docker_build_surface_inventory() -> dict[str, Any]:
"""Return the latest read-only Docker build surface inventory."""
try:
return await asyncio.to_thread(load_latest_docker_build_surface_inventory)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("docker_build_surface_inventory_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Docker build surface 盤點快照無效",
) from exc
@router.get(
"/dependency-risk-policy",
response_model=dict[str, Any],
summary="取得依賴風險政策",
description=(
"讀取最新已提交的 CVE / license / drift 嚴重度政策;"
"此端點不呼叫外部 CVE 或 license 來源、不安裝套件、不升級套件、"
"不寫 lockfile、不執行 docker build、不 pull image、不推 registry、"
"不呼叫付費 API、不建立 shadow/canary、不改生產路由。"
),
)
async def get_dependency_risk_policy() -> dict[str, Any]:
"""Return the latest read-only dependency risk policy."""
try:
return await asyncio.to_thread(load_latest_dependency_risk_policy)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("dependency_risk_policy_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="依賴風險政策快照無效",
) from exc
@router.get(
"/dependency-drift-check-plan",
response_model=dict[str, Any],
summary="取得依賴漂移檢查設計",
description=(
"讀取最新已提交的定期依賴漂移、外部資料來源與 AI Agent 市場觀察設計;"
"此端點只回傳 read-only plan不啟用排程、不寫 workflow、不呼叫外部 CVE / license / registry / 市場來源、"
"不安裝 SDK、不呼叫付費 API、不安裝或升級套件、不寫 lockfile、"
"不執行 docker build、不 pull image、不推 registry、不建立 shadow/canary、不改生產路由。"
),
)
async def get_dependency_drift_check_plan() -> dict[str, Any]:
"""Return the latest read-only dependency drift check plan."""
try:
return await asyncio.to_thread(load_latest_dependency_drift_check_plan)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("dependency_drift_check_plan_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="依賴漂移檢查設計快照無效",
) from exc
@router.get(
"/dependency-supply-chain-drift-monitor",
response_model=dict[str, Any],
summary="取得 P2-004 依賴 / 供應鏈漂移監控",
description=(
"讀取最新已提交的 P2-004 依賴 / 供應鏈漂移監控;"
"此端點只回傳 repo-only committed snapshot不啟用排程、不寫 workflow、"
"不呼叫外部 CVE / license / registry / Agent market 來源、不安裝或升級套件、"
"不寫 lockfile、不執行 npm audit、不執行 docker build、不 pull image、不推 registry、"
"不建立 PR、不送 Telegram、不讀 secret、不做 host probe、不做 production write。"
),
)
async def get_dependency_supply_chain_drift_monitor() -> dict[str, Any]:
"""Return the latest read-only P2-004 dependency / supply-chain drift monitor."""
try:
return await asyncio.to_thread(load_latest_dependency_supply_chain_drift_monitor)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("dependency_supply_chain_drift_monitor_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P2-004 依賴 / 供應鏈漂移監控快照無效",
) from exc
@router.get(
"/product-code-review-gate",
response_model=dict[str, Any],
summary="取得 P2-111 全產品 Code Review 防木馬 Gate",
description=(
"讀取最新已提交的 P2-111 全產品推版前後 Code Review / 防木馬 Gate"
"此端點會把 AwoooP tenants 資產台帳、Gitea code-review、供應鏈漂移、Aider 事件與 AI reviewer "
"分工收斂成只讀 read model。它不啟用外部 scanner、不寫 workflow、不 auto-merge、"
"不部署、不讀 secret、不推 registry、不簽 artifact、不送 Telegram、不寫 Gateway queue、不做 host probe。"
),
)
async def get_product_code_review_gate() -> dict[str, Any]:
"""Return the latest read-only all-product code review gate."""
try:
return await asyncio.to_thread(load_latest_product_code_review_gate)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("product_code_review_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P2-111 全產品 Code Review Gate 快照無效",
) from exc
@router.get(
"/dependency-upgrade-approval-package-template",
response_model=dict[str, Any],
summary="取得依賴升級批准包模板",
description=(
"讀取最新已提交的依賴升級、digest pin、publish boundary 與外部來源啟用批准包模板;"
"此端點只回傳 read-only template不安裝或升級套件、不寫 manifest 或 lockfile、"
"不修改 Dockerfile、不執行 docker build、不 pull image、不推 registry、不 publish package、"
"不安裝 SDK、不呼叫付費 API、不建立 shadow/canary、不改生產路由。"
),
)
async def get_dependency_upgrade_approval_package_template() -> dict[str, Any]:
"""Return the latest read-only dependency upgrade approval package template."""
try:
return await asyncio.to_thread(load_latest_dependency_upgrade_approval_package_template)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("dependency_upgrade_approval_package_template_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="依賴升級批准包模板快照無效",
) from exc
# =============================================================================
# Integration with Incident Flow
# =============================================================================
async def trigger_agent_analysis_for_incident(
incident_id: str,
background_tasks: BackgroundTasks,
) -> str | None:
"""
整合點: 當 Incident 需要複雜決策時自動觸發 Agent Teams
這個函數可被 incident_engine 或 webhooks 調用
Returns:
task_id if triggered, None if skipped
"""
service = get_agent_service()
task_id, incident = await service.trigger_for_incident(incident_id)
if task_id is None:
return None
if incident is None:
return None
# 加入背景任務
background_tasks.add_task(
service.run_analysis,
task_id,
incident,
)
return task_id