"""C4 ``ISam2GraphHandle`` Protocol stub (AZ-355).

The C5 iSAM2 graph is the shared GTSAM substrate (ADR-003). C4
NEVER owns the graph — it receives a typed handle from the runtime
root and uses ONLY the minimum surface it needs to attach pose
factors against C5's key namespace.

Per the C4 contract this Protocol exposes ONLY
``get_pose_key(frame_id) -> int`` — the C5 concrete handle
(``components.c5_state._isam2_handle.ISam2GraphHandleImpl``) is
strictly a superset of this surface, so a duck-typed satisfaction
check via ``isinstance(handle, ISam2GraphHandle)`` succeeds without
C4 importing C5 internals.

Risk-1 mitigation per the AZ-355 task spec: if C5's graph design
grows, this stub grows ONLY if C4's needs grow. Otherwise the two
Protocols diverge cleanly along the producer/consumer split.
"""

from __future__ import annotations

from typing import Protocol, runtime_checkable

__all__ = ["ISam2GraphHandle"]


@runtime_checkable
class ISam2GraphHandle(Protocol):
    """Read-only view of C5's iSAM2 graph for C4's pose-factor adds."""

    def get_pose_key(self, frame_id: int) -> int:
        """Map a C4 frame_id to the corresponding GTSAM pose key.

        C5 owns the key allocation policy (typically
        ``gtsam.symbol('x', frame_id)``); C4 only needs the integer
        key to construct a ``PriorFactorPose3``.
        """
