feat(ai): add automation surface summary
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
This commit is contained in:
@@ -25,7 +25,8 @@ def test_ai_intelligence_first_viewport_has_benchmark_golden_signals():
|
||||
assert "異動狀態" in strip
|
||||
assert "下一步" in strip
|
||||
assert "loadAutomationBenchmarkStrip()" in template
|
||||
assert "/api/ai/pchome-growth/ai-automation-readiness" in template
|
||||
assert "/api/ai/pchome-growth/ai-automation-surface-summary" in template
|
||||
assert "golden_signals" in template
|
||||
|
||||
|
||||
def test_observability_overview_first_viewport_has_benchmark_golden_signals():
|
||||
|
||||
@@ -165,3 +165,39 @@ def test_candidate_decision_lane_closeout_route_defaults_to_cached_no_db_no_sear
|
||||
assert payload["product_readiness"]["primary_human_gate_count"] == 0
|
||||
assert payload["safety"]["executes_search"] is False
|
||||
assert payload["safety"]["writes_database"] is False
|
||||
|
||||
|
||||
def test_ai_automation_surface_summary_route_defaults_to_cached_no_db(monkeypatch):
|
||||
from routes import ai_routes as routes
|
||||
|
||||
monkeypatch.setattr(routes, "_get_cached_pchome_growth_payload", lambda: _payload())
|
||||
|
||||
def fail_engine(database_path):
|
||||
raise AssertionError("cached AI automation surface summary should not open a DB engine")
|
||||
|
||||
monkeypatch.setattr(routes, "_create_icaim_dashboard_engine", fail_engine)
|
||||
|
||||
app = Flask(__name__)
|
||||
with app.test_request_context(
|
||||
"/api/ai/pchome-growth/ai-automation-surface-summary"
|
||||
"?batch_size=1&include_receipt_replay=false&include_drift_verifier=false"
|
||||
):
|
||||
response = routes.api_pchome_growth_ai_automation_surface_summary.__wrapped__()
|
||||
|
||||
payload = response.get_json()
|
||||
signals = {signal["key"]: signal for signal in payload["golden_signals"]}
|
||||
assert payload["success"] is True
|
||||
assert payload["policy"] == "read_only_pchome_growth_ai_automation_surface_summary"
|
||||
assert payload["source_endpoint"] == "/api/ai/pchome-growth/ai-automation-readiness"
|
||||
assert payload["summary"]["safe_lane_count"] >= 4
|
||||
assert payload["summary"]["primary_human_gate_count"] == 0
|
||||
assert payload["summary"]["writes_database_count"] == 0
|
||||
assert set(signals) == {
|
||||
"automated-landing",
|
||||
"verified",
|
||||
"change-state",
|
||||
"next-machine-action",
|
||||
}
|
||||
assert signals["next-machine-action"]["next_machine_action"]
|
||||
assert payload["safety"]["writes_database"] is False
|
||||
assert payload["safety"]["llm_calls_in_preview"] is False
|
||||
|
||||
@@ -89,6 +89,7 @@ from services.pchome_mapping_backlog_service import (
|
||||
build_pchome_direct_mapping_retry_candidate_exception_closeout_verifier_input_package,
|
||||
build_pchome_direct_mapping_retry_candidate_exception_resolution_closeout_package,
|
||||
build_pchome_growth_ai_automation_readiness,
|
||||
build_pchome_growth_ai_automation_surface_summary,
|
||||
build_pchome_mapping_operator_preview,
|
||||
parse_pchome_product_page_evidence_html,
|
||||
parse_unit_package_basis,
|
||||
@@ -1684,6 +1685,97 @@ def test_ai_automation_readiness_surfaces_controlled_apply_drift_detected():
|
||||
assert readiness["safety"]["writes_database"] is False
|
||||
|
||||
|
||||
def test_ai_automation_surface_summary_turns_readiness_into_golden_signals():
|
||||
readiness = build_pchome_growth_ai_automation_readiness(
|
||||
_payload(),
|
||||
batch_size=1,
|
||||
controlled_apply_receipt_replay={
|
||||
"summary": {
|
||||
"target_selector_count": 4,
|
||||
"post_apply_readback_pass_count": 4,
|
||||
"executor_receipt_ready_count": 1,
|
||||
"executor_receipt_materialized_count": 1,
|
||||
"executor_receipt_hash_match_count": 1,
|
||||
},
|
||||
},
|
||||
controlled_apply_drift_verifier={
|
||||
"summary": {
|
||||
"target_selector_count": 4,
|
||||
"post_apply_readback_pass_count": 4,
|
||||
"drift_count": 0,
|
||||
"drift_verified_count": 1,
|
||||
"drift_verifier_artifact_materialized_count": 1,
|
||||
"drift_verifier_artifact_hash_match_count": 1,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
surface = build_pchome_growth_ai_automation_surface_summary(readiness)
|
||||
signals = {signal["key"]: signal for signal in surface["golden_signals"]}
|
||||
|
||||
assert surface["policy"] == "read_only_pchome_growth_ai_automation_surface_summary"
|
||||
assert surface["summary"]["safe_lane_count"] >= 4
|
||||
assert surface["summary"]["ready_lane_count"] >= 1
|
||||
assert surface["summary"]["completed_lane_count"] >= 1
|
||||
assert surface["summary"]["controlled_apply_replay_readback_pass_count"] == 4
|
||||
assert surface["summary"]["controlled_apply_drift_count"] == 0
|
||||
assert surface["summary"]["primary_human_gate_count"] == 0
|
||||
assert surface["summary"]["manual_required_as_primary_flow_count"] == 0
|
||||
assert surface["summary"]["writes_database_count"] == 0
|
||||
assert set(signals) == {
|
||||
"automated-landing",
|
||||
"verified",
|
||||
"change-state",
|
||||
"next-machine-action",
|
||||
}
|
||||
assert signals["automated-landing"]["label"] == "已自動落地"
|
||||
assert signals["verified"]["label"] == "已驗證"
|
||||
assert signals["change-state"]["label"] == "異動狀態"
|
||||
assert signals["next-machine-action"]["label"] == "下一步"
|
||||
assert signals["automated-landing"]["value"] == "已完成回讀"
|
||||
assert "4/4" in signals["automated-landing"]["detail"]
|
||||
assert signals["verified"]["value"] == "4 筆已回讀"
|
||||
assert signals["change-state"]["value"] == "無漂移"
|
||||
assert surface["surface_contract"]["first_viewport_required"] is True
|
||||
assert surface["surface_contract"]["raw_evidence_hidden_from_first_viewport"] is True
|
||||
assert surface["safety"]["writes_database"] is False
|
||||
assert surface["safety"]["llm_calls_in_preview"] is False
|
||||
|
||||
|
||||
def test_ai_automation_surface_summary_prioritizes_drift_recovery_action():
|
||||
readiness = build_pchome_growth_ai_automation_readiness(
|
||||
_payload(),
|
||||
batch_size=1,
|
||||
controlled_apply_receipt_replay={
|
||||
"summary": {
|
||||
"target_selector_count": 4,
|
||||
"post_apply_readback_pass_count": 3,
|
||||
"executor_receipt_ready_count": 0,
|
||||
"executor_receipt_materialized_count": 1,
|
||||
"executor_receipt_hash_match_count": 0,
|
||||
},
|
||||
},
|
||||
controlled_apply_drift_verifier={
|
||||
"summary": {
|
||||
"target_selector_count": 4,
|
||||
"post_apply_readback_pass_count": 3,
|
||||
"drift_count": 1,
|
||||
"drift_verified_count": 0,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
surface = build_pchome_growth_ai_automation_surface_summary(readiness)
|
||||
signals = {signal["key"]: signal for signal in surface["golden_signals"]}
|
||||
|
||||
assert surface["summary"]["controlled_apply_drift_count"] == 1
|
||||
assert surface["summary"]["next_machine_action"] == "執行漂移恢復、重新回讀與 rollback path 比對"
|
||||
assert signals["change-state"]["value"] == "1 筆漂移"
|
||||
assert signals["change-state"]["status"] == "bad"
|
||||
assert signals["next-machine-action"]["value"] == surface["summary"]["next_machine_action"]
|
||||
assert surface["safety"]["writes_database"] is False
|
||||
|
||||
|
||||
def test_ai_automation_readiness_reports_candidate_decisions_after_controlled_search():
|
||||
call_count = {"search": 0}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user