feat(ai): add PixelRAG marketplace candidate knowledge replay
This commit is contained in:
@@ -1441,6 +1441,7 @@ def test_collect_ai_automation_smoke_uses_worst_status(monkeypatch):
|
||||
monkeypatch.setattr(smoke, "_pixelrag_marketplace_identity_matcher_replay_check", lambda: smoke._check("pixelrag marketplace identity matcher replay", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_marketplace_promotion_gate_replay_check", lambda: smoke._check("pixelrag marketplace promotion gate replay", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_marketplace_embedding_signature_guard_replay_check", lambda: smoke._check("pixelrag marketplace embedding signature guard replay", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_marketplace_candidate_knowledge_replay_check", lambda: smoke._check("pixelrag marketplace candidate knowledge replay", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_ocr_vlm_replay_check", lambda: smoke._check("pixelrag ocr vlm", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_vlm_route_readiness_check", lambda: smoke._check("pixelrag vlm route", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_vlm_replay_worker_check", lambda: smoke._check("pixelrag vlm worker", "ok", "ok"))
|
||||
@@ -1450,7 +1451,7 @@ def test_collect_ai_automation_smoke_uses_worst_status(monkeypatch):
|
||||
result = smoke.collect_ai_automation_smoke(record_history=False)
|
||||
|
||||
assert result["status"] == "critical"
|
||||
assert result["summary"] == {"ok": 42, "warning": 1, "critical": 1, "total": 44}
|
||||
assert result["summary"] == {"ok": 43, "warning": 1, "critical": 1, "total": 45}
|
||||
|
||||
|
||||
def test_pchome_controlled_apply_drift_monitor_reports_verified_zero_drift(monkeypatch):
|
||||
@@ -3986,6 +3987,7 @@ def test_collect_ai_automation_smoke_persists_recent_history(tmp_path, monkeypat
|
||||
monkeypatch.setattr(smoke, "_pixelrag_marketplace_identity_matcher_replay_check", lambda: smoke._check("pixelrag marketplace identity matcher replay", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_marketplace_promotion_gate_replay_check", lambda: smoke._check("pixelrag marketplace promotion gate replay", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_marketplace_embedding_signature_guard_replay_check", lambda: smoke._check("pixelrag marketplace embedding signature guard replay", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_marketplace_candidate_knowledge_replay_check", lambda: smoke._check("pixelrag marketplace candidate knowledge replay", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_ocr_vlm_replay_check", lambda: smoke._check("pixelrag ocr vlm", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_vlm_route_readiness_check", lambda: smoke._check("pixelrag vlm route", "ok", "ok"))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_vlm_replay_worker_check", lambda: smoke._check("pixelrag vlm worker", "ok", "ok"))
|
||||
@@ -4046,7 +4048,7 @@ def test_scheduled_automation_health_summary_reads_history_without_side_effects(
|
||||
json.dumps({
|
||||
"generated_at": datetime.now().isoformat(timespec="seconds"),
|
||||
"status": "ok",
|
||||
"summary": {"ok": 44, "warning": 0, "critical": 0, "total": 44},
|
||||
"summary": {"ok": 45, "warning": 0, "critical": 0, "total": 45},
|
||||
"checks": [
|
||||
{
|
||||
"name": "PChome 受控落地 drift monitor",
|
||||
@@ -4291,6 +4293,33 @@ def test_scheduled_automation_health_summary_reads_history_without_side_effects(
|
||||
"primary_human_gate_count": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "PixelRAG marketplace candidate knowledge replay",
|
||||
"status": "ok",
|
||||
"summary": "PixelRAG marketplace candidate knowledge replay candidates=1, ready=1, blocked=0, dry_run=1, executed=0, receipts=0, knowledge_candidates=2, internal_rag_ready=2, signatures=8c8063c66dbe",
|
||||
"details": {
|
||||
"policy": "controlled_pixelrag_marketplace_candidate_knowledge_replay_v1",
|
||||
"candidate_count": 1,
|
||||
"ready_count": 1,
|
||||
"blocked_count": 0,
|
||||
"dry_run_count": 1,
|
||||
"executed_count": 0,
|
||||
"receipt_written_count": 0,
|
||||
"capture_runtime_gap_count": 0,
|
||||
"knowledge_candidate_count": 2,
|
||||
"internal_rag_ready_count": 2,
|
||||
"expected_embedding_signatures": ["8c8063c66dbe"],
|
||||
"network_call_performed": False,
|
||||
"model_call_performed": False,
|
||||
"embedding_generation_performed": False,
|
||||
"artifact_write_performed": False,
|
||||
"writes_ai_insights": False,
|
||||
"writes_price_tables": False,
|
||||
"next_machine_action": "run_marketplace_candidate_knowledge_replay_execute",
|
||||
"writes_database_count": 0,
|
||||
"primary_human_gate_count": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "PixelRAG OCR/VLM replay contract",
|
||||
"status": "ok",
|
||||
@@ -4405,7 +4434,7 @@ def test_scheduled_automation_health_summary_reads_history_without_side_effects(
|
||||
)
|
||||
assert summary["policy"] == "read_only_ai_automation_scheduled_health_summary"
|
||||
assert summary["status"] == "ok"
|
||||
assert summary["summary"]["total"] == 41
|
||||
assert summary["summary"]["total"] == 42
|
||||
assert summary["summary"]["primary_human_gate_count"] == 0
|
||||
assert summary["summary"]["writes_database_count"] == 0
|
||||
assert pchome_family["status"] == "ok"
|
||||
@@ -6767,6 +6796,11 @@ def test_surface_html_readback_check_is_part_of_ai_smoke(monkeypatch):
|
||||
"ok",
|
||||
"pixelrag marketplace embedding signature guard replay ok",
|
||||
))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_marketplace_candidate_knowledge_replay_check", lambda: smoke._check(
|
||||
"PixelRAG marketplace candidate knowledge replay",
|
||||
"ok",
|
||||
"pixelrag marketplace candidate knowledge replay ok",
|
||||
))
|
||||
monkeypatch.setattr(smoke, "_pixelrag_ocr_vlm_replay_check", lambda: smoke._check(
|
||||
"PixelRAG OCR/VLM replay contract",
|
||||
"ok",
|
||||
@@ -6807,7 +6841,7 @@ def test_surface_html_readback_check_is_part_of_ai_smoke(monkeypatch):
|
||||
item for item in result["checks"]
|
||||
if item["name"] == "Sitewide visual QA readback"
|
||||
)
|
||||
assert result["summary"]["total"] == 44
|
||||
assert result["summary"]["total"] == 45
|
||||
assert surface_check["status"] == "ok"
|
||||
assert surface_check["details"]["checked_surface_count"] == 10
|
||||
assert sitewide_check["status"] == "ok"
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
def _signature_candidate(platform, manifest_id, index, embedding_signature):
|
||||
return {
|
||||
"candidate_id": f"{platform}:{manifest_id}:{index}",
|
||||
"candidate_index": index,
|
||||
"identity_fingerprint": f"identity-{platform}-{index}",
|
||||
"promotion_fingerprint": f"promotion-{platform}-{index}",
|
||||
"embedding_signature_guard_fingerprint": f"signature-guard-{platform}-{index}",
|
||||
"expected_embedding_signature": embedding_signature,
|
||||
"embedding_signature": embedding_signature,
|
||||
"guard_stage": "pre_candidate_knowledge_replay",
|
||||
"ready_for_candidate_knowledge_replay": True,
|
||||
"ready_for_ai_insights_write": False,
|
||||
"ready_for_price_table_write": False,
|
||||
"price_write_blocked_until_candidate_canary": True,
|
||||
"requires_candidate_knowledge_replay": True,
|
||||
"requires_embedding_signature_guard": True,
|
||||
"requires_source_provenance": True,
|
||||
"embedding_generation_performed": False,
|
||||
}
|
||||
|
||||
|
||||
def _write_embedding_signature_guard_receipt(
|
||||
root,
|
||||
*,
|
||||
platform="coupang_tw",
|
||||
manifest_id="coupang-403",
|
||||
adapter_code="coupang",
|
||||
barrier_type="access_denied",
|
||||
capture_runtime_unavailable=False,
|
||||
):
|
||||
from services.rag_service import get_embedding_signature
|
||||
|
||||
receipt_dir = root / platform / manifest_id
|
||||
receipt_dir.mkdir(parents=True)
|
||||
source_root = "runtime_artifacts"
|
||||
embedding_signature = get_embedding_signature()
|
||||
payload = {
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"policy": "controlled_pixelrag_marketplace_embedding_signature_guard_replay_v1",
|
||||
"worker_status": "executed_marketplace_embedding_signature_guard_replay_ready",
|
||||
"platform": platform,
|
||||
"manifest_id": manifest_id,
|
||||
"adapter_code": adapter_code,
|
||||
"embedding_signature_guard_replay_check_count": 24,
|
||||
"embedding_signature_guard_replay_check_pass_count": 24,
|
||||
"embedding_signature_guard_replay_checks": {
|
||||
"blocked_page_not_product_data": True,
|
||||
"candidate_knowledge_replay_ready": True,
|
||||
"database_write_disallowed": True,
|
||||
"direct_ai_insights_write_disallowed": True,
|
||||
"direct_price_write_disallowed": True,
|
||||
"embedding_generation_not_performed": True,
|
||||
"embedding_signature_guard_required": True,
|
||||
"embedding_signature_present": True,
|
||||
"model_call_disallowed": True,
|
||||
"network_call_disallowed": True,
|
||||
"price_write_blocked_until_candidate_canary": True,
|
||||
"receipt_fresh": True,
|
||||
"receipt_parse_ok": True,
|
||||
"required_promotion_gates_present": True,
|
||||
"signature_guard_contracts_generated": True,
|
||||
"source_provenance_paths_present": True,
|
||||
},
|
||||
"embedding_signature_guard_replay": {
|
||||
"embedding_signature_guard_replay_version": "pixelrag_marketplace_embedding_signature_guard_replay_v1",
|
||||
"promotion_gate_replay_version": "pixelrag_marketplace_promotion_gate_replay_v1",
|
||||
"identity_matcher_replay_version": "pixelrag_marketplace_identity_matcher_replay_v1",
|
||||
"adapter_dry_run_version": "pixelrag_marketplace_adapter_dry_run_v1",
|
||||
"adapter_preflight_version": "pixelrag_marketplace_adapter_preflight_v1",
|
||||
"source_contract_version": "pixelrag_marketplace_source_contract_v1",
|
||||
"contract_id": f"{platform}:{manifest_id}:{adapter_code}",
|
||||
"adapter_code": adapter_code,
|
||||
"barrier_type": barrier_type,
|
||||
"capture_runtime_unavailable": capture_runtime_unavailable,
|
||||
"input_embedding_signature_guard_receipt_path": (
|
||||
f"{source_root}/pixelrag_marketplace_embedding_signature_guard_replay_receipts/"
|
||||
f"{platform}/{manifest_id}/marketplace_embedding_signature_guard_replay_receipt.json"
|
||||
),
|
||||
"input_promotion_gate_receipt_path": (
|
||||
f"{source_root}/pixelrag_marketplace_promotion_gate_replay_receipts/"
|
||||
f"{platform}/{manifest_id}/marketplace_promotion_gate_replay_receipt.json"
|
||||
),
|
||||
"input_identity_matcher_receipt_path": (
|
||||
f"{source_root}/pixelrag_marketplace_identity_matcher_replay_receipts/"
|
||||
f"{platform}/{manifest_id}/marketplace_identity_matcher_replay_receipt.json"
|
||||
),
|
||||
"input_adapter_dry_run_receipt_path": (
|
||||
f"{source_root}/pixelrag_marketplace_adapter_dry_run_receipts/"
|
||||
f"{platform}/{manifest_id}/marketplace_adapter_dry_run_receipt.json"
|
||||
),
|
||||
"adapter_preflight_receipt_path": (
|
||||
f"{source_root}/pixelrag_marketplace_adapter_preflight_receipts/"
|
||||
f"{platform}/{manifest_id}/marketplace_adapter_preflight_receipt.json"
|
||||
),
|
||||
"source_contract_replay_receipt_path": (
|
||||
f"{source_root}/pixelrag_source_contract_replay_receipts/"
|
||||
f"{platform}/{manifest_id}/source_contract_replay_receipt.json"
|
||||
),
|
||||
"source_worker_receipt_path": (
|
||||
f"{source_root}/pixelrag_platform_probe_worker_receipts/"
|
||||
f"{platform}/{manifest_id}/platform_probe_worker_receipt.json"
|
||||
),
|
||||
"source_receipt_path": (
|
||||
f"{source_root}/pixelrag_visual_evidence/"
|
||||
f"{platform}/{manifest_id}/capture_receipt.json"
|
||||
),
|
||||
"embedding_signature_contract": {
|
||||
"embedding_signature": embedding_signature,
|
||||
"embedding_model": "bge-m3:latest",
|
||||
"embedding_dim": 1024,
|
||||
"embedding_normalize": True,
|
||||
"embedding_generation_performed": False,
|
||||
"model_call_performed": False,
|
||||
},
|
||||
"embedding_signature_guard_execution_mode": (
|
||||
"deterministic_signature_guard_only_no_embedding_no_network_no_db"
|
||||
),
|
||||
"signature_guard_candidate_count": 2,
|
||||
"signature_guard_candidate_contracts": [
|
||||
_signature_candidate(platform, manifest_id, 0, embedding_signature),
|
||||
_signature_candidate(platform, manifest_id, 1, embedding_signature),
|
||||
],
|
||||
"required_before_data_promotion": [
|
||||
"public_source_boundary",
|
||||
"rate_limit_contract",
|
||||
"provenance_contract",
|
||||
"identity_matcher_replay",
|
||||
"promotion_gate",
|
||||
"embedding_signature_guard",
|
||||
],
|
||||
"allowed_next_step": "run_marketplace_candidate_knowledge_replay",
|
||||
},
|
||||
"promotion_boundary": {
|
||||
"direct_ai_insights_write_allowed": False,
|
||||
"direct_price_write_allowed": False,
|
||||
"requires_candidate_knowledge_replay": True,
|
||||
},
|
||||
"writes_database": False,
|
||||
"writes_database_count": 0,
|
||||
"network_call_performed": False,
|
||||
"model_call_performed": False,
|
||||
"embedding_generation_performed": False,
|
||||
}
|
||||
path = receipt_dir / "marketplace_embedding_signature_guard_replay_receipt.json"
|
||||
path.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")
|
||||
return path
|
||||
|
||||
|
||||
def test_marketplace_candidate_knowledge_reads_signature_guard_receipts(tmp_path):
|
||||
from services.pixelrag_marketplace_candidate_knowledge_replay_service import (
|
||||
INTERNAL_RAG_TARGET,
|
||||
POLICY,
|
||||
run_pixelrag_marketplace_candidate_knowledge_replay,
|
||||
)
|
||||
from services.rag_service import get_embedding_signature
|
||||
|
||||
signature_root = tmp_path / "signature"
|
||||
_write_embedding_signature_guard_receipt(signature_root)
|
||||
_write_embedding_signature_guard_receipt(
|
||||
signature_root,
|
||||
platform="shopee_tw",
|
||||
manifest_id="shopee-runtime-gap",
|
||||
adapter_code="shopee",
|
||||
barrier_type="language_or_region_interstitial",
|
||||
capture_runtime_unavailable=True,
|
||||
)
|
||||
|
||||
payload = run_pixelrag_marketplace_candidate_knowledge_replay(
|
||||
embedding_signature_guard_receipt_root=signature_root,
|
||||
platform=("coupang_tw", "shopee_tw"),
|
||||
)
|
||||
by_platform = {item["platform"]: item for item in payload["worker_items"]}
|
||||
|
||||
assert payload["policy"] == POLICY
|
||||
assert payload["status"] == "ok"
|
||||
assert payload["summary"]["candidate_count"] == 2
|
||||
assert payload["summary"]["ready_count"] == 2
|
||||
assert payload["summary"]["dry_run_count"] == 2
|
||||
assert payload["summary"]["knowledge_candidate_count"] == 4
|
||||
assert payload["summary"]["internal_rag_ready_count"] == 4
|
||||
assert payload["summary"]["capture_runtime_gap_count"] == 1
|
||||
assert payload["summary"]["expected_embedding_signatures"] == [
|
||||
get_embedding_signature()
|
||||
]
|
||||
assert payload["summary"]["writes_database_count"] == 0
|
||||
assert payload["summary"]["writes_ai_insights"] is False
|
||||
assert payload["summary"]["writes_price_tables"] is False
|
||||
assert payload["controlled_apply"]["embedding_generation"] is False
|
||||
assert payload["controlled_apply"]["writes_ai_insights"] is False
|
||||
assert payload["promotion_boundary"]["writes_price_tables"] is False
|
||||
assert payload["next_machine_action"] == (
|
||||
"run_marketplace_candidate_knowledge_replay_execute"
|
||||
)
|
||||
assert by_platform["coupang_tw"]["worker_status"] == (
|
||||
"dry_run_ready_for_marketplace_candidate_knowledge_replay"
|
||||
)
|
||||
first_knowledge = by_platform["coupang_tw"]["candidate_knowledge_replay"][
|
||||
"candidate_knowledge_contracts"
|
||||
][0]
|
||||
assert first_knowledge["embedding_signature"] == get_embedding_signature()
|
||||
assert first_knowledge["internal_rag_target"] == INTERNAL_RAG_TARGET
|
||||
assert first_knowledge["ready_for_internal_rag_candidate_replay"] is True
|
||||
assert first_knowledge["ready_for_ai_insights_write"] is False
|
||||
assert first_knowledge["ready_for_price_table_write"] is False
|
||||
assert first_knowledge["price_write_blocked_until_candidate_canary"] is True
|
||||
assert by_platform["shopee_tw"]["candidate_knowledge_replay"][
|
||||
"capture_runtime_unavailable"
|
||||
] is True
|
||||
|
||||
|
||||
def test_marketplace_candidate_knowledge_execute_writes_receipt(tmp_path):
|
||||
from services.pixelrag_marketplace_candidate_knowledge_replay_service import (
|
||||
run_pixelrag_marketplace_candidate_knowledge_replay,
|
||||
)
|
||||
|
||||
signature_root = tmp_path / "signature"
|
||||
output_root = tmp_path / "knowledge"
|
||||
_write_embedding_signature_guard_receipt(signature_root)
|
||||
|
||||
payload = run_pixelrag_marketplace_candidate_knowledge_replay(
|
||||
embedding_signature_guard_receipt_root=signature_root,
|
||||
output_root=output_root,
|
||||
platform="coupang_tw",
|
||||
execute=True,
|
||||
write_receipt=True,
|
||||
)
|
||||
|
||||
assert payload["status"] == "ok"
|
||||
assert payload["summary"]["executed_count"] == 1
|
||||
assert payload["summary"]["receipt_written_count"] == 1
|
||||
assert payload["controlled_apply"]["artifact_write"] is True
|
||||
assert payload["controlled_apply"]["writes_database"] is False
|
||||
assert payload["next_machine_action"] == "run_internal_rag_candidate_canary"
|
||||
receipt_path = (
|
||||
output_root
|
||||
/ "coupang_tw"
|
||||
/ "coupang-403"
|
||||
/ "marketplace_candidate_knowledge_replay_receipt.json"
|
||||
)
|
||||
assert receipt_path.exists()
|
||||
receipt = json.loads(receipt_path.read_text(encoding="utf-8"))
|
||||
assert receipt["worker_status"] == (
|
||||
"executed_marketplace_candidate_knowledge_replay_ready"
|
||||
)
|
||||
assert receipt["artifact_write_performed"] is True
|
||||
assert receipt["writes_database"] is False
|
||||
assert receipt["writes_ai_insights"] is False
|
||||
assert receipt["writes_price_tables"] is False
|
||||
assert receipt["candidate_knowledge_replay_check_pass_count"] == (
|
||||
receipt["candidate_knowledge_replay_check_count"]
|
||||
)
|
||||
assert receipt["candidate_knowledge_replay"]["allowed_next_step"] == (
|
||||
"run_internal_rag_candidate_canary"
|
||||
)
|
||||
|
||||
|
||||
def test_marketplace_candidate_knowledge_cli_outputs_json(tmp_path):
|
||||
signature_root = tmp_path / "signature"
|
||||
_write_embedding_signature_guard_receipt(signature_root)
|
||||
|
||||
completed = subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
"scripts/ops/run_pixelrag_marketplace_candidate_knowledge_replay.py",
|
||||
"--embedding-signature-guard-receipt-root",
|
||||
str(signature_root),
|
||||
"--platform",
|
||||
"coupang_tw",
|
||||
],
|
||||
capture_output=True,
|
||||
check=False,
|
||||
text=True,
|
||||
)
|
||||
|
||||
assert completed.returncode == 0
|
||||
payload = json.loads(completed.stdout)
|
||||
assert payload["summary"]["candidate_count"] == 1
|
||||
assert payload["summary"]["ready_count"] == 1
|
||||
assert payload["summary"]["knowledge_candidate_count"] == 2
|
||||
assert payload["controlled_apply"]["writes_database"] is False
|
||||
assert payload["controlled_apply"]["writes_ai_insights"] is False
|
||||
|
||||
|
||||
def test_marketplace_candidate_knowledge_route_returns_readback(
|
||||
tmp_path,
|
||||
monkeypatch,
|
||||
):
|
||||
from flask import Flask
|
||||
from routes import system_public_routes as routes
|
||||
from services import (
|
||||
pixelrag_marketplace_candidate_knowledge_replay_service as service,
|
||||
)
|
||||
|
||||
signature_root = tmp_path / "signature"
|
||||
_write_embedding_signature_guard_receipt(signature_root)
|
||||
monkeypatch.setattr(
|
||||
service,
|
||||
"DEFAULT_EMBEDDING_SIGNATURE_GUARD_RECEIPT_ROOT",
|
||||
str(signature_root),
|
||||
)
|
||||
|
||||
app = Flask(__name__)
|
||||
with app.test_request_context(
|
||||
"/api/ai-automation/pixelrag-marketplace-candidate-knowledge-replay?platform=coupang_tw"
|
||||
):
|
||||
response = (
|
||||
routes
|
||||
.ai_automation_pixelrag_marketplace_candidate_knowledge_replay_api
|
||||
.__wrapped__()
|
||||
)
|
||||
payload = response.get_json()
|
||||
|
||||
assert payload["policy"] == (
|
||||
"controlled_pixelrag_marketplace_candidate_knowledge_replay_v1"
|
||||
)
|
||||
assert payload["summary"]["candidate_count"] == 1
|
||||
assert payload["summary"]["ready_count"] == 1
|
||||
assert payload["controlled_apply"]["writes_database"] is False
|
||||
assert payload["controlled_apply"]["writes_ai_insights"] is False
|
||||
Reference in New Issue
Block a user