docs(agent99): advance mainline to alert routing
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 resolved,alert 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 | 強化 ingress:relay 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。
|
||||
|
||||
Reference in New Issue
Block a user