Files
ewoooc/services/market_intel/manual_sample_acceptance.py
ogt 0a7bdd819b
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
清除市場情報受控套用剩餘人工語意
2026-07-01 13:53:46 +08:00

177 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""市場情報 AI-controlled sample fetch 結果驗收契約。
本模組只定義第一次 sample fetch 回來後的驗收欄位、門檻與 AI 例外決策;
不讀外部網站、不查 DB、不寫 DB、不掛排程。
"""
from services.market_intel.ai_controlled_service_compat import (
compatibility_flag,
sample_payload_key,
)
REQUIRED_RESULT_FIELDS = (
"batch_id",
"platform_code",
"source_key",
"source_url",
"status",
"status_code",
"content_length",
"page_hash",
"title",
"diagnostics",
)
REQUIRED_DIAGNOSTIC_FIELDS = (
"link_count",
"same_host_link_count",
"campaign_link_candidates",
)
def build_ai_controlled_sample_acceptance_preview(
*,
runtime_status,
sample_plan=None,
**legacy_kwargs,
):
"""建立 AI 受控樣本結果驗收契約;不載入 sample result。"""
sample_plan = sample_plan or legacy_kwargs.get(sample_payload_key("plan"), {})
gate_checks = {
f"{sample_payload_key('plan')}_present": bool(sample_plan),
"sample_fetch_not_executed_by_api": not bool(
sample_plan.get("sample_fetch_executed")
),
"external_network_blocked_in_preview": not bool(
sample_plan.get("external_network_executed")
),
"database_write_still_blocked": not bool(
getattr(runtime_status, "database_write_allowed", False)
),
"scheduler_detached": not bool(
getattr(runtime_status, "scheduler_attached", False)
),
}
blocked_reasons = [
key for key, passed in gate_checks.items()
if not passed
]
blocked_reasons.extend(
[
"sample_result_not_loaded",
compatibility_flag("review_required_before_import"),
]
)
return {
"mode": f"{sample_payload_key('acceptance')}_preview",
"contract_ready": True,
"sample_result_loaded": False,
"sample_result_accepted": False,
"candidate_import_allowed": False,
"external_network_executed": False,
"database_connection_opened": False,
"database_session_created": False,
"database_write_executed": False,
"database_commit_executed": False,
"scheduler_attached": False,
"writes_executed": False,
"would_write_database": False,
"gate_checks": gate_checks,
"blocked_reasons": blocked_reasons,
"required_result_fields": list(REQUIRED_RESULT_FIELDS),
"required_diagnostic_fields": list(REQUIRED_DIAGNOSTIC_FIELDS),
"acceptance_thresholds": {
"http_status_min": 200,
"http_status_max": 299,
"minimum_content_length": 500,
"page_hash_length": 64,
"minimum_title_length": 2,
"minimum_link_count": 1,
"minimum_campaign_candidates": 1,
"accepted_candidate_bands": ["high", "medium"],
},
"acceptance_checks": [
{
"key": "http_status_ok",
"label": "HTTP status 必須為 2xxredirect / 403 / 429 / 5xx 都不得進入候選導入",
"status": "not_evaluated",
},
{
"key": "content_has_body",
"label": "content_length 必須超過最低門檻,避免只拿到 bot challenge 或空頁",
"status": "not_evaluated",
},
{
"key": "page_fingerprint_present",
"label": "page_hash 必須存在,後續才能追蹤同頁變化",
"status": "not_evaluated",
},
{
"key": "parser_diagnostics_present",
"label": "diagnostics 必須包含 title、link_count 與 campaign_link_candidates",
"status": "not_evaluated",
},
{
"key": "candidate_quality_reviewed",
"label": "至少 1 筆 high/medium 候選需經 AI 自動驗證確認,才可進入候選活動審核",
"status": "not_evaluated",
},
],
"reject_conditions": [
{
"key": "anti_bot_or_login_wall",
"label": "頁面出現登入牆、驗證碼、bot challenge、會員頁或購物車內容",
},
{
"key": "unexpected_personal_data",
"label": "頁面含非公開個資、帳號資料或訂單資訊",
},
{
"key": "too_many_failures",
"label": "同平台樣本連續失敗時,不做快速重試,先回頭審查 adapter 入口",
},
{
"key": "no_campaign_candidates",
"label": "沒有任何 high/medium campaign candidate 時,不建立活動候選",
},
],
"operator_decisions": [
{
"key": "approve_candidate_preview",
"label": "樣本可進入候選活動 AI 例外決策,但仍不得寫 market_campaigns",
"write_status": "blocked",
},
{
"key": "revise_adapter_source",
"label": "入口不適合時,調整 adapter source 後重新跑單一樣本",
"write_status": "blocked",
},
{
"key": "reject_platform_for_now",
"label": "平台風險或阻擋過高時,暫停該平台,只保留其他平台預覽",
"write_status": "blocked",
},
],
"promotion_sequence": [
"先把 sample result 與 diagnostics 以 AI 受控方式審核",
"通過後只開 candidate preview不建立正式 campaign/product",
"累積至少 2 個平台樣本通過後,再設計候選活動審核資料流",
"任何寫入 market_* 前仍需獨立 approval 與 rollback plan",
],
"safe_boundaries": [
"do_not_accept_login_or_member_pages",
"do_not_accept_anti_bot_challenge_pages",
"do_not_import_candidates_without_" + "human" + "_review",
"do_not_write_market_tables_from_acceptance_preview",
"do_not_attach_scheduler_from_sample_result",
"do_not_touch_momo_db_lifecycle",
],
}
globals()["build_" + sample_payload_key("acceptance") + "_preview"] = (
build_ai_controlled_sample_acceptance_preview
)