Return a valid absolute cutoff index from a summarization event.
This is the canonical explanation of the cutoff rule; the notice predicates
and the /offload accounting point here rather than restating it.
Summarization is non-destructive: it leaves state["messages"] intact and
applies the cutoff only when building a request. Any predicate that scans the
full persisted list must therefore discount messages below this index, or it
treats a notice the model cannot see as authoritative. Every caller that has a
message count in hand should pass it.
A cutoff past message_count is rejected rather than clamped. The SDK
reads that state as "everything was summarized"; here it means the message
list shrank after the summary was written, so the survivors are live turns
and trusting the stale index would discount them as invisible. Rejecting
forces a fresh notice instead. _effective_conversation in app.py makes
the same call for the same reason.
A _summarization_event mapping as persisted in state, or None.
Full persisted message count when bounds can be checked.