按 docs/order-gateway.md 落地:第三个部署单元 app.gateway(:31109)承担任务队列 + 状态镜像;本地 worker 在 app.trading.worker 内,按 RAKUTEN_ORDER_GATEWAY_URL 决定是否启动。规格 §5 最关键约束已守:租约过期绝不自动重投,恢复只能 reclaim, worker 收到 lease_count>1 时先核对站点订单。 站点交互(加购/下单/付款/订单列表反查)按规格 §10 留接口缝,site_interact.py 全部 NotImplementedError,verify.py 恒返回 unknown——等真实账号实测后再填, 不写猜测的提交逻辑。 310 个测试全绿,覆盖规格 §9 验收清单 12 条;架构测试守住三方互不 import。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
57 lines
1.8 KiB
Python
57 lines
1.8 KiB
Python
"""证据落盘:HTML 快照、截图与 meta.json
|
|
|
|
规格 §6.1:每个任务一个子目录,按步骤序号命名文件。report 里的 evidence_ref
|
|
填 `{task_id}/{序号}-{步骤名}`,不含扩展名。
|
|
|
|
证据**只留本地**(约束 4),网关只存 evidence_ref 这个相对路径字符串。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import logging
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class EvidenceStore:
|
|
"""把每一步的页面快照、截图与 meta 落到 {evidence_dir}/{task_id}/ 下"""
|
|
|
|
def __init__(self, evidence_dir: Path):
|
|
self._root = evidence_dir
|
|
|
|
def step_dir(self, task_id: str) -> Path:
|
|
path = self._root / task_id
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
return path
|
|
|
|
def write_step(
|
|
self,
|
|
task_id: str,
|
|
step_no: int,
|
|
step_name: str,
|
|
*,
|
|
html: str | None = None,
|
|
png: bytes | None = None,
|
|
meta: dict[str, Any] | None = None,
|
|
) -> str:
|
|
"""写入一步的证据文件
|
|
|
|
返回相对 evidence_dir 的引用路径(不含扩展名),用于 report 的 evidence_ref
|
|
字段。文件命名:`{序号:02d}-{步骤名}.{html|png|meta.json}`。
|
|
"""
|
|
step_dir = self.step_dir(task_id)
|
|
stem = f"{step_no:02d}-{step_name}"
|
|
rel_stem = f"{task_id}/{stem}"
|
|
|
|
if html is not None:
|
|
(step_dir / f"{stem}.html").write_text(html, encoding="utf-8")
|
|
if png is not None:
|
|
(step_dir / f"{stem}.png").write_bytes(png)
|
|
if meta is not None:
|
|
(step_dir / f"{stem}.meta.json").write_text(
|
|
json.dumps(meta, ensure_ascii=False, indent=2), encoding="utf-8"
|
|
)
|
|
return rel_stem
|