# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-should-an-instance-treat-lossy-summarized-checkpoint-recovery-as-a-compaction-invariant-rather-than-a-retry.md
# Remnant Warrant:    https://corpusfetch.com/c/how-should-an-instance-treat-lossy-summarized-checkpoint-recovery-as-a-compaction-invariant-rather-than-a-retry.warrant.json
# Markdown SHA-256:   107ab85328ca57eb7952a4c35e9001adc35e0ca126881f587dc9fb67632e3f18
# Code AST SHA-256:   97e356abb1fde3e1f5c47abd3cbb43633a18915e72aa9ab3a4ffa28b1b046a26
# Verified Classes:   SummaryReconciliationError
# Defensive Guards:   4 fail-closed invariants (zero external deps)

class SummaryReconciliationError(RuntimeError):
    """Raised when a lossy summary cannot be safely resumed from.

    Carries the summary generation, the checkpoint turn index, and the
    reference that could not be located verbatim, so an outer controller
    can choose replay-from-exact or explicit divergence acceptance.
    """

    def __init__(self, summary_generation, checkpoint_turn, missing_ref, reason):
        self.summary_generation = summary_generation
        self.checkpoint_turn = checkpoint_turn
        self.missing_ref = missing_ref
        self.reason = reason
        super().__init__(
            f"summary gen={summary_generation} vs checkpoint turn={checkpoint_turn}: "
            f"cannot resume; missing {missing_ref!r} ({reason})"
        )


def resume_from_checkpoint(checkpoint, next_turn_deps):
    """Resume only if the summary is generation-consistent and self-contained.

    Fails closed into reconciliation instead of re-deriving dropped facts.
    """
    summary = checkpoint.summary
    if summary is None:
        raise SummaryReconciliationError(
            summary_generation=None,
            checkpoint_turn=checkpoint.turn,
            missing_ref="<summary>",
            reason="checkpoint carries no summary",
        )

    if summary.generation != checkpoint.summary_generation:
        raise SummaryReconciliationError(
            summary_generation=summary.generation,
            checkpoint_turn=checkpoint.turn,
            missing_ref="<generation>",
            reason="summary generation does not match checkpoint",
        )

    if summary.partial:
        raise SummaryReconciliationError(
            summary_generation=summary.generation,
            checkpoint_turn=checkpoint.turn,
            missing_ref="<partial-write>",
            reason="checkpoint captured a half-written summary",
        )

    for ref in next_turn_deps:
        if ref not in summary.verbatim_refs:
            raise SummaryReconciliationError(
                summary_generation=summary.generation,
                checkpoint_turn=checkpoint.turn,
                missing_ref=ref,
                reason="dependency not present verbatim; re-derivation is not recovery",
            )

    return checkpoint.resume_context()
