Files
ewoooc/services/pixelrag_source_contract_replay_worker_service.py
ogt 05296f20c5
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
feat(ai): add PixelRAG source contract replay worker
2026-07-10 10:49:56 +08:00

365 lines
14 KiB
Python

"""Controlled PixelRAG source-contract replay worker.
This worker turns platform-probe structured fallback receipts into replayable
source-contract receipts. It does not fetch marketplace pages, call models,
write databases, or promote price truth.
"""
from __future__ import annotations
import json
import os
import re
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Mapping
from services.pixelrag_crawler_integration_service import DEFAULT_ARTIFACT_MAX_AGE_HOURS
from services.pixelrag_rag_candidate_replay_service import (
DEFAULT_PLATFORM_PROBE_WORKER_RECEIPT_ROOT,
build_pixelrag_rag_candidate_replay_readback,
)
POLICY = "controlled_pixelrag_source_contract_replay_worker_v1"
SOURCE_CONTRACT_VERSION = "pixelrag_marketplace_source_contract_v1"
DEFAULT_LIMIT = 25
DEFAULT_OUTPUT_ROOT = os.getenv(
"PIXELRAG_SOURCE_CONTRACT_REPLAY_RECEIPT_ROOT",
"/app/data/ai_automation/pixelrag_source_contract_replay_receipts"
if Path("/app/data").exists()
else "runtime_artifacts/pixelrag_source_contract_replay_receipts",
)
def _normalise_platforms(
platform: str | tuple[str, ...] | list[str] | None,
) -> tuple[str, ...]:
if isinstance(platform, str):
value = platform.strip().lower()
return (value,) if value else ()
return tuple(
str(item or "").strip().lower()
for item in (platform or ())
if str(item or "").strip()
)
def _safe_segment(value: Any) -> str:
text = str(value or "unknown").strip().lower()
text = re.sub(r"[^a-z0-9._-]+", "-", text)
return text.strip("-") or "unknown"
def _source_contract_candidates(readback: Mapping[str, Any]) -> list[dict[str, Any]]:
candidates: list[dict[str, Any]] = []
for item in list(readback.get("candidates") or []):
if not isinstance(item, Mapping):
continue
if item.get("candidate_status") != "source_contract_fallback":
continue
if not item.get("eligible_for_source_contract_replay"):
continue
candidates.append(dict(item))
return candidates
def _contract_checks(candidate: Mapping[str, Any]) -> dict[str, bool]:
worker = candidate.get("platform_probe_worker")
if not isinstance(worker, Mapping):
worker = {}
package = worker.get("structured_source_package")
if not isinstance(package, Mapping):
package = {}
return {
"structured_source_package_available": bool(package.get("available")),
"source_count_positive": int(package.get("source_count") or 0) > 0,
"database_write_disallowed": not bool(package.get("database_write_allowed")),
"network_request_deferred": not bool(package.get("network_request_allowed")),
"dry_run_only_contract": bool(package.get("dry_run_only")),
"blocked_page_not_product_data": bool(package.get("blocked_page_not_product_data")),
"source_worker_receipt_path_present": bool(candidate.get("receipt_path")),
"source_receipt_path_present": bool(worker.get("source_receipt_path")),
}
def _source_contract_preview(candidate: Mapping[str, Any]) -> dict[str, Any]:
worker = candidate.get("platform_probe_worker")
if not isinstance(worker, Mapping):
worker = {}
package = worker.get("structured_source_package")
if not isinstance(package, Mapping):
package = {}
platform = str(candidate.get("platform") or "unknown")
manifest_id = str(candidate.get("manifest_id") or "unknown")
adapter_code = str(package.get("adapter_code") or platform)
return {
"source_contract_version": SOURCE_CONTRACT_VERSION,
"contract_id": f"{platform}:{manifest_id}:{adapter_code}",
"adapter_code": adapter_code,
"source_count": int(package.get("source_count") or 0),
"capture_runtime_unavailable": bool(package.get("capture_runtime_unavailable")),
"barrier_type": worker.get("barrier_type"),
"expected_offer_fields": [
"platform",
"platform_product_id",
"title",
"url",
"image_url",
"price",
"currency",
"availability",
"seller",
"promotion_badges",
"shipping_badges",
"evidence_time",
"source_method",
"confidence",
],
"required_before_data_promotion": [
"public_source_boundary",
"rate_limit_contract",
"provenance_contract",
"identity_matcher_replay",
"promotion_gate",
"embedding_signature_guard",
],
}
def _worker_item(
candidate: Mapping[str, Any],
*,
execute: bool,
) -> dict[str, Any]:
checks = _contract_checks(candidate)
check_count = len(checks)
pass_count = sum(1 for passed in checks.values() if passed)
ready = pass_count == check_count
worker = candidate.get("platform_probe_worker")
if not isinstance(worker, Mapping):
worker = {}
package = worker.get("structured_source_package")
if not isinstance(package, Mapping):
package = {}
status = (
"executed_source_contract_replay_ready"
if execute and ready
else (
"dry_run_ready_for_source_contract_replay"
if ready
else "skipped_source_contract_guard_failed"
)
)
return {
"worker_status": status,
"platform": candidate.get("platform"),
"manifest_id": candidate.get("manifest_id"),
"source_type": "platform_probe_worker_receipt",
"source_worker_receipt_path": candidate.get("receipt_path"),
"source_receipt_path": worker.get("source_receipt_path"),
"source_contract_status": "ready" if ready else "blocked",
"ready_for_execution": ready,
"execute": bool(execute),
"adapter_code": package.get("adapter_code"),
"structured_source_count": int(package.get("source_count") or 0),
"capture_runtime_unavailable": bool(package.get("capture_runtime_unavailable")),
"barrier_type": worker.get("barrier_type"),
"network_call_performed": False,
"model_call_performed": False,
"artifact_write_performed": False,
"writes_database": False,
"writes_database_count": 0,
"primary_human_gate_count": 0,
"source_contract_checks": checks,
"source_contract_check_count": check_count,
"source_contract_check_pass_count": pass_count,
"source_contract_preview": _source_contract_preview(candidate),
"promotion_boundary": {
"direct_ai_insights_write_allowed": False,
"direct_price_write_allowed": False,
"source_contract_is_candidate_only": True,
"requires_public_source_boundary": True,
"requires_rate_limit_contract": True,
"requires_provenance_contract": True,
"requires_identity_matcher_replay": True,
"requires_promotion_gate": True,
"requires_embedding_signature_guard": True,
},
"next_machine_action": (
"run_marketplace_source_contract_adapter_replay_preflight"
if execute and ready
else (
"run_pixelrag_source_contract_replay_worker_execute"
if ready
else "repair_source_contract_fallback_package"
)
),
}
def _write_replay_receipt(*, output_root: Path, item: Mapping[str, Any]) -> str:
target = (
output_root
/ _safe_segment(item.get("platform"))
/ _safe_segment(item.get("manifest_id"))
/ "source_contract_replay_receipt.json"
)
target.parent.mkdir(parents=True, exist_ok=True)
receipt = dict(item)
receipt["artifact_write_performed"] = True
receipt["receipt_path"] = str(target)
receipt["generated_at"] = datetime.now(timezone.utc).isoformat()
receipt["policy"] = POLICY
target.write_text(
json.dumps(receipt, ensure_ascii=False, indent=2, sort_keys=True),
encoding="utf-8",
)
return str(target)
def run_pixelrag_source_contract_replay_worker(
*,
artifact_root: str | Path | None = None,
platform_probe_worker_receipt_root: str | Path | None = None,
output_root: str | Path | None = None,
platform: str | tuple[str, ...] | list[str] | None = None,
max_age_hours: int | None = None,
limit: int | None = None,
execute: bool = False,
write_receipt: bool = False,
) -> dict[str, Any]:
"""Run or dry-run source-contract replay for platform probe worker receipts."""
output = Path(output_root or DEFAULT_OUTPUT_ROOT)
worker_root = Path(
platform_probe_worker_receipt_root
or DEFAULT_PLATFORM_PROBE_WORKER_RECEIPT_ROOT
)
platforms = _normalise_platforms(platform)
max_age = max(1, int(max_age_hours or DEFAULT_ARTIFACT_MAX_AGE_HOURS))
item_limit = max(1, min(int(limit or DEFAULT_LIMIT), 250))
readback = build_pixelrag_rag_candidate_replay_readback(
artifact_root=artifact_root,
platform_probe_worker_receipt_root=worker_root,
platform=platforms,
max_age_hours=max_age,
limit=item_limit,
)
candidates = _source_contract_candidates(readback)
worker_items: list[dict[str, Any]] = []
for candidate in candidates:
item = _worker_item(candidate, execute=execute)
if execute and write_receipt and item.get("ready_for_execution"):
item["receipt_path"] = _write_replay_receipt(output_root=output, item=item)
item["artifact_write_performed"] = True
worker_items.append(item)
ready_count = sum(1 for item in worker_items if item.get("ready_for_execution"))
blocked_count = len(worker_items) - ready_count
dry_run_count = sum(
1 for item in worker_items if str(item.get("worker_status") or "").startswith("dry_run_")
)
executed_count = sum(
1 for item in worker_items if str(item.get("worker_status") or "").startswith("executed_")
)
receipt_written_count = sum(1 for item in worker_items if item.get("receipt_path"))
capture_runtime_gap_count = sum(
1 for item in worker_items if item.get("capture_runtime_unavailable")
)
guard_failed_count = sum(
1 for item in worker_items if item.get("source_contract_status") != "ready"
)
if not worker_items:
status = "warning"
elif guard_failed_count:
status = "warning"
else:
status = "ok"
if not worker_items:
next_action = "run_pixelrag_platform_probe_worker_or_rag_candidate_replay"
elif not execute and ready_count:
next_action = "run_pixelrag_source_contract_replay_worker_execute"
elif execute and receipt_written_count:
next_action = "run_marketplace_source_contract_adapter_replay_preflight"
elif guard_failed_count:
next_action = "repair_source_contract_fallback_package"
else:
next_action = "refresh_pixelrag_source_contract_replay_candidates"
summary = {
"candidate_count": len(worker_items),
"ready_count": ready_count,
"blocked_count": blocked_count,
"dry_run_count": dry_run_count,
"executed_count": executed_count,
"receipt_written_count": receipt_written_count,
"capture_runtime_gap_count": capture_runtime_gap_count,
"guard_failed_count": guard_failed_count,
"platforms": sorted({str(item.get("platform") or "unknown") for item in worker_items}),
"network_call_performed": False,
"model_call_performed": False,
"artifact_write_performed": bool(receipt_written_count),
"writes_database_count": 0,
"primary_human_gate_count": 0,
}
return {
"success": status != "critical",
"policy": POLICY,
"status": status,
"generated_at": datetime.now(timezone.utc).isoformat(),
"source_contract_version": SOURCE_CONTRACT_VERSION,
"artifact_root": str(artifact_root or readback.get("artifact_root") or ""),
"platform_probe_worker_receipt_root": str(worker_root),
"output_root": str(output),
"platform_filter": list(platforms),
"max_age_hours": max_age,
"limit": item_limit,
"execute": bool(execute),
"write_receipt": bool(write_receipt and execute),
"summary": summary,
"worker_items": worker_items,
"source_readback": {
"policy": readback.get("policy"),
"status": readback.get("status"),
"summary": readback.get("summary"),
"next_machine_action": readback.get("next_machine_action"),
},
"controlled_apply": {
"network_call": False,
"model_call": False,
"artifact_write": bool(receipt_written_count),
"db_write": False,
"writes_database": False,
"writes_database_count": 0,
"secret_read": False,
"raw_cookie_or_session_read": False,
"credentialed_session_allowed": False,
"login_allowed": False,
"production_price_write": False,
"primary_human_gate_count": 0,
},
"promotion_boundary": {
"writes_ai_insights": False,
"writes_price_tables": False,
"source_contract_is_candidate_only": True,
"blocked_pages_are_not_product_data": True,
"requires_public_source_boundary": True,
"requires_rate_limit_contract": True,
"requires_provenance_contract": True,
"requires_identity_matcher_replay": True,
"requires_promotion_gate": True,
"requires_embedding_signature_guard": True,
},
"next_machine_action": next_action,
}
__all__ = [
"DEFAULT_OUTPUT_ROOT",
"POLICY",
"SOURCE_CONTRACT_VERSION",
"run_pixelrag_source_contract_replay_worker",
]