fix(awooop): fail soft drift fingerprint readback
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 2m3s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped

This commit is contained in:
Your Name
2026-07-03 07:53:18 +08:00
parent b338a7ab54
commit 468eba526e
5 changed files with 147 additions and 0 deletions

View File

@@ -15,6 +15,7 @@ leWOOOgo 積木化原則:
from typing import Literal
import structlog
from fastapi import APIRouter, BackgroundTasks, HTTPException
from pydantic import BaseModel, Field
@@ -32,6 +33,7 @@ from src.services.drift_analyzer import get_drift_analyzer
from src.services.drift_detector import get_drift_detector
from src.services.drift_fingerprint_state_service import (
DriftFingerprintStateNotFoundError,
build_drift_fingerprint_unavailable_state,
get_drift_fingerprint_state_service,
)
from src.services.drift_interpreter import get_drift_interpreter
@@ -39,6 +41,7 @@ from src.services.drift_remediator import get_drift_remediator
from src.utils.timezone import now_taipei
router = APIRouter(prefix="/drift", tags=["drift"])
logger = structlog.get_logger(__name__)
# 2026-04-09 Claude Sonnet 4.6: B4 drift_reports 持久化 — 改用 DB repository
@@ -157,6 +160,18 @@ async def get_drift_fingerprint_state(
return await svc.get_state(report_id=report_id, namespace=namespace)
except DriftFingerprintStateNotFoundError as exc:
raise HTTPException(status_code=404, detail="drift_report_not_found") from exc
except Exception as exc:
logger.warning(
"drift_fingerprint_state_readback_degraded",
report_id=report_id,
namespace=namespace,
error_type=type(exc).__name__,
)
return build_drift_fingerprint_unavailable_state(
namespace=namespace,
report_id=report_id,
reason="internal_readback_error",
)
@router.post("/fingerprints/handoff", summary="記錄 Config Drift fingerprint 交接")

View File

@@ -233,6 +233,67 @@ def build_drift_fingerprint_state(
}
def build_drift_fingerprint_unavailable_state(
*,
namespace: str | None = None,
report_id: str | None = None,
reason: str = "readback_exception",
) -> dict[str, Any]:
"""Build a no-write degraded payload when the read model cannot load."""
selected_namespace = namespace or DEFAULT_NAMESPACE
return {
"schema_version": SCHEMA_VERSION,
"namespace": selected_namespace,
"fingerprint": None,
"latest_report_id": report_id,
"latest_status": "readback_unavailable",
"latest_scanned_at": None,
"latest_created_at": None,
"summary": "Drift fingerprint readback unavailable; AI controlled retry required",
"high_count": 0,
"medium_count": 0,
"info_count": 0,
"interpretation": None,
"repeat_state": {
"fingerprint": None,
"occurrences_12h": 0,
"matching_strategy": "readback_degraded_fallback_v1",
},
"occurrences_12h": 0,
"matching_strategy": "readback_degraded_fallback_v1",
"operator_stage": "readback_degraded_ai_controlled_repair",
"fsm_state": "pending_human",
"next_step": "manual_investigation_or_ansible_check_mode",
"open_pr": None,
"latest_handoff": None,
"latest_remediation": None,
"strict_fingerprint": None,
"p0_escalation": {
"suppresses_repeated_p0": False,
"dedup_key_strategy": "readback_degraded_no_fingerprint",
"dedup_window_hours": 24,
},
"read_model_route": {
"agent_id": "openclaw",
"tool_name": "drift_fingerprint_state",
"required_scope": "read:drift read:gitea",
"flywheel_node": (
"drift_scanned>ai_analyzed>fingerprint_fsm>"
"ai_controlled_readback_repair"
),
},
"readback_status": "degraded",
"readback_error": reason,
"writes_incident_state": False,
"writes_auto_repair_result": False,
"writes_drift_status": False,
"writes_ticket": False,
"writes_remediation_record": False,
"creates_external_ticket": False,
}
def _handoff_context(
state: dict[str, Any],
*,