fix(awooop): json-safe recurrence audit context
All checks were successful
Code Review / ai-code-review (push) Successful in 11s
CD Pipeline / tests (push) Successful in 4m13s
CD Pipeline / build-and-deploy (push) Successful in 4m26s
CD Pipeline / post-deploy-checks (push) Successful in 1m57s

This commit is contained in:
Your Name
2026-05-21 09:20:00 +08:00
parent 72043adac1
commit f671637e23
3 changed files with 20 additions and 3 deletions

View File

@@ -39,6 +39,16 @@ def _as_dict(value: Any) -> dict[str, Any]:
return value if isinstance(value, dict) else {}
def _json_safe(value: Any) -> Any:
if isinstance(value, dict):
return {str(key): _json_safe(item) for key, item in value.items()}
if isinstance(value, (list, tuple, set)):
return [_json_safe(item) for item in value]
if value is None or isinstance(value, (str, int, float, bool)):
return value
return str(value)
def _compact_ref_count(source_refs: dict[str, Any]) -> int:
total = 0
for value in source_refs.values():
@@ -905,7 +915,7 @@ async def _record_recurrence_work_item_dry_run_history(
actor="awooop_recurrence_work_item_service",
action_detail=f"recurrence_work_item_dry_run:{payload.get('mode')}"[:200],
success=allowed,
context=context,
context=_json_safe(context),
)
if record is not None:
history["alert_operation_id"] = getattr(record, "id", None)
@@ -978,7 +988,7 @@ async def _record_recurrence_work_item_handoff_history(
f"recurrence_work_item_handoff:{payload.get('handoff_kind')}"
)[:200],
success=allowed,
context=context,
context=_json_safe(context),
)
if record is not None:
history["alert_operation_id"] = getattr(record, "id", None)

View File

@@ -606,6 +606,7 @@ async def test_source_correlation_dry_run_history_records_without_incident(
"sentry:upstream_canary:"
"awoooi-canary-codex-t115-production"
),
"latest_run_id": UUID("11111111-1111-4111-8111-111111111111"),
},
"ticket_preview": {"would_create": False},
"read_model_route": {
@@ -629,6 +630,10 @@ async def test_source_correlation_dry_run_history_records_without_incident(
assert appended[0]["incident_id"] is None
assert appended[0]["actor"] == "awooop_recurrence_work_item_service"
assert appended[0]["context"]["work_item_id"].startswith("source-evidence:")
assert (
appended[0]["context"]["current_state_summary"]["latest_run_id"]
== "11111111-1111-4111-8111-111111111111"
)
def test_build_recurrence_work_item_handoff_records_ticket_proposal_contract() -> None:

View File

@@ -14,6 +14,7 @@
- `reason=provider_native_evidence_unlinked`
- 不寫入 Incident / AutoRepair / Ticket只提供 preview / dry-run / handoff read model。
- Source review dry-run / handoff 沒有 Incident 時仍會寫入 `alert_operation_log``incident_id=null`),避免 operator 看到 `missing_incident_id` 誤判為沒有 DB audittimeline 仍只在有 Incident 時寫入。
- Recurrence work item audit context 會先做 JSON-safe 轉換,避免 UUID / datetime 這類 DB row 型別讓 `alert_operation_log.context` 寫入失敗。
- `/api/v1/platform/events/dossier/recurrence` summary 新增 `source_correlation_review_group_total`
- AwoooP Runs 前端「重複告警關聯」新增「來源待審」指標,卡片顯示事件 stage讓 operator 可看見 provider-native evidence 已進 AwoooP 但仍需配對審核。
- AwoooP Work Items 同步顯示 source review count、stage、provider event id、Sentry / SignOz refs避免從 Runs 點進工作項後掉成 unknown。
@@ -47,7 +48,8 @@ python -m ruff check src/services/channel_event_dossier_service.py src/api/v1/pl
- 前端 AI 自動化管理介面同步99.99%Runs / Work Items recurrence panel 已同步來源待審)。
- 完整 AI 自動化管理產品化99.65% → 99.68%。
- 第一輪部署Gitea Actions 1952 Code Review success1951 CD successproduction recurrence schema 已出現 `source_correlation_review_group_total` / `latest_stage` / `stage_counts`
- 剩餘source review audit 小修再推 Gitea main等待第二輪 CI/CD、production dry-run history 驗證
- 第二輪部署Gitea Actions 1954 Code Review success1953 CD in progressproduction dry-run 已進入新分支但 alert_operation_log context 需 JSON-safe follow-up
- 剩餘JSON-safe audit follow-up 再推 Gitea main等待第三輪 CI/CD、production dry-run history 驗證。
## 2026-05-20T115 Provider-native upstream canary 接入