fix(ci): 修正測試與 Sprint 5.2 部署腳本
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 1m38s

tests/test_auto_repair_service.py:
  - 更新 3個測試符合 2026-04-07 統帥指令移除門檻
  - APPROVED Playbook 直接通過 (低相似度/低品質/高風險均通過)

tests/test_phase22_nemotron_collab.py:
  - 更新 log key: nemotron_collaboration_failed → exhausted

ops/monitoring/docker-compose.exporters.yaml:
  - 修正 postgres DSN: awoooi:awoooi_prod_2026@localhost:5432/awoooi_prod

Sprint 5.2 新增腳本:
  - scripts/sprint51_e2e_validation.py: L7 E2E 驗收腳本 (T1-T5)
  - scripts/ops/deploy-docker-health-monitor.sh: Plan A 一鍵部署腳本

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-04-08 18:17:48 +08:00
parent 4f2f9e176f
commit 170ce2f11d
5 changed files with 479 additions and 22 deletions

View File

@@ -163,22 +163,29 @@ class TestAutoRepairService:
@pytest.mark.asyncio
async def test_evaluate_low_similarity(self, service, mock_playbook_service):
"""Test when similarity is too low"""
"""Test that low similarity no longer blocks auto-repair.
2026-04-07: 統帥指令移除相似度門檻 — 只要 APPROVED Playbook 匹配即執行。
2026-04-08 Claude Sonnet 4.6: 更新測試預期以符合當前設計。
"""
playbook = create_high_quality_playbook()
mock_playbook_service.add_playbook(playbook)
mock_playbook_service.set_recommendations([
MockPlaybookRecommendation(playbook, similarity_score=0.5) # Below 0.7
MockPlaybookRecommendation(playbook, similarity_score=0.5) # Below old 0.7 threshold
])
incident = create_test_incident(severity=Severity.P2)
decision = await service.evaluate_auto_repair(incident)
assert decision.can_auto_repair is False
assert decision.blocked_by == "LOW_SIMILARITY"
# 相似度門檻已移除 — APPROVED Playbook 即使低相似度也應通過
assert decision.can_auto_repair is True
assert decision.blocked_by is None
@pytest.mark.asyncio
async def test_evaluate_not_high_quality(self, service, mock_playbook_service):
"""Test when playbook is not high quality and not cold-start eligible (MEDIUM risk)"""
"""Test low-quality playbook is now approved (gates removed 2026-04-07).
2026-04-07: 統帥指令移除品質門檻 — 只要 APPROVED 狀態即可執行。
2026-04-08 Claude Sonnet 4.6: 更新測試預期以符合當前設計。
"""
playbook = Playbook(
playbook_id="PB-LOW-QUALITY",
name="Low quality playbook",
@@ -193,11 +200,11 @@ class TestAutoRepairService:
step_number=1,
action_type=ActionType.KUBECTL,
command="kubectl rollout restart",
risk_level=RiskLevel.MEDIUM, # MEDIUM → 不符合冷啟動 (需 LOW)
risk_level=RiskLevel.MEDIUM,
description="restart deployment",
),
],
success_count=2, # < 3 (冷啟動門檻 2026-04-05)
success_count=2,
failure_count=0,
)
mock_playbook_service.add_playbook(playbook)
@@ -208,12 +215,16 @@ class TestAutoRepairService:
incident = create_test_incident(severity=Severity.P2)
decision = await service.evaluate_auto_repair(incident)
assert decision.can_auto_repair is False
assert decision.blocked_by == "NOT_HIGH_QUALITY"
# 品質門檻已移除 — APPROVED Playbook 直接通過
assert decision.can_auto_repair is True
assert decision.blocked_by is None
@pytest.mark.asyncio
async def test_evaluate_high_risk_blocked(self, service, mock_playbook_service):
"""Test when playbook contains HIGH risk actions"""
"""Test HIGH risk playbook is now approved (gates removed 2026-04-07).
2026-04-07: 統帥指令移除風險等級門檻 — 只要 APPROVED 狀態即可執行。
2026-04-08 Claude Sonnet 4.6: 更新測試預期以符合當前設計。
"""
playbook = create_high_quality_playbook(risk_level=RiskLevel.HIGH)
mock_playbook_service.add_playbook(playbook)
mock_playbook_service.set_recommendations([
@@ -223,12 +234,16 @@ class TestAutoRepairService:
incident = create_test_incident(severity=Severity.P2)
decision = await service.evaluate_auto_repair(incident)
assert decision.can_auto_repair is False
assert decision.blocked_by == "HIGH_RISK"
# 風險等級門檻已移除 — HIGH risk APPROVED Playbook 也通過
assert decision.can_auto_repair is True
assert decision.blocked_by is None
@pytest.mark.asyncio
async def test_evaluate_critical_risk_blocked(self, service, mock_playbook_service):
"""Test when playbook contains CRITICAL risk actions"""
"""Test CRITICAL risk playbook is now approved (gates removed 2026-04-07).
2026-04-07: 統帥指令移除風險等級門檻。
2026-04-08 Claude Sonnet 4.6: 更新測試預期以符合當前設計。
"""
playbook = create_high_quality_playbook(risk_level=RiskLevel.CRITICAL)
mock_playbook_service.add_playbook(playbook)
mock_playbook_service.set_recommendations([
@@ -238,8 +253,9 @@ class TestAutoRepairService:
incident = create_test_incident(severity=Severity.P2)
decision = await service.evaluate_auto_repair(incident)
assert decision.can_auto_repair is False
assert decision.blocked_by == "HIGH_RISK"
# 風險等級門檻已移除 — CRITICAL risk APPROVED Playbook 也通過
assert decision.can_auto_repair is True
assert decision.blocked_by is None
@pytest.mark.asyncio
async def test_evaluate_success(self, service, mock_playbook_service):

View File

@@ -156,16 +156,20 @@ class TestNemotronFailureFallback:
"""#213: Nemotron 失敗降級為純 OpenClaw"""
def test_nemotron_failure_does_not_raise(self):
"""Nemotron 失敗有 except 捕捉,不拋出"""
"""Nemotron 失敗有 except 捕捉,不拋出
2026-04-08 Claude Sonnet 4.6: 更新 log key — 改為 nemotron_collaboration_exhausted
(失敗時仍顯示區塊讓統帥知悉nemotron_enabled=True)
"""
with open("src/services/openclaw.py") as f:
source = f.read()
idx_func = source.find("async def generate_incident_proposal_with_tools")
func_body = source[idx_func:idx_func + 5000]
# except 區塊捕捉 nemotron 失敗
assert "nemotron_collaboration_failed" in func_body
assert "nemotron_enabled = False" in func_body or 'proposal["nemotron_enabled"] = False' in func_body
# except 區塊捕捉 nemotron 失敗 (exhausted 為重試耗盡的 log key)
assert "nemotron_collaboration_exhausted" in func_body
# 失敗時 nemotron_enabled=True (讓統帥看到失敗狀態)
assert 'proposal["nemotron_enabled"] = True' in func_body
def test_nemotron_failure_still_returns_proposal(self):
"""Nemotron 失敗後仍 return (proposal, provider, True)"""
@@ -189,11 +193,13 @@ class TestNemotronFailureFallback:
assert 'proposal["nemotron_validation"]' in source
def test_nemotron_failure_logs_warning(self):
"""Nemotron 失敗時記錄 warning log"""
"""Nemotron 失敗時記錄 warning/error log.
2026-04-08 Claude Sonnet 4.6: 改為 nemotron_collaboration_exhausted
"""
with open("src/services/openclaw.py") as f:
source = f.read()
assert "nemotron_collaboration_failed" in source
assert "nemotron_collaboration_exhausted" in source
# =============================================================================