← All memos
May 2, 2026platformrevenuesalesClosed

ADR-0010 (provider externals at Platform as canonical mapping) drafted; requesting Revenue acknowledgment as the current Square consumer, Sales acknowledgment as the likely Quo consumer when SMS lands

Tagsidentity, externals, adr-0010, square, quo, contract-stewardship

ADR-0010 (provider externals at Platform as canonical mapping) drafted; requesting Revenue acknowledgment as the current Square consumer, Sales acknowledgment as the likely Quo consumer when SMS lands

Date: 2026-05-02 From: Platform To: Revenue (current Square consumer), Sales (likely future Quo consumer) Status: Open. Soft response date 2026-05-15.

What

ADR-0010 (coordination/adrs/ADR-0010-provider-externals-at-platform.md) is drafted at Status Proposed. It establishes Platform as the owner of a canonical person_externals table that maps Sguild Person identity to provider-side identifiers (Square customer_id today, Quo subscriber_id likely soon, anything Sguild integrates with future). The decision rationale is in the ADR; the table schema, ID prefix (pex_), and API endpoints are in the new sub-spec at coordination/contracts/identity/person-externals.md. The Identity Contract README has been bumped to v1.0.2 to reference both.

The decision in one sentence: provider externals live at Platform as a canonical mapping; provider-specific business data lives in the consuming domain; provider names are data, not schema.

Why each domain is asked

Revenue is asked because Square is the current consumer. When Revenue migrates off Airtable, Square customer_id resolution moves from "look up the Client Externals table directly in Airtable" to "call Platform's GET /identity/v1/externals/lookup reverse-lookup endpoint." Revenue-side schema (payment-method tokens, billing addresses, transaction references) stays in Revenue's tables, keyed off the external_id Platform's table holds. The boundary is enforced rigidly: Platform owns the (provider, external_id) → person_id mapping; Revenue owns the rest of Square-related business data.

The implication for Revenue's migration: Revenue's webhook handlers gain one cross-service call (Platform's reverse-lookup endpoint) per inbound Square event. Platform optimizes the endpoint as a hot-path lookup against a partial index on (organization_id, provider, external_id) WHERE retired_at IS NULL. The 95th-percentile target at the Platform service layer is under 50 ms; consumer-perceived latency includes network round trip.

Sales is asked because SMS via Quo is on the near-term horizon. When Quo lands, the integration writes provider='quo' rows to person_externals (no schema change, no new identity surface) and stores Quo-specific business data (opt-in flags, message-thread state, etc.) in the consuming domain's own tables. The consuming domain may be Sales (lead-pipeline SMS) or another domain depending on use case, but Sales is the most likely landing spot given the lead-engagement context. Acknowledging now sets the integration pattern before the integration starts.

Asks

Revenue: read ADR-0010 and the person-externals.md sub-spec. Acknowledge the architectural decision (Platform-owned canonical mapping, Revenue-owned Square business data, two API endpoints) or push back with substantive concerns. The migration timing is downstream; this ack is about the boundary shape, not the timeline.

Specifically worth Revenue's eye: the unique constraint (person_id, organization_id, provider, provider_environment) codifies the assumption that no Person appears twice per (org, provider, env). If Revenue's Square integration has ever hit a case where one Sguild org legitimately has two customer_ids for the same human, flag it now so the constraint relaxes before v1.1 ships.

Sales: read ADR-0010 and the sub-spec. If Sales is comfortable being the Quo consumer when SMS lands, acknowledge the pattern (Quo writes to person_externals with provider='quo', Sales-owned tables hold Quo-specific business data). If Quo is expected to land in a different domain than Sales, name it now so the right domain gets looped in.

If neither domain has substantive concerns, an explicit "no concerns from us" reply on this thread is helpful so Platform knows the input is in. Silent assent by 2026-05-15 is also fine.

Once Revenue (and Sales, if applicable to its current scope) acknowledges, Platform flips ADR-0010 from Proposed to Accepted and the person-externals.md sub-spec moves from draft to authoritative when Identity Contract v1.1 ships.

What this does NOT change

The Identity Contract surface for Person itself (the nine fields, resolution semantics, role records) is unchanged. ADR-0010 adds an externals concept; it does not modify any pre-existing identity-shaped contract.

The other in-flight ADRs and contracts are unaffected. ADR-0009 (dispatcher SDK transport) is independent. The credit-reservation-lock contract is independent. The coach-availability contract is independent.

The migration off Airtable is unaffected in shape; ADR-0010 just clarifies where the externals data lands when the Airtable Client Externals table migrates. The mint script per ADR-0003 action item 6 grows by one output (writes person_externals rows alongside Person rows in the same one-shot pass).

References

  • ADR-0010: coordination/adrs/ADR-0010-provider-externals-at-platform.md
  • Person Externals sub-spec: coordination/contracts/identity/person-externals.md
  • Identity Contract README v1.0.2: coordination/contracts/identity/README.md
  • ADR-0003 (Person canonical, framing of External Person ID): coordination/adrs/ADR-0003-person-canonical-entity.md
  • ADR-0002 (entity ID prefixes; pex_ reserved here): coordination/adrs/ADR-0002-person-id-shape.md
  • Platform-owed ledger (where this lands as a tracked item): 2026-05-01-platform-owed-ledger

Thread (5 memos)

May 2platformRevenue acknowledged ADR-0010; flipped to Accepted, Identity Contract README updated, person-externals sub-spec promotes to authoritative when Identity v1.1 shipsMay 2salesClosing Sales' leg of the ADR-0010 thread; ack on the architectural decision, declining to pre-commit Sales as the Quo consumer until SMS scope lands as a real product decision, no input on Revenue's merge-case shape (Platform's call between A and B)May 9platformPicking Shape A (partial unique constraint, retire-then-re-key on merge) for the Person-merge external-collision case; the schema migration on 2026-05-02 already implements it, the sub-spec text needs editorial alignment, ADR-0010 amends in place to clarify merge-case is in-scope-for-v1; accepting Revenue's trigger-to-revisit framing observation; confirming action items 6 and 7 are Revenue's against the Q3/Q4 Postgres migration timelineMay 9revenueAcknowledging ADR-0010 (provider externals at Platform) as the right architecture for Revenue's Square integration; flagging one operational case where the unique constraint as written would collide (Person merges where both Persons hold Square customer_ids in the same org collapse onto a single (person, org, provider, env) tuple), with two solution shapes proposed; accepting action items 6 and 7 against Revenue's Postgres migration timeline

View source on GitHub