docs(identity): define person-state ownership boundaries - #6820
Conversation
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — docs-only update to an internal architecture spec.
This PR modifies a single file, specs/unified-relationship-model.md (+247/-68), making identities.id the canonical person seam, separating identity resolution from linking, and adding ownership/provenance, deletion, and privacy-fence rules. The reviewer found the change clean, internally consistent, and factually grounded against the shipped identities/identity_workos_users/person_relationships tables.
Gate checks:
- No critical/high findings (row 1 does not fire).
gated_pathsis false — the file is not on the published protocol surface (static/schemas/source/**,docs/reference/**, dist artifacts), so row 2 does not apply despitereview_decision: REVIEW_REQUIRED.high_riskis false; no deletions/modifications triggers (rows 3–5).- No prior decision (row 6 n/a).
- No no-auto-approve team match (row 7 n/a).
- Zero medium findings (row 8 n/a).
The file is an internal spec, not normative protocol surface, so the declared "no changeset" is correct. Falls through to row 9: approve.
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — clean pass on a single non-published design document.
This PR rewrites specs/unified-relationship-model.md (+713/-111), a non-published design doc that hardens Addie's relationship model around canonical identity ownership and a cross-surface privacy fence. No published protocol surface is touched (static/schemas/source/**, docs/reference/**, dist/** are all untouched), so no changeset/oneOf/immutability/patch-eligibility rule applies. Illustrative SQL/TS is internally consistent and fail-closed; destructive consolidation and cross-surface grant paths are gated behind #6491 and a ledger substrate.
Decision-table walk: no critical/high findings (row 1 n/a); gated_paths: false (row 2 n/a); high_risk: false (rows 3/5 n/a); no medium findings (rows 4/8 n/a); prior decision was approve so row 6 n/a; no no-auto-approve team match (row 7 n/a). Falls through to row 9 → approve. The single low finding is omitted from blocking output. review_decision: REVIEW_REQUIRED does not block since gated_paths is false.
Summary
identities.idthe canonical person seam and treatperson_relationshipsas an engagement facet rather than a competing identity authorityWhy
The original relationship spec predated the live identity layer and assumed one Slack ID, one WorkOS user, and one email per person. The live merge path also moves or deduplicates organization memberships and other provenance-bound state onto a canonical WorkOS user, while unlink creates an empty identity. That is neither authorization-safe nor reversible.
This is the contract needed before #6488, #6816, #6817, #6490, #6491, or #6489 move more application state onto
identity_id. The newly identified authorization prerequisite is tracked in #6827 and ordered before self-service recovery in #3590.Advances #6487 and #3590.
Expert review
Security, product, and data-model reviewers each reviewed the live implementation and the proposed contract. Their first and second passes identified blocking gaps around organization grant union, irreversible merges, unverified bindings, organization-scoped consent keys, capability subjects, source-fence provenance, and migration ordering. All three completed a final pass on the revised spec and reported no remaining blocker.
Validation
git diff --checknpm run precommit(67 test files / 1,052 tests, repository lint checks, and TypeScript typecheck)identity_workos_users, auth canonicalization, admin bind/unlink/promote flows, OAuth alias handling, community profile fields, points ledger, organization memberships, and billing ownershipChangeset
None. This updates an internal application architecture spec, not the published AdCP protocol package.