/**
 * hosting/sessionOwnership — the ONE owner-transition rule, so four stores
 * cannot each get it slightly wrong (9.36.1).
 *
 * Every store implementing {@link SessionLifecycle} keeps an owner index, and
 * every one of them wrote the write-once rule out longhand in its own dialect:
 * a `COALESCE` in SQL, a `has()` on a `Map`, a read-then-decide inside a
 * transaction. Four spellings of one sentence, and all four were missing the
 * same half of it — which is what a rule that lives in prose rather than in
 * code eventually costs.
 *
 * ── The rule, whole ─────────────────────────────────────────────────────────
 * An owner is a fact about the CONVERSATION, established by the first turn
 * that signs for it. Given what is stored and what a turn is carrying:
 *
 *   | stored     | incoming   | outcome                                       |
 *   |------------|------------|-----------------------------------------------|
 *   | nobody     | nobody     | still nobody — an anonymous conversation       |
 *   | nobody     | somebody   | FILLED IN — the first turn that signs, owns    |
 *   | somebody   | nobody     | KEPT — a leaner turn erases nothing            |
 *   | somebody   | the same   | KEPT — the ordinary turn                       |
 *   | somebody   | DIFFERENT  | REFUSED, by name                               |
 *
 * The last row is the one that was missing, and the difference between the
 * last two rows is the whole design decision:
 *
 *  - **A different identity is a CONTRADICTION.** Two people cannot both have
 *    signed for one conversation. Keeping the index and storing the payload
 *    anyway — which is what every store did — leaves the index naming one
 *    person and the conversation naming another, and the person the index
 *    names opens it and reads the other one's conversation.
 *  - **An absent identity is not a contradiction.** It claims nobody. The
 *    contract blesses it in as many words ("a later turn carrying a leaner
 *    identity must not erase it"), and refusing it would fail a flow the
 *    library's own documentation describes as intended, to protect against a
 *    claim nobody made.
 *
 * ── Why this is a function and not a base class ─────────────────────────────
 * Stores share no ancestry and should not start now: one is a `Map`, one is a
 * SQL upsert, one is a distributed transaction, one is somebody's managed
 * service where the owner field is immutable. What they share is a DECISION,
 * so what they share is a decision function — called at the point each of them
 * already had to decide, inside whatever atomicity that store can offer.
 *
 * The atomicity is deliberately NOT this module's business, and cannot be: a
 * read-then-decide is only as safe as the transaction it happens inside, and
 * only the store knows what it has. What this owns is the answer; where it is
 * safe to ask is the store's own promise, and the conformance suite is what
 * checks that the store kept it (`contested-write-leaves-no-split-brain`).
 */
/**
 * Which owner a store should record, given what it already has and what the
 * turn being written is signed by — or a refusal.
 *
 * Call it INSIDE whatever the store uses to make read-then-write atomic (a
 * transaction, a lock, a single-threaded map), with the owner already derived
 * from the stored conversation by `envelopeOwner`. The return value is the
 * owner to store; a refusal means the whole `persist` must not land, including
 * the envelope.
 *
 * **The envelope is the part that matters.** A store that catches this and
 * writes the payload anyway has re-created the exact defect: the refusal
 * exists to stop the CONVERSATION being replaced, not merely to protect an
 * index column.
 *
 * Empty strings are read as "nobody" on both sides, matching `envelopeOwner`,
 * so a store that keeps `''` for an unowned row cannot accidentally make it a
 * principal that conflicts with everybody.
 *
 * @param sessionId  the id being written — the caller's own string, and the
 *   only thing the refusal repeats back.
 * @param storedOwner  the owner already recorded for this session, or
 *   `undefined` for a session that is new or that nobody has signed for.
 * @param incomingOwner  the owner derived from the envelope being written —
 *   `envelopeOwner(envelope)`, never anything a caller supplied.
 * @returns the owner to record. `undefined` means "record nobody".
 * @throws SessionOwnershipConflictError when the two name DIFFERENT people.
 *
 * @example  Inside a store's persist
 *   const incoming = envelopeOwner(checked);
 *   const owner = resolveSessionOwner(sessionId, rows.get(sessionId), incoming);
 *   // Only now — a refusal above must leave the stored conversation alone.
 *   rows.set(sessionId, checked);
 *   if (owner !== undefined) owners.set(sessionId, owner);
 */
export declare function resolveSessionOwner(sessionId: string, storedOwner: string | undefined, incomingOwner: string | undefined): string | undefined;
