Uh oh!
There was an error while loading. Please reload this page.
R-X5: a guest id cannot yet be held as an external reference - #19
Merged
Conversation
The point of a golden profile is that other systems can store its guestId as
the authoritative reference for a person. They cannot today, and the way it
fails is quiet.
A merge deletes the absorbed guest, so GET /guests/{absorbedId} answers a bare
404 — "No guest … in this tenant", as if the person had never existed. The
reference breaks on exactly the event this product exists to produce. An
unmerge that empties a guest retires an id the same way, so the mapping is not
always one-to-one either.
Observed rather than inferred: ingest two records that resolve separately, then
one carrying both identifiers. The merge reports MERGED and the absorbed id
404s. No test covered this, which is why it went unnoticed.
Nothing is actually lost. merge_event is append-only and already records both
the survivor and absorbed_guest_ids — the answer is stored, no query walks it.
What is missing is that a retired id should resolve instead of disappearing:
200 {"status":"MERGED","currentGuestId":…}, an HTTP-shaped redirect for
identity, transitive across merge chains and fanning out when an unmerge split
one id into several.
Slice 4 now carries a directive to consume this. Connectors are the first real
holders of a guestId — writing one back into a PMS is what makes GuestGraph the
system of record rather than a report — and that write-back is unsafe while a
merge can silently invalidate the key, because the connector cannot tell that
it broke.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The point of a golden profile is that other systems can hold its
guestIdas the authoritative reference for a person — a PMS or CRM storing it as a foreign key. That is what makes GuestGraph the system of record for identity rather than a de-duplication report.They cannot today, and the way it fails is quiet.
The gap
A merge deletes the absorbed guest (
ResolutionEngine.execute→deleteGuest), so the id simply stops existing. Observed, not inferred — ingest two records that resolve separately, then one carrying both identifiers:The reference breaks on exactly the event this product exists to produce. An unmerge that empties a guest retires an id the same way (
UnmergeOperation), so the mapping is not always 1:1:No test covered this, which is why it went unnoticed.
Nothing is lost — no query walks it
merge_eventis append-only and already records both the survivor (guest_id) andabsorbed_guest_ids. The answer is stored; there is simply no path that dereferences a retired id.What R-X5 asks for:
GET /guests/{id}on a retired id returns200 {"status":"MERGED","currentGuestId":…,"mergedAt":…}instead of 404 — an HTTP-shaped redirect for identity.Why slice 4 now carries a directive to consume it
Connectors are the first real holders of a
guestId. Writing one back into a PMS is precisely the "authoritative reference in another system" case — and it is unsafe while a merge can silently invalidate the key, because the connector cannot tell that it broke. Its foreign key looks fine right up until it doesn't.So slice 4 must either build the resolution endpoint or state the constraint in the connector contract, so no integrator stores an id believing it is stable.
What is deliberately not here
No test asserting the 404. It is the current behaviour but the wrong behaviour, and a characterization test would lock in something we intend to change. The probe ran, proved the point, and was deleted.
Documentation only — no code changes.
🤖 Generated with Claude Code