"""Execution state helpers (decision deduplication, executions.json).""" import hashlib __all__ = [ "default_decision_id", "load_executions", "save_executions", "record_execution_state", "get_execution_state", ] from ..runtime import get_runtime_paths from .file_utils import load_json_locked, read_modify_write_json, save_json_locked def _paths(): return get_runtime_paths() def default_decision_id(action: str, argv_tail: list[str]) -> str: from datetime import datetime from .trade_common import CST now = datetime.now(CST) bucket_min = (now.minute // 15) * 15 bucket = now.strftime(f"%Y%m%dT%H{bucket_min:02d}") raw = f"{bucket}|{action}|{'|'.join(argv_tail)}" return hashlib.sha1(raw.encode()).hexdigest()[:16] def load_executions() -> dict: paths = _paths() data = load_json_locked(paths.executions_file, paths.executions_lock, {"executions": {}}) return data.get("executions", {}) # type: ignore[no-any-return] def save_executions(executions: dict): paths = _paths() save_json_locked(paths.executions_file, paths.executions_lock, {"executions": executions}) def record_execution_state(decision_id: str, payload: dict): paths = _paths() read_modify_write_json( paths.executions_file, paths.executions_lock, {"executions": {}}, lambda data: data.setdefault("executions", {}).__setitem__(decision_id, payload) or data, ) def get_execution_state(decision_id: str): return load_executions().get(decision_id)