A guest's held pitch and the account's own held pitch collide at sign-in — which one survives, and how do you keep the merge idempotent?
answer
- soft collision versus scarce inventory
- release neither hold
- the guest record is the key
- mark migrated before destroying
- drop what claims to be a person's statement
basics
~20 sNeither is discarded automatically: surface both and let the camper choose, keeping both holds until they do. Idempotency comes from marking the guest record migrated before destroying it, so a retried sign-in finds nothing left to copy.
solid answer
~40 sOnce guest state can be carried across sign-in, the interesting case is when the account already has its own. A silent overwrite in either direction destroys something that cost a human money or a place in the inventory, so the honest default is to **surface the conflict and release neither hold** until the camper resolves it. Everything that does not conflict is merged without asking. Two properties keep it safe: the merge is **keyed on the guest record** and marks it `migrated_to` before destroying it, so a retried or double-submitted sign-in takes an early return instead of copying a second time; and identity-bearing guest data such as recorded consent is not carried at all, because an anonymous record from a shared counter terminal is not evidence that this human made those choices.
code
pseudocode · 14 lineson login_completed(guest_record_id, account_id):
guest = guest_store.get(guest_record_id)
if guest is missing or guest.migrated_to is set:
return # replay: this run has nothing to do
existing = holds.active_for(account_id)
if existing exists and guest.hold exists:
conflicts.open(account_id, guest.hold, existing) # release neither
else if guest.hold exists:
holds.transfer(guest.hold, to = account_id)
merge_non_conflicting(guest, account_id)
guest.migrated_to = account_id # marked BEFORE destroy, same transaction
guest_store.destroy(guest_record_id)go deeper
Know that the account may already hold something of its own, so carrying guest state across sign-in is not always a straight copy. Recognising that there is a conflict to resolve is the level-appropriate answer.
Explain the split between preferences, where a rule can decide silently, and scarce inventory, where a rule will occasionally destroy something a human paid for.
Demonstrate the production instinct: the sign-in handler gets retried, so the merge is keyed on the guest record and marks it migrated in the same transaction that performs the copy, before the record is destroyed.
Own the policy rather than the code: which classes of pre-identity state the business is willing to attach to an identity at all, and why a record from a shared terminal cannot support a claim about a person's consent.
## Two kinds of collision Carrying guest state across sign-in is easy while the authenticated side is empty. At a park's reservation counter it often is not: the camper phoned last week and already holds a pitch, and the browser they are standing at has a guest selection of its own. Two different things can collide, and they resolve differently. - **A soft collision** is two values for the same preference — a display language, a notification choice. Pick a rule, apply it silently, and move on; the account's own value is the better default because a proven human set it. - **A hard collision** is two claims on something scarce. A held pitch is an inventory reservation with a clock and often money attached. There is no rule that silently discards one of those without occasionally discarding the wrong one. ## Deciding who wins | Option | What it costs | |---|---| | Guest wins, account's hold released | Destroys a hold the camper may have paid for and travelled against, in service of a selection made minutes ago | | Account wins, guest selection dropped | Throws away the work the camper just did at the counter, which is the exact failure the migration existed to prevent | | Union both into one booking | Invents a reservation nobody asked for; scarce inventory does not merge | | Surface both, release neither, let the camper choose | One extra screen, and the only option that cannot silently destroy value | The fourth is the default worth arguing for, and the argument is not about correctness — all four are implementable — but about which failure you are willing to have. A conflict screen is an annoyance; a released hold is a phone call and a refund. Everything that does *not* conflict is merged in the same transaction without asking, so the camper sees one question rather than a wall of them. ## Making the merge safe to run twice The sign-in handler is one of the most re-run pieces of code in a service: a double-submitted form, a retried request after a timeout, a camper who hits back and signs in again. If "copy the guest hold onto the account" runs twice, the camper ends up holding two pitches, and the second one will not be noticed until the inventory report does not balance. The cheap fix is to make the guest record the key of the operation: 1. read the guest record; if it is missing or already carries a `migrated_to` value, return — this run has nothing to do; 2. do the merge, or record the conflict for the camper to resolve; 3. set `migrated_to` on the guest record **before** destroying it, in the same transaction as the merge; 4. destroy the guest record so no stale tab keeps writing to it. That ordering is what makes the replay branch real. Marking after a separate commit, or destroying without marking, both leave a window where a second run sees a record that still looks unmigrated. ## Why consent is not carried The scarce-inventory case gets the attention, but the quieter decision is about data that says something about a person. Recorded consent choices, a typed email address, a marketing preference: these are carried only if the anonymous record can be shown to have been this human. At a counter terminal used by several people across a shift, it frequently cannot — the record may hold the previous visitor's choices, and attaching them to a signed-in account is both wrong and, for consent specifically, a record you would not want to have to defend. The workable rule: **carry what the visitor would have to redo, re-derive what the account already knows, and drop what claims to be a statement by a person.** ## What to tell the visitor The conflict screen should name both holds in the camper's own terms — pitch, dates, what each one costs — and state what happens to the one they do not pick, including whether it is released immediately. A screen that says "you have a conflict" without saying what is at stake produces the same phone call as the silent overwrite, one step later. ## Answering it in an interview Separate soft from hard collisions in the first sentence, because most candidates give one rule for both. Then say the default — surface, release neither — and immediately follow with idempotency, because that is the part that bites in production and the part that shows you have run a sign-in handler that was retried.
- The camper never resolves the conflict screen. What happens to the two holds?Both run out their own inventory clocks and are released by the normal expiry path, and the conflict record expires with them. The important part is that nothing about the unresolved conflict extends either hold, so an abandoned decision cannot pin scarce inventory open indefinitely.
- Why key idempotency on the guest record rather than on the account?Because the guest record is what is being consumed, and there is exactly one of them per migration. Keying on the account cannot distinguish this sign-in's migration from the next one an hour later, so it would either block a legitimate second migration or fail to block a replay of the first.
- Is there any guest-side state you would let overwrite the account's own value silently?Something the visitor just chose deliberately and that costs nothing to be wrong about — a display language picked at the counter, say. The test is whether an incorrect choice is invisible and reversible in one click. Anything holding inventory, money, or a statement about a person fails that test.
saying these in an interview costs you the question
- Last write wins; the guest selection is newer so it overwrites.
- Always drop the guest hold, pre-identity state is never trustworthy.
- Merge both holds into one longer reservation.
- The sign-in handler only ever runs once, so replay is not a concern.
- Carry the consent choices over too, they were made in the same browser.
- Keep the guest record after merging in case the camper changes their mind.