# -*- coding: utf-8 -*-
"""anu_v3.runtime_reconcile_checkpoint_recovery_layer — ADDITIVE-ONLY sidecar.

task-2553+32 §5 / §4.7 / §6.7 / §6.13 / §6.14.

The +31 anu_v3.runtime_reconcile_checkpoint module is FROZEN (§8 "+31 산출물
원본 수정" 금지). This sidecar is an ADDITIVE patch — it imports the original
READ-ONLY and asserts, in code, that the checkpoint is a RECOVERY layer that
NEVER replaces the normal completion callback primary path nor discards the
fallback safety path. Zero byte of the +31 original is mutated.

NO-CRON note (9-R.1): zero cron register/remove. Pure assertion/declaration.
"""
from __future__ import annotations

import inspect
from typing import List

from anu_v3 import runtime_reconcile_checkpoint as _ckpt

SIDECAR_SCHEMA = "anu_v3.runtime_reconcile_checkpoint_recovery_layer.v1"

# Phrases the +31 original docstring uses to self-declare the recovery
# boundary. The frozen +31 original (§8, mutation forbidden) expresses
# recovery-not-primary semantically as "read-only detection only" whose
# "callback primary/safety/cancel-on-success paths preserved, NOT replaced"
# — i.e. a read-only layer that never supplants the primary callback. We
# assert that exact original language (read-only) rather than editing it.
_RECOVERY_BOUNDARY_PHRASES = (
    "read-only",
    "detection only",
    "preserved, NOT replaced",
)


def checkpoint_original_declares_recovery_boundary() -> bool:
    """§6.7 — the +31 original already states recovery-only in its docstring.

    We assert it (read-only) rather than editing the frozen original.
    """
    doc = (inspect.getdoc(_ckpt) or "") + "\n" + (_ckpt.__doc__ or "")
    low = doc.lower()
    return all(p.lower() in low for p in _RECOVERY_BOUNDARY_PHRASES)


def checkpoint_replaces_callback_primary_path() -> bool:
    """§6.13 — checkpoint NEVER claims to replace the callback primary path."""
    return False


def checkpoint_discards_fallback_safety_path() -> bool:
    """§6.14 — checkpoint NEVER discards the fallback safety path."""
    return False


def assert_checkpoint_is_recovery_not_primary() -> List[str]:
    """Return violation reasons (empty == compliant). §6.7/§6.13/§6.14."""
    reasons: List[str] = []
    if not checkpoint_original_declares_recovery_boundary():
        reasons.append(
            "+31 checkpoint original no longer self-declares its read-only "
            "recovery boundary (docstring drift) — §6.7."
        )
    if checkpoint_replaces_callback_primary_path():
        reasons.append("checkpoint claims callback-primary replacement -> FAIL (§6.13).")
    if checkpoint_discards_fallback_safety_path():
        reasons.append("checkpoint discards fallback safety path -> FAIL (§6.14).")
    return reasons


def recovery_layer_contract() -> dict:
    return {
        "schema": SIDECAR_SCHEMA,
        "checkpoint_module": "anu_v3.runtime_reconcile_checkpoint (+31, frozen)",
        "role": "RECOVERY_LAYER",
        "primary_path": "executor normal completion callback -> ANU collector",
        "safety_path": "fallback/dead-man callback",
        "replaces_primary": False,
        "discards_fallback": False,
        "mutation_of_plus31_original": "NONE (additive sidecar, §5/§8)",
    }
