"""The declarative, versioned gate + promotion POLICY (sub-project B1).

Single source for the gate/promotion DEFAULTS that used to be scattered as module constants in
reconciliation_gate.py + inline literals in gate.py. Per-track overrides still live in the registry
gate_spec; `resolve_policy` (gate_policy_resolve.py) layers them on top. A policy change = a code commit +
a POLICY_VERSION bump; the content-derived `policy_hash` self-check test forces the bump (mirrors sub-project
A's definition_version discipline). Every gate verdict is stamped with (POLICY_VERSION, policy_hash) for
audit — 'PASSed under policy v3' is queryable."""
from __future__ import annotations

import hashlib
import json
from dataclasses import asdict, dataclass


@dataclass(frozen=True, slots=True)
class GatePolicy:
    # reconciliation gate
    min_forward_days: int = 14
    recon_tolerance_frac: float = 0.5
    recon_min_band: float = 0.05
    recon_min_corr: float = 0.0
    max_gap_days: int = 1
    # absolute gate
    min_days: int = 20
    min_total_return: float = 0.0
    min_sharpe: float = 0.0
    # promotion (research -> deploy) correlation backstop
    promotion_max_corr: float = 0.5
    promotion_min_overlap_days: int = 10
    # funding revocation on sustained decay (B3): consecutive DIVERGENCE days that de-fund, and consecutive
    # PASS days that re-fund. Asymmetric (quicker to de-risk, slower to re-arm capital). Debounce over an
    # already-cumulative gate signal.
    defund_window: int = 10
    refund_window: int = 15


POLICY = GatePolicy()
POLICY_VERSION = 2


def policy_hash(policy: GatePolicy, version: int) -> str:
    canonical = json.dumps(asdict(policy), sort_keys=True, separators=(",", ":"))
    return hashlib.sha256(f"{canonical}|v{version}".encode()).hexdigest()
