docs(agent99): advance mainline to alert routing

This commit is contained in:
ogt
2026-07-10 16:26:23 +08:00
parent 5ea4405c2a
commit 025ef46625
4 changed files with 55 additions and 40 deletions

View File

@@ -53,6 +53,7 @@ def load_latest_agent99_enterprise_ai_automation_work_items(
priority_counts = {priority: 0 for priority in _VALID_PRIORITIES}
status_counts = {status: 0 for status in _VALID_STATUSES}
p0_ids: list[str] = []
active_p0_ids: list[str] = []
for index, item in enumerate(work_items, start=1):
if not isinstance(item, dict):
@@ -78,6 +79,8 @@ def load_latest_agent99_enterprise_ai_automation_work_items(
status_counts[item_status] += 1
if priority == "P0":
p0_ids.append(item_id)
if item_status != "complete":
active_p0_ids.append(item_id)
missing = [field for field in required_p0_fields if item.get(field) is None]
if missing:
raise ValueError(f"{path}: {item_id} missing P0 fields: {missing}")
@@ -88,12 +91,14 @@ def load_latest_agent99_enterprise_ai_automation_work_items(
raise ValueError(f"{path}: work item order is not contiguous")
current_p0_id = current_p0.get("id")
if current_p0_id not in p0_ids:
raise ValueError(f"{path}: current_p0.id is not a P0 work item")
if not p0_ids or p0_ids[0] != current_p0_id:
raise ValueError(f"{path}: current_p0 must be the first ordered P0")
if payload.get("next_execution_order") != p0_ids:
raise ValueError(f"{path}: next_execution_order must equal ordered P0 ids")
if current_p0_id not in active_p0_ids:
raise ValueError(f"{path}: current_p0.id is not an active P0 work item")
if not active_p0_ids or active_p0_ids[0] != current_p0_id:
raise ValueError(f"{path}: current_p0 must be the first ordered active P0")
if payload.get("next_execution_order") != active_p0_ids:
raise ValueError(
f"{path}: next_execution_order must equal ordered active P0 ids"
)
_require_count(summary, "p0_count", priority_counts["P0"], path)
_require_count(summary, "p1_count", priority_counts["P1"], path)

View File

@@ -31,7 +31,7 @@ def test_agent99_enterprise_work_items_loader_returns_complete_scope() -> None:
"agent99_enterprise_ai_automation_work_items_v1"
)
assert payload["scope_complete"] is False
assert payload["current_p0"]["id"] == "AG99-P0-001"
assert payload["current_p0"]["id"] == "AG99-P0-002"
assert payload["summary"] == {
"host_count": 7,
"product_count": 12,
@@ -42,11 +42,11 @@ def test_agent99_enterprise_work_items_loader_returns_complete_scope() -> None:
"p2_count": 3,
"in_progress_count": 5,
"in_progress_blocked_count": 3,
"planned_count": 17,
"complete_count": 0,
"planned_count": 16,
"complete_count": 1,
"current_p0_count": 1,
}
assert payload["next_execution_order"][0] == "AG99-P0-001"
assert payload["next_execution_order"][0] == "AG99-P0-002"
assert payload["next_execution_order"][-1] == "AG99-P0-014"
@@ -54,7 +54,7 @@ def test_agent99_enterprise_projection_is_bounded() -> None:
payload = load_latest_agent99_enterprise_ai_automation_work_items()
projection = build_agent99_enterprise_priority_projection(payload)
assert projection["current_p0"]["id"] == "AG99-P0-001"
assert projection["current_p0"]["id"] == "AG99-P0-002"
assert projection["coverage"] == {
"host_count": 7,
"product_count": 12,
@@ -73,7 +73,7 @@ def test_priority_readback_projects_agent99_enterprise_order() -> None:
payload = load_latest_awoooi_priority_work_order_readback()
projection = payload["agent99_enterprise_ai_automation"]
assert projection["current_p0"]["id"] == "AG99-P0-001"
assert projection["current_p0"]["id"] == "AG99-P0-002"
assert projection["work_item_counts"]["p0"] == 14
assert (
payload["source_refs"]["agent99_enterprise_ai_automation_work_items_api"]
@@ -103,7 +103,7 @@ def test_agent99_enterprise_work_items_endpoint_returns_snapshot() -> None:
assert response.status_code == 200
payload = response.json()
assert payload["current_p0"]["id"] == "AG99-P0-001"
assert payload["current_p0"]["id"] == "AG99-P0-002"
assert payload["summary"]["host_count"] == 7
assert payload["summary"]["product_count"] == 12
assert payload["summary"]["public_surface_count"] == 23

View File

@@ -1,7 +1,7 @@
{
"schema_version": "agent99_enterprise_ai_automation_work_items_v1",
"generated_at": "2026-07-10T16:00:26+08:00",
"status": "in_progress_p0_agent_outcome_staging_verified_runtime_apply_pending",
"generated_at": "2026-07-10T16:22:00+08:00",
"status": "in_progress_p0_alert_routing_grouping_dedupe",
"scope_complete": false,
"north_star": "Make Windows host 192.168.0.99 the policy-controlled on-prem AI execution node for all hosts, VMs, services, products, sites, tools, packages, alerts and recovery workflows, with external monitoring when host 99 is unavailable.",
"canonical_sources": {
@@ -17,22 +17,11 @@
"runtime_reboot_slo_readback": "https://awoooi.wooo.work/api/v1/agents/reboot-auto-recovery-slo-scorecard"
},
"current_p0": {
"id": "AG99-P0-001",
"title": "Agent outcome truth and source-runtime reconciliation",
"reason": "Agent99 currently treats command exit success as incident resolution and the Windows runtime scripts do not consistently match the current Gitea source. All later automation depends on trustworthy outcomes.",
"implementation_status": "source_implemented_staging_verified_runtime_apply_pending",
"staging_verifier": {
"host": "99",
"outcome_contract": "agent99_outcome_contract_v1",
"outcome_self_test_ok": true,
"runtime_manifest": "agent99_runtime_manifest_v1",
"source_revision": "p0-001-staging-latest",
"runtime_manifest_matched": true,
"runtime_manifest_file_count": 7,
"runtime_manifest_mismatch_count": 0,
"evidence": "C:\\Wooo\\Agent99\\staging\\p0-001-runtime\\evidence\\agent99-OutcomeContractSelfTest-20260710-160255.json"
},
"next_action": "Commit and deploy the verified outcome contract to host 99, rerun the runtime manifest and outcome self-test, then replay one operator smoke and one alert-source event without counting transport-only success as resolved."
"id": "AG99-P0-002",
"title": "Alert taxonomy, routing, grouping and dedupe",
"reason": "Explicit event kind and suggested mode are not consistently authoritative, and forwarding before grouping can create wrong-domain or duplicate Agent99 work.",
"implementation_status": "in_progress_replay_corpus_and_pre_bridge_grouping",
"next_action": "Add routing precedence and a replay corpus for backup, provider, reboot, PostgreSQL, host and K3s events; move grouping and single-flight ahead of Agent99 dispatch."
},
"current_runtime_truth": {
"observed_at": "2026-07-10T15:04:27+08:00",
@@ -267,7 +256,7 @@
"id": "AG99-P0-001",
"order": 1,
"priority": "P0",
"status": "in_progress",
"status": "complete",
"title": "Agent outcome truth and source-runtime reconciliation",
"owner_lane": "agent99_control_plane",
"dependencies": [],
@@ -283,13 +272,35 @@
"verifier": "For every mode, require post-condition pass plus source event resolution; compare source and runtime manifest hashes.",
"callback": "Write final outcome to AWOOOI incident and AwoooP Run/Verifier using the same trace id.",
"acceptance": "No false-resolved regression cases; source/runtime drift count is zero; unresolved evidence stays degraded or blocked.",
"next_action": "Deploy the staging-verified outcome contract to host 99, confirm source/runtime manifest hashes, then replay operator and alert-source outcomes."
"completion_receipt": {
"source_revision": "5ea4405c2a75b51244da168a4834d27e24d74ee6",
"runtime_manifest_matched": true,
"runtime_manifest_file_count": 7,
"runtime_manifest_mismatch_count": 0,
"self_health_runtime_manifest_severity": "ok",
"outcome_self_test_ok": true,
"operator_replay_state": "resolved",
"operator_replay_verified_resolved": 1,
"alert_replay_state": "verifying",
"alert_replay_verified_resolved": 0,
"alert_replay_source_event_resolved": false,
"telegram_sent_count": 0,
"rollback": "C:\\Wooo\\Agent99\\rollback\\p0-001-pre-5ea4405c",
"evidence": [
"C:\\Wooo\\Agent99\\evidence\\agent99-OutcomeContractSelfTest-20260710-161302.json",
"C:\\Wooo\\Agent99\\evidence\\agent99-SelfCheck-20260710-161350.json",
"C:\\Wooo\\Agent99\\queue\\processed\\processed-p0-001-operator-verifier-20260710-1615.json",
"C:\\Wooo\\Agent99\\queue\\processed\\processed-p0-001-alert-verifier-20260710-1615.json",
"C:\\Wooo\\Agent99\\evidence\\agent99-ControlTick-20260710-161919.json"
]
},
"next_action": "Keep runtime-manifest drift and verified-resolution counters under SelfCheck; continue with AG99-P0-002."
},
{
"id": "AG99-P0-002",
"order": 2,
"priority": "P0",
"status": "planned",
"status": "in_progress",
"title": "Alert taxonomy, routing, grouping and dedupe",
"owner_lane": "awoooi_alert_router_agent99_ingress",
"dependencies": ["AG99-P0-001"],
@@ -736,12 +747,11 @@
"p2_count": 3,
"in_progress_count": 5,
"in_progress_blocked_count": 3,
"planned_count": 17,
"complete_count": 0,
"planned_count": 16,
"complete_count": 1,
"current_p0_count": 1
},
"next_execution_order": [
"AG99-P0-001",
"AG99-P0-002",
"AG99-P0-003",
"AG99-P0-004",

View File

@@ -91,8 +91,8 @@
| 順序 | ID | 工作 | 狀態 | 驗收 |
| --- | --- | --- | --- | --- |
| 1 | AG99-P0-001 | 修正 `exitCode=0 => resolved` 假綠,對齊 99 runtime script 與 Gitea source SHA | **進行中current P0** | 每種模式以 verifier 決定 outcome舊 runtime/script drift 歸零;不得再把缺證據算 resolved |
| 2 | AG99-P0-002 | 修正 alert taxonomy、wrong-domain routing、bridge-before-grouping 與重複事件 | 待辦 | `suggestedMode`/kind 優先於 source 字串5 分鐘先 group同 fingerprint 只建立一個 active incident |
| 1 | AG99-P0-001 | 修正 `exitCode=0 => resolved` 假綠,對齊 99 runtime script 與 Gitea source SHA | **完成** | Production 99 outcome self-test 通過runtime manifest `7/7` matched、drift `0`operator replay 為 verified resolvedalert replay 缺 source-event resolved 時維持 verifying |
| 2 | AG99-P0-002 | 修正 alert taxonomy、wrong-domain routing、bridge-before-grouping 與重複事件 | **進行中current P0** | `suggestedMode`/kind 優先於 source 字串5 分鐘先 group同 fingerprint 只建立一個 active incident |
| 3 | AG99-P0-003 | 強化 ingressrelay token 必填、Telegram chat+sender allowlist、idempotency/single consumer | 待辦 | 未認證 LAN request 拒絕producer `auto_repair`/policy 被保留;所有 request 可追 trace |
| 4 | AG99-P0-004 | 新增 EvidenceCollect / RepairCandidate / MCP lane | 待辦 | 缺 evidence 的事件會建立可查 candidate不再錯送 Perf/AwoooRepair`INC-*` 可從收件追到 candidate |
@@ -157,4 +157,4 @@
## 8. 立即下一步
目前唯一 P0 是 `AG99-P0-001`先修正 Agent99 假 resolved 與 99 runtime/source drift建立 outcome contract 與 regression tests。完成後依序做 routing/dedupe、secure ingress、RepairCandidate再回到 reboot state machine live rerun;如此不是離開重啟主線,而是先修正會把重啟與告警錯誤結案的控制核心
目前唯一 P0 是 `AG99-P0-002`以 explicit event kind / suggested mode 建立 routing precedence將 5 分鐘 grouping、fingerprint dedupe 與 single-flight 移到 Agent99 dispatch 之前,並用 backup、provider、reboot、PostgreSQL、host、K3s replay corpus 證明不再 wrong-domain 或重複派工。完成後依序做 secure ingress、RepairCandidate再回到 reboot state machine live rerun。