fix(awooop): strengthen outbound truth references
This commit is contained in:
@@ -785,6 +785,8 @@ async def fetch_truth_chain(source_id: str, project_id: str = "awoooi") -> dict[
|
||||
AND (
|
||||
run_id::text = :source_id
|
||||
OR content_preview ILIKE :needle
|
||||
OR coalesce(source_envelope #> '{source_refs,incident_ids}', '[]'::jsonb) ? :source_id
|
||||
OR coalesce(source_envelope #> '{source_refs,code_refs}', '[]'::jsonb) ? :source_id
|
||||
)
|
||||
ORDER BY queued_at DESC
|
||||
LIMIT :limit
|
||||
|
||||
@@ -514,7 +514,7 @@ async def record_outbound_message(
|
||||
content_hash, content_preview, content_redacted,
|
||||
redaction_version, source_envelope,
|
||||
provider_message_id,
|
||||
send_status, queued_at,
|
||||
send_status, queued_at, sent_at,
|
||||
triggered_by_state, waiting_since
|
||||
) VALUES (
|
||||
:project_id, :run_id, :conversation_event_id,
|
||||
@@ -523,6 +523,7 @@ async def record_outbound_message(
|
||||
:redaction_version, CAST(:source_envelope AS jsonb),
|
||||
:provider_message_id,
|
||||
:send_status, NOW(),
|
||||
CASE WHEN :send_status = 'sent' THEN NOW() ELSE NULL END,
|
||||
:triggered_by_state, :waiting_since
|
||||
)
|
||||
RETURNING message_id
|
||||
|
||||
@@ -69,6 +69,7 @@ POLLING_LEADER_WATCH = 30 # seconds - 非 Leader Pod 每 30s 嘗試接管
|
||||
logger = structlog.get_logger(__name__)
|
||||
_TELEGRAM_BOT_URL_RE = re.compile(r"(api\.telegram\.org/bot)[^/\s]+")
|
||||
_INCIDENT_ID_RE = re.compile(r"\bINC-\d{8}-[A-Z0-9]{4,}\b")
|
||||
_CODE_REF_RE = re.compile(r"<code>([0-9a-f]{7,12})</code>", re.IGNORECASE)
|
||||
|
||||
|
||||
def _top_gateway_bucket(
|
||||
@@ -213,6 +214,9 @@ def _reply_markup_summary(payload: dict) -> dict[str, object]:
|
||||
|
||||
def _outbound_source_envelope(method: str, payload: dict) -> dict[str, object]:
|
||||
"""Build a redaction-friendly source envelope for Channel Hub replay."""
|
||||
text = str(payload.get("text") or payload.get("caption") or "")
|
||||
incident_ids = sorted(set(_INCIDENT_ID_RE.findall(text)))
|
||||
code_refs = sorted(set(match.group(1) for match in _CODE_REF_RE.finditer(text)))
|
||||
return {
|
||||
"adapter": "legacy_telegram_gateway",
|
||||
"method": method,
|
||||
@@ -222,6 +226,10 @@ def _outbound_source_envelope(method: str, payload: dict) -> dict[str, object]:
|
||||
"disable_web_page_preview": payload.get("disable_web_page_preview"),
|
||||
"has_reply_context": _has_reply_context(payload),
|
||||
"reply_markup": _reply_markup_summary(payload),
|
||||
"source_refs": {
|
||||
"incident_ids": incident_ids[:20],
|
||||
"code_refs": code_refs[:20],
|
||||
},
|
||||
}
|
||||
|
||||
# 2026-04-27 Claude Sonnet 4.6: B3 — LLM 動態 Telegram 按鈕 Feature Flag
|
||||
|
||||
@@ -6,6 +6,7 @@ from src.services.channel_hub import (
|
||||
ensure_completed_shadow_run,
|
||||
format_grouped_alert_digest_text,
|
||||
format_grouped_alert_event_content,
|
||||
record_outbound_message,
|
||||
)
|
||||
|
||||
|
||||
@@ -79,10 +80,14 @@ class _FakeSession:
|
||||
def __init__(self) -> None:
|
||||
self.statement = ""
|
||||
self.params = {}
|
||||
self.statements = []
|
||||
self.param_sets = []
|
||||
|
||||
async def execute(self, statement, params): # noqa: ANN001
|
||||
self.statement = str(statement)
|
||||
self.params = params
|
||||
self.statements.append(str(statement))
|
||||
self.param_sets.append(params)
|
||||
return _FakeResult()
|
||||
|
||||
|
||||
@@ -105,3 +110,27 @@ async def test_completed_shadow_run_sets_run_state_not_null_defaults() -> None:
|
||||
assert "0, 3, 0.0000, 0" in session.statement
|
||||
assert session.params["project_id"] == "awoooi"
|
||||
assert session.params["run_id"] == run_id
|
||||
|
||||
|
||||
async def test_record_outbound_message_sets_sent_at_for_sent_messages() -> None:
|
||||
session = _FakeSession()
|
||||
run_id = build_grouped_alert_run_id("awoooi", "telegram-message-13152")
|
||||
|
||||
await record_outbound_message(
|
||||
session, # type: ignore[arg-type]
|
||||
project_id="awoooi",
|
||||
run_id=run_id,
|
||||
channel_type="telegram",
|
||||
channel_chat_id="-100123",
|
||||
message_type="approval_request",
|
||||
content="ACTION REQUIRED INC-20260513-9B082D",
|
||||
provider_message_id="13152",
|
||||
send_status="sent",
|
||||
triggered_by_state="legacy_gateway",
|
||||
is_shadow=False,
|
||||
)
|
||||
|
||||
insert_statement = session.statements[-1]
|
||||
assert "sent_at" in insert_statement
|
||||
assert "CASE WHEN :send_status = 'sent' THEN NOW() ELSE NULL END" in insert_statement
|
||||
assert session.param_sets[-1]["send_status"] == "sent"
|
||||
|
||||
@@ -18,7 +18,11 @@ def test_telegram_gateway_sanitizes_bot_token_url() -> None:
|
||||
def test_outbound_source_envelope_keeps_replay_context_without_raw_payload() -> None:
|
||||
payload = {
|
||||
"chat_id": "-100123",
|
||||
"text": "ACTION REQUIRED token 1234567890:abcdefghijklmnopqrstuvwxyzABCDEFGH",
|
||||
"text": (
|
||||
"ACTION REQUIRED INC-20260513-9B082D "
|
||||
"<code>7f858956</code> token "
|
||||
"1234567890:abcdefghijklmnopqrstuvwxyzABCDEFGH"
|
||||
),
|
||||
"parse_mode": "HTML",
|
||||
"reply_markup": {
|
||||
"inline_keyboard": [
|
||||
@@ -40,6 +44,8 @@ def test_outbound_source_envelope_keeps_replay_context_without_raw_payload() ->
|
||||
assert envelope["reply_markup"]["button_count"] == 2
|
||||
assert envelope["reply_markup"]["buttons"][0]["callback_prefix"] == "approve"
|
||||
assert envelope["reply_markup"]["buttons"][1]["callback_prefix"] == "details"
|
||||
assert envelope["source_refs"]["incident_ids"] == ["INC-20260513-9B082D"]
|
||||
assert envelope["source_refs"]["code_refs"] == ["7f858956"]
|
||||
assert "approval-id-secret" not in str(envelope)
|
||||
assert "1234567890:" not in str(envelope)
|
||||
assert "ACTION REQUIRED" not in str(envelope)
|
||||
|
||||
@@ -7251,3 +7251,57 @@ scope=write
|
||||
- T11 已部署:Operator Run Detail 與 Telegram detail formatter 都已能呈現 MCP Gateway 摘要。
|
||||
- 這次沒有發送真實 Telegram 測試訊息,避免洗版;改以 production pod 直接呼叫 detail formatter 驗證。
|
||||
- 目前整體進度更新:約 68%。
|
||||
|
||||
### 2026-05-13 — AwoooP truth-chain T12a:Telegram outbound 可回放關聯強化(local green)
|
||||
|
||||
**production live audit 摘要**:
|
||||
|
||||
```text
|
||||
24h:
|
||||
incidents=150
|
||||
approval_records=102
|
||||
alert_operation_log=682
|
||||
timeline_events=154
|
||||
incident_evidence=130
|
||||
auto_repair_executions=10
|
||||
knowledge_entries=42
|
||||
legacy_mcp_audit_log=1265
|
||||
awooop_mcp_gateway_audit=1365
|
||||
awooop_outbound_message=420
|
||||
|
||||
outbound_quality:
|
||||
total=420 redacted=226 envelope=420 envelope_schema=226 with_run=420 sent_at=0
|
||||
|
||||
incident_join_quality:
|
||||
total=150 with_aol=100 with_evidence=102 with_legacy_mcp=102 with_timeline=102 with_approval=102 with_auto_repair=10
|
||||
|
||||
Sentry / SignOz durable event tables:
|
||||
none found by information_schema table_name ILIKE '%sentry%' OR '%signoz%'
|
||||
```
|
||||
|
||||
**判讀**:
|
||||
|
||||
- MCP / SignOz 能力已有實際使用,且 legacy MCP bridge 已寫入 AwoooP Gateway audit。
|
||||
- 仍不能宣稱完整 AI 自動修復:24h incident 150 筆中只有 10 筆有 `auto_repair_executions`。
|
||||
- Telegram outbound mirror 有資料,但 `sent_at=0` 是真缺口;source envelope 也缺少 structured source refs,truth-chain 只能靠 `content_preview ILIKE` 猜關聯。
|
||||
|
||||
**變更**:
|
||||
|
||||
- `record_outbound_message()` 在 `send_status='sent'` 時寫入 `sent_at=NOW()`。
|
||||
- Telegram outbound `source_envelope` 新增 `source_refs.incident_ids` 與 `source_refs.code_refs`,保留 redaction-friendly 關聯錨點。
|
||||
- truth-chain outbound 查詢支援 structured `source_refs`,不只靠 preview 文字搜尋。
|
||||
|
||||
**local verification**:
|
||||
|
||||
```text
|
||||
DATABASE_URL=postgresql+asyncpg://u:p@localhost:5432/db python -m pytest tests/test_telegram_gateway_error_sanitizer.py tests/test_channel_hub_grouped_alert_events.py tests/test_awooop_truth_chain_service.py tests/test_telegram_adr050.py -q
|
||||
51 passed
|
||||
|
||||
python -m ruff check --select F821 src/services/channel_hub.py src/services/telegram_gateway.py src/services/awooop_truth_chain_service.py tests/test_telegram_gateway_error_sanitizer.py tests/test_channel_hub_grouped_alert_events.py tests/test_telegram_adr050.py
|
||||
All checks passed
|
||||
|
||||
python -m py_compile src/services/channel_hub.py src/services/telegram_gateway.py src/services/awooop_truth_chain_service.py tests/test_telegram_gateway_error_sanitizer.py tests/test_channel_hub_grouped_alert_events.py tests/test_telegram_adr050.py
|
||||
OK
|
||||
```
|
||||
|
||||
**目前整體進度**:約 69%。
|
||||
|
||||
Reference in New Issue
Block a user