Core System Architecture Part 85 — Anonymous Network Contacts, Address Book, Relationship Graph, Invitations, Trust State & Privacy-Preserving Social Connectivity Architecture
SIAR — Secure, Local-First, Multi-Transport Communication Platform
Series: Core System Architecture
Part: 85
Status: Architecture specification
Primary language: Rust
Builds on: Core System Architecture Parts 2, 15, 28, 30, 43, 45–46, 56–59, 67–69, 74–84
Primary purpose: define SIAR's contacts, local address-book, relationship graph, invitation, trust-state, blocking, discovery, relationship synchronization, multi-device contact state, social-graph privacy, and contact-specific profile/capability architecture without creating a centralized graph of who knows whom.
1. Purpose
Contacts are not merely names in a list.
A contact relationship can reveal:
who knows whom
how often people interact
which identity belongs to which person
which groups overlap
which devices belong to the same account
The governing principle is:
SIAR treats social connectivity as scoped cryptographic relationships, not as rows in a global people graph.
2. Architectural Position
Invitation / Bootstrap Capability
│
▼
Relationship Establishment
│
▼
Local Relationship Record
│
┌───────┼────────┐
│ │ │
Trust Profile Capabilities
│ │ │
└───────┼────────┘
▼
Contact-Specific State
3. Core Separation
Keep distinct:
local address-book entry
SIAR relationship
public handle
account identity
device identity
transport identity
group membership
federation identity
4. Non-Goals
Part 85 does not create:
a global friend graph
a centralized uploaded address book
automatic contact merging by phone/email
a global trust score
a permanent universal contact identifier
5. Relationship Identity
Each relationship receives a local random identifier.
#![allow(unused)] fn main() { pub struct RelationshipId(pub [u8; 32]); }
6. Relationship ID Scope
Local account/device relationship scope.
7. Hard Rule
RelationshipId is not globally stable or meaningful outside the relationship context.
8. Remote Relationship Reference
Each side can use a different identifier.
9. No Shared Global Contact ID
Hard rule.
10. Contact Record
#![allow(unused)] fn main() { pub struct ContactRecord { pub relationship: RelationshipId, pub state: RelationshipState, pub trust: ContactTrustState, pub profile: ContactProfileCache, pub capabilities: RelationshipCapabilities, } }
11. Relationship State
#![allow(unused)] fn main() { pub enum RelationshipState { PendingOutgoing, PendingIncoming, Active, Blocked, Revoked, Archived, } }
12. PendingOutgoing
Invitation sent but not accepted.
13. PendingIncoming
Invitation received.
14. Active
Relationship established.
15. Blocked
Local communication denied.
16. Revoked
Relationship authority terminated.
17. Archived
Local UI state only.
18. Hard Rule
Archive is not a security revocation state.
19. Contact Trust State
Trust is multidimensional.
#![allow(unused)] fn main() { pub struct ContactTrustState { pub familiarity: FamiliarityState, pub identity_verification: IdentityVerificationState, pub device_trust: DeviceTrustSummary, } }
20. Familiarity
#![allow(unused)] fn main() { pub enum FamiliarityState { Unknown, Invited, Accepted, Known, } }
21. Identity Verification
#![allow(unused)] fn main() { pub enum IdentityVerificationState { Unverified, VerifiedInPerson, VerifiedQr, VerifiedOutOfBand, ChangedSinceVerification, } }
22. Device Trust
Separate.
23. Hard Rule
Accepted contact ≠ cryptographically verified identity.
24. Hard Rule
Verified identity ≠ all devices trusted forever.
25. Invitation
A capability-based bootstrap.
26. Invitation Type
#![allow(unused)] fn main() { pub enum InvitationType { DirectCapability, Qr, Nfc, PrivateLink, ExactHandleBootstrap, ManagedDirectoryInvite, } }
27. Direct Capability
Strong privacy baseline.
28. QR
Good in-person bootstrap.
29. NFC
Convenient local bootstrap.
30. Private Link
Share through another channel.
31. Exact Handle Bootstrap
Optional.
32. Managed Directory Invite
Enterprise-scoped.
33. Invitation Capability
#![allow(unused)] fn main() { pub struct ContactInvitation { pub invitation_id: InvitationId, pub inviter_bootstrap_key: BootstrapPublicKey, pub capability: ContactBootstrapCapability, pub expires_at: Timestamp, } }
34. Invitation ID
Random.
35. No AccountId Embedded
Hard rule.
36. Bootstrap Capability
May authorize only:
contact request
initial profile projection
initial key exchange
37. It Must Not Authorize
admin actions
account recovery
tenant access
arbitrary file access
38. Hard Rule
Contact invitation authority is narrowly scoped.
39. Invitation Expiry
Required.
40. One-Time Use
Preferred.
41. Invitation Replay
Rejected or idempotently mapped to same pending relationship.
42. No Multiple Relationships From One Single-Use Invite
Hard rule.
43. Invitation State
#![allow(unused)] fn main() { pub enum InvitationState { Issued, Presented, Redeemed, Revoked, Expired, } }
44. Invitation Revocation
Possible before acceptance.
45. Invitation Storage
Local.
46. Server may hold opaque routing capability if feature requires.
47. No central list of inviter/invitee identities.
48. Invitation Flow
create scoped invitation
→ share through chosen channel
→ receiver verifies format/capability
→ receiver explicitly accepts
→ perform relationship key exchange
→ create local relationship IDs
→ exchange profile projection
→ activate relationship
49. Explicit Acceptance
Required by default.
50. No Automatic Contact Addition From Mere Message Receipt
Hard rule.
51. Message Request
Separate from trusted contact.
52. Message Request State
#![allow(unused)] fn main() { pub enum MessageRequestState { Pending, Accepted, Rejected, Blocked, } }
53. Accepting Message Request
May establish limited relationship.
54. User can later verify identity.
55. Relationship Capability
#![allow(unused)] fn main() { pub struct RelationshipCapabilities { pub send_message: CapabilityState, pub call: CapabilityState, pub profile_view: CapabilityState, pub presence_view: CapabilityState, pub file_send: CapabilityState, } }
56. Capability State
#![allow(unused)] fn main() { pub enum CapabilityState { Allowed, Denied, Ask, } }
57. Capabilities Are Relationship Scoped
Hard rule.
58. No Contact Relationship Automatically Grants All Features
Hard rule.
59. Relationship Key Material
Separate from account/login identity.
60. Relationship Root
Cryptographic state for peer relationship.
61. Device-Level Sessions
Derived separately.
62. Multi-Device Fanout
Each peer device authorized individually.
63. Hard Rule
One account relationship does not mean unknown newly-added devices are silently trusted.
64. Device Change
May change trust status.
65. Device Notification
Contact can be informed of newly-added device where protocol supports.
66. Verification State
May become:
ChangedSinceVerification
if identity root changes unexpectedly.
67. Expected New Device
Does not necessarily invalidate person verification.
68. Identity Root Change
More severe.
69. Trust Model
Separate:
person/contact relationship
account/identity continuity
device trust
session trust
70. No Single Boolean trusted
Preferred hard rule.
71. Address Book
OS/local address book integration is optional.
72. Local Address Book Entry
#![allow(unused)] fn main() { pub struct LocalAddressBookEntry { pub local_id: LocalAddressBookId, pub display_name: String, pub phone_numbers: Vec<PhoneNumber>, pub emails: Vec<EmailAddress>, } }
73. Sensitive Data
Local only by default.
74. Hard Rule
Raw device address book is never uploaded wholesale.
75. Contact Matching
Privacy-sensitive.
76. Default
No automatic server-side address-book matching.
77. Safer Alternatives
explicit invite
QR/NFC
exact handle
reviewed PSI/OPRF protocol
78. Simple Hashing Phone/Email
Not sufficient privacy.
79. Why
Small searchable input space.
80. Hard Rule
Do not treat SHA256(phone/email) upload as private contact discovery.
81. Private Contact Discovery
Future optional feature.
82. Use Reviewed Protocol
Potential:
OPRF
PSI
private set intersection
83. No Custom PSI Crypto
Hard rule.
84. Discovery Service
Should learn minimum possible.
85. No persistent uploaded contact list.
86. Rate Limits
Prevent enumeration.
87. User Opt-In
Required.
88. Exact Handle Discovery
Part 59.
89. Exact match only by default.
90. No prefix/wildcard people search.
91. Hard rule.
92. Address Book Linking
Local mapping:
#![allow(unused)] fn main() { pub struct AddressBookLink { pub local_entry: LocalAddressBookId, pub relationship: RelationshipId, } }
93. Link Never Synced By Default
Hard rule.
94. Why
Phone/email metadata may leak.
95. Contact Nickname
Local user-owned metadata.
96. Not shared.
97. Contact Notes
Local.
98. Sensitive.
99. No Central Sync By Default
Hard rule unless user explicitly enables encrypted sync.
100. Contact Groups/Labels
Local UI metadata.
101. Not equivalent to messaging group membership.
102. Hard rule.
103. Relationship Graph
Local graph only.
104. Graph Node
Relationship-local identity.
105. Graph Edge
User's own relationship.
106. No Central Adjacency Graph
Hard rule.
107. Relationship Graph Storage
#![allow(unused)] fn main() { pub struct RelationshipGraph { pub owner: LocalProfileId, pub relationships: BTreeMap<RelationshipId, ContactRecord>, } }
108. Server Synchronization
Encrypted user-owned state only where multi-device sync enabled.
109. Server should not interpret graph.
110. Hard Rule
Synced contact graph is opaque ciphertext where feasible.
111. Relationship Metadata Minimization
Do not sync:
frequency
interaction score
message count
unless strictly local feature.
112. No "Top Friends" Server Metric
Hard rule.
113. Interaction Ranking
If useful, local only.
114. Relationship Sync
Local-first.
115. Durable state:
relationship state
trust verification state
relationship capabilities
profile projection cache
116. Sync Classification
#![allow(unused)] fn main() { pub enum RelationshipSyncClass { LocalOnly, AccountEncrypted, RelationshipProtocol, } }
117. LocalOnly
Nickname, notes, OS address-book link.
118. AccountEncrypted
Own multi-device relationship record.
119. RelationshipProtocol
State shared with peer.
120. Hard Rule
Local-only contact metadata never enters relationship protocol.
121. Multi-Device Contact Sync
New own device can receive encrypted relationship state.
122. But
New device must establish fresh device sessions.
123. Hard Rule
Syncing contact record does not clone ratchet/session keys blindly.
124. Contact Sync Snapshot
May include:
RelationshipId local mapping
peer identity continuity record
profile cache
user-owned nickname if encrypted sync enabled
125. Session/Ratchet Keys
Excluded.
126. New Device Re-provisioning
Part 57.
127. Relationship peer may receive device-add event.
128. Device fanout updates.
129. Contact State Conflict
Examples:
block on one device
rename nickname on another
capability preference change
130. Conflict Policies
#![allow(unused)] fn main() { pub enum ContactConflictPolicy { RestrictiveWins, LastWriterWinsAllowed, Manual, } }
131. Block
RestrictiveWins.
132. Revocation
RestrictiveWins.
133. Nickname
LWW allowed.
134. Verification
Never silently upgraded by conflict.
135. Hard Rule
Security/trust conflicts resolve toward less trust/more restriction.
136. Blocking
Local security/privacy action.
137. Block Effects
reject new direct messages
reject calls
hide presence
stop profile updates
138. Block Does Not Necessarily Notify Peer
Preferred.
139. No Block Oracle
Hard rule.
140. Peer may only observe generic delivery unavailability.
141. Blocked Contact
No automatic unblock from stale sync.
142. Hard rule.
143. Revocation
Stronger than block.
144. Revocation removes relationship capability.
145. May rotate related keys.
146. Peer cannot use old invitation to recreate relationship.
147. Hard rule.
148. Relationship Revocation Record
#![allow(unused)] fn main() { pub struct RelationshipRevocation { pub relationship: RelationshipId, pub revocation_epoch: u64, } }
149. Epoch Monotonic
150. Old sync/invite state cannot resurrect.
151. Hard Rule
Revoked relationship cannot be restored from stale backup without explicit new invitation.
152. Reconnecting After Revocation
Creates new relationship.
153. New RelationshipId.
154. No hidden continuity.
155. Trust Verification
QR/in-person/out-of-band.
156. Verification Artifact
Fingerprint/SAS.
157. Example
#![allow(unused)] fn main() { pub struct VerificationRecord { pub method: IdentityVerificationMethod, pub verified_identity: PeerIdentityDigest, pub verified_at: Option<CoarseTimestamp>, } }
158. No Precise Location
Hard rule.
159. Verification Timestamp
Local/coarse.
160. Verification State Sync
Encrypted to own devices.
161. Not sent publicly.
162. Safety Number / Fingerprint
Derived from identity keys.
163. Human-comparable.
164. QR Verification
Encode reviewed fingerprint/capability.
165. No QR containing unnecessary account metadata.
166. Hard rule.
167. Identity Change
Contact sees warning.
168. Auto-Accept Only If cryptographically proven continuity.
169. Otherwise require review.
170. No Silent Trust Carryover
Hard rule.
171. Contact Profile Exchange
Uses Part 84 projections.
172. Relationship-specific projection.
173. Peer sees only fields user exposes.
174. Public profile not automatically used.
175. Hard Rule
A contact relationship does not automatically expose all private profile fields.
176. Contact Visibility Policy
#![allow(unused)] fn main() { pub struct ContactVisibilityPolicy { pub show_avatar: bool, pub show_status: bool, pub show_presence: bool, pub show_read_receipts: bool, } }
177. Per-Contact Override
Allowed.
178. Effective policy
Most restrictive between global and per-contact.
179. No Per-Contact Override Can Bypass Max-Anonymity Floor
Hard rule.
180. Presence
Part 45.
181. Capability-based.
182. Not global broadcast.
183. Read Receipts/Typing
Relationship scoped.
184. No Graph-Wide presence fanout.
185. Hard rule.
186. Invitations & Abuse
Unsolicited requests can be abusive.
187. Rate Limits
Per invite capability/source class.
188. No Central Permanent IP Reputation
Hard rule.
189. Request Inbox
Bounded.
190. Spam Filtering
Local heuristics.
191. Sender Reputation
Scoped/local.
192. No global social reputation.
193. Abuse Report
Part 46.
194. User can report invitation/message-request evidence.
195. Evidence scoped.
196. No automatic contact graph disclosure.
197. Invitation Privacy
Invite channel may reveal metadata.
198. In-person QR
Strong privacy.
199. Private link
Leaks to chosen transport/channel.
200. Exact handle
Directory sees query class.
201. UX should explain tradeoff.
202. No False "Anonymous" Claim For Contact Discovery
Hard rule.
203. Contact Import
From OS address book.
204. Import means local copy/link.
205. It does not imply network upload.
206. Hard rule.
207. Contact Export
Portable encrypted/human-readable export.
208. Exclude:
ratchet keys
live sessions
bearer invitations
209. Include:
nicknames
relationship metadata
verification record
subject to user choice.
210. No Export Of Peer Secrets
Hard rule.
211. Backup
Part 33.
212. Backup Contact State
Logical.
213. On Restore
Relationship authority needs safe rebind.
214. Do not blindly restore active live session state.
215. Peer identity continuity preserved if valid.
216. New own device gets fresh sessions.
217. Deleted/Revoked Relationships
Deletion barrier.
218. No backup resurrection.
219. Hard rule.
220. Contact Deletion
User may remove local record.
221. Options:
RemoveLocal
Block
RevokeRelationship
222. Different semantics.
223. Hard Rule
UI/API must not conflate delete-local with cryptographic relationship revocation.
224. RemoveLocal
May leave peer able to message if relationship remains.
225. Block
Prevents interaction locally.
226. RevokeRelationship
Terminates capability.
227. Account Deletion
Part 83.
228. Account deletion revokes outbound relationship authority where possible.
229. Peers retain their own copies of historical received messages/contact notes.
230. No remote deletion promise.
231. Hard truth.
232. Public Handle Retirement
Part 59/83.
233. Relationship does not depend permanently on public handle.
234. Handle can rotate without relationship loss.
235. Hard rule.
236. Managed Enterprise Contacts
Separate domain.
237. Org Directory
Can expose managed members within org policy.
238. Managed directory identity
Org-scoped.
239. No automatic personal contact creation.
240. Hard rule.
241. Employee Directory Entry
Not personal relationship.
242. Directory can facilitate invite.
243. User accepts relationship separately where appropriate.
244. Organization Offboarding
Removes managed directory entry.
245. Personal relationship may remain if independently established.
246. Hard Rule
Offboarding does not silently erase personal social relationships.
247. Tenant Boundary
Part 69.
248. Tenant contacts separate.
249. No cross-tenant graph query.
250. Cross-Tenant Relationship
Explicit capability/federation.
251. Federation Contacts
Part 58.
252. Cross-domain contact bootstrap uses signed domain identity and relationship capability.
253. No global federation people directory.
254. Hard rule.
255. Remote Federation Domain
Sees only needed bootstrap metadata.
256. No transitive contact graph.
257. Groups
Part 43.
258. Group membership does not automatically create pairwise contacts.
259. Hard rule.
260. Group Member Profile
Group-scoped projection.
261. Direct Contact Invite
Separate action.
262. No automatic "friend everyone in group."
263. Contact Suggestions
High privacy risk.
264. Default
No server-generated social suggestions.
265. Hard rule.
266. If ever supported
Use local signals only.
267. Example
recently shared QR
same local event code
268. No centralized mutual-contact graph.
269. Mutual Contacts
Not exposed by default.
270. Why
Graph leakage.
271. Hard rule.
272. Contact Search
Local list full-text search.
273. Server not needed.
274. Search index
DeviceLocal.
275. No remote search query telemetry.
276. Hard rule.
277. Contact Sorting
Local.
278. Recent interaction order
Local.
279. No central ranking.
280. Relationship Graph Query API
Local-only.
281. Example
#![allow(unused)] fn main() { pub trait RelationshipRepository { fn get( &self, id: RelationshipId, ) -> Result<Option<ContactRecord>, ContactError>; fn list( &self, filter: ContactFilter, ) -> Result<Vec<ContactSummary>, ContactError>; } }
282. No API
find all contacts of remote user
Hard rule.
283. Invitation Service
#![allow(unused)] fn main() { pub trait ContactInvitationService { fn create( &self, policy: InvitationPolicy, ) -> Result<ContactInvitation, ContactError>; fn redeem( &self, invitation: ContactInvitation, ) -> Result<PendingRelationship, ContactError>; } }
284. Relationship Establishment Service
#![allow(unused)] fn main() { pub trait RelationshipEstablishmentService { fn accept( &self, pending: PendingRelationship, ) -> Result<RelationshipId, ContactError>; } }
285. Verification Service
#![allow(unused)] fn main() { pub trait ContactVerificationService { fn verify( &self, relationship: RelationshipId, evidence: VerificationEvidence, ) -> Result<VerificationRecord, ContactError>; } }
286. Block Service
#![allow(unused)] fn main() { pub trait RelationshipBlockService { fn block( &self, relationship: RelationshipId, ) -> Result<(), ContactError>; } }
287. Revocation Service
#![allow(unused)] fn main() { pub trait RelationshipRevocationService { fn revoke( &self, relationship: RelationshipId, ) -> Result<RelationshipRevocation, ContactError>; } }
288. Relationship Keying
Local DB key by RelationshipId.
289. No AccountId as primary graph edge key.
290. Hard rule.
291. Storage
Encrypted local DB.
292. Synced ciphertext optional.
293. Relationship secrets
secure store/crypto state.
294. Contact notes/nicknames
encrypted.
295. Search index
local encrypted/derived where possible.
296. Server Mailbox
Does not store contact list.
297. Hard rule.
298. Social Graph Telemetry
Forbidden.
299. Safe Aggregate Metrics
Possible:
invitation success rate
request rejection rate
verification feature usage aggregate
300. Forbidden Metrics
degree per user
mutual contacts
relationship edge list
who contacts whom
301. Hard rule.
302. Contact Analytics
Local only.
303. No central "engagement graph."
304. Observability
Sync health only.
305. Relationship events
Do not send to global analytics bus.
306. Hard rule.
307. Audit
Managed enterprise admin actions only where relevant.
308. Personal contact creation/blocking
No central audit.
309. Security Event
Identity-key change can be locally logged/notified.
310. Retention bounded.
311. Contact State Events
#![allow(unused)] fn main() { pub enum RelationshipEvent { InvitationCreated, InvitationRedeemed, RelationshipActivated, TrustChanged, Blocked, Revoked, } }
312. Event Bus
Local/account encrypted only.
313. No server-wide social event stream.
314. Hard rule.
315. Privacy Threat Model
Attacks include:
address-book harvesting
handle enumeration
invite replay
graph reconstruction
device-correlation
profile-correlation
316. Address-Book Harvesting
Raw upload forbidden.
317. Handle Enumeration
Exact lookup/rate limit.
318. Invite Replay
Single-use/idempotency.
319. Graph Reconstruction
No central graph/logging.
320. Device Correlation
Separate device IDs, minimized profile data.
321. Profile Correlation
Relationship-specific projection.
322. Anti-Correlation
Do not expose same stable identifier across:
contact bootstrap
mailbox
transport
payments
telemetry
323. Hard rule.
324. Abuse Threat Model
Attackers may send mass invites.
325. Defense
bounded inbox
rate limits
proof/credits if needed
local filtering
326. No proof-of-real-world-identity requirement.
327. Safety Blocking
Immediate local effect.
328. Blocked user cannot bypass via same relationship.
329. New identity/spam remains general abuse problem.
330. Reputation
Part 46, scoped.
331. No global blacklist that deanonymizes.
332. Message Requests
Can be disabled entirely.
333. Invite Policy
#![allow(unused)] fn main() { pub enum IncomingContactPolicy { InvitationsOnly, ExactHandleRequests, ContactsOfManagedDirectory, Disabled, } }
334. Default Privacy-Friendly
InvitationsOnly.
335. Public Account
May choose ExactHandleRequests.
336. No Implicit Open DMs
Hard rule.
337. Presence Integration
Part 45.
338. Relationship capability controls.
339. If Blocked/Revoked
Presence stops.
340. Typing/read receipt
stop.
341. Profile updates
stop.
342. Notification Integration
Part 31/84.
343. Incoming request notification
privacy-safe.
344. Do not include remote sensitive data on lock screen by default.
345. Call Integration
Part 44.
346. Calls only if relationship capability allows.
347. Unknown callers
request policy.
348. No call reveals direct IP in strict privacy mode.
349. File Sharing
Part 40.
350. Relationship capability.
351. Unknown incoming files
restricted.
352. Security Verification UX
Show:
Unverified
Verified
Identity changed
New device
353. Avoid misleading "Trusted" single label.
354. Hard rule.
355. Trust State Changes
Typed.
356. Example
#![allow(unused)] fn main() { pub enum TrustTransition { Verify, IdentityChanged, DeviceAdded, DeviceRevoked, RelationshipRevoked, } }
357. No Automatic Verified State
except cryptographically proven continuity.
358. Local Nickname
Does not affect identity verification.
359. Hard rule.
360. Verification On Multiple Own Devices
Sync encrypted proof state.
361. New device can inherit "user previously verified this identity" marker.
362. But device-specific session still fresh.
363. Profile Key Rotation
If contact profile encryption key rotates
continuity proof required.
364. No silent new identity.
365. Relationship Secret Rotation
Periodic/after compromise.
366. Old keys retired.
367. Key lifecycle Part 66.
368. Contact Data Lifecycle
Part 67.
369. Local contact record retention
User-controlled.
370. Revoked state tombstone
bounded but sufficient anti-resurrection.
371. Contact Notes
Delete when contact removed if user requests.
372. Verification record
delete with relationship record unless retention needed.
373. No indefinite metadata.
374. Managed Directory Data
Org retention separately.
375. Account Deletion
Deletes local account-owned relationship records in own cloud sync.
376. Other parties' relationship copies remain theirs.
377. No remote erasure claim.
378. Hard truth.
379. Schema Versioning
Relationship protocol version separate from storage version.
380. Invitation version.
381. Trust-state version.
382. No conflation.
383. Migration
Part 74.
384. Unknown future trust state
display conservatively.
385. No default "verified."
386. Hard rule.
387. Relationship Protocol Envelope
#![allow(unused)] fn main() { pub struct RelationshipEnvelope<T> { pub protocol_version: RelationshipProtocolVersion, pub relationship_ref: OpaqueRelationshipRef, pub message: T, } }
388. Opaque Relationship Ref
Per-peer.
389. No local RelationshipId exposed directly.
390. Hard rule.
391. Serialization
Postcard internal/network binary.
392. RON export/config.
393. JSON only interop.
394. Strict bounds.
395. No unbounded contact profile payload.
396. Contact Photo
Part 84 avatar pipeline.
397. No original EXIF.
398. Contact-supplied media
untrusted input.
399. Decode sandbox/bounds.
400. Testing
Need dedicated contact/social testkit.
401. Test Scenarios
invite replay
expired invite
block
revoke
identity change
multi-device sync
402. Invite Replay Test
Second redemption cannot create duplicate relationship.
403. Expiry Test
Expired invite rejected.
404. Wrong Audience Test
Invitation not usable by unintended context if bound.
405. Block Test
Messages/calls/presence denied.
406. Block Sync Test
Stale device cannot unblock.
407. Revoke Test
Old relationship capability invalid.
408. Backup Test
Revoked relationship not resurrected.
409. Verification Test
Identity change downgrades state.
410. Device Add Test
Person verification and device trust remain distinct.
411. Contact Projection Test
One contact never sees another's projection.
412. Address Book Test
Raw address book never enters network request.
413. Hash Discovery Test
Simple phone/email hash upload prohibited.
414. Managed Directory Test
Directory membership does not auto-create personal contact.
415. Group Test
Group membership does not auto-create pairwise contacts.
416. Federation Test
No global cross-domain contact graph.
417. Telemetry Test
No relationship IDs/edges in remote analytics.
418. Deletion Test
Local removal vs block vs revoke behave distinctly.
419. Fuzzing
Fuzz:
invitation envelope
relationship protocol
profile projection
trust-state transition
420. Property Tests
Properties:
revoked relationship never returns active without new invitation
block/revoke conflict resolves restrictive
verified state never appears without valid verification evidence
local address-book data never enters network payload
421. Formal Verification Targets
Strong candidates:
invitation state machine
relationship activation/revocation
trust-state transitions
multi-device restrictive merge
422. Kani Candidate
capability/state transition subset rules.
423. TLA+ Candidate
multi-device block/revoke + stale sync + backup restore.
424. Loom Candidate
concurrent invitation redemption/acceptance/revocation.
425. Performance
Contacts are low/medium throughput.
426. Local search
fast.
427. Relationship lookup
O(1)/indexed.
428. No remote search for local contact list.
429. Multi-device sync
incremental/batched.
430. Profile projections
small.
431. Contact graph
not loaded globally server-side.
432. Memory
Client may cache summaries.
433. Large contact lists
paged/virtualized.
434. No O(n) network fanout for every profile update.
435. Fanout
Use relationship-scoped update mechanisms.
436. Max-Anonymity Mode
Profile/presence fanout reduced.
437. No timing-rich contact updates.
438. Batch/jitter noncritical updates.
439. Crate Layout
Recommended:
crates/
├── siar-contact-core/
├── siar-contact-invitation/
├── siar-relationship-core/
├── siar-contact-trust/
├── siar-contact-verification/
├── siar-contact-profile/
├── siar-address-book/
├── siar-private-contact-discovery/
├── siar-contact-sync/
├── siar-contact-observability/
└── siar-contact-testkit/
440. siar-contact-core
Owns:
RelationshipId
contact state
errors
441. siar-contact-invitation
Invitation capability/state.
442. siar-relationship-core
Relationship activation/capabilities/revocation.
443. siar-contact-trust
Familiarity/identity/device trust.
444. siar-contact-verification
QR/out-of-band verification.
445. siar-contact-profile
Relationship-specific profile projections.
446. siar-address-book
Local OS address-book links/import.
447. siar-private-contact-discovery
Optional reviewed PSI/OPRF adapter.
448. siar-contact-sync
Encrypted multi-device relationship sync.
449. siar-contact-observability
Aggregate privacy-safe metrics only.
450. siar-contact-testkit
Replay/block/revoke/identity-change/graph-privacy tests.
451. Error Taxonomy
#![allow(unused)] fn main() { pub enum ContactError { InvitationInvalid, InvitationExpired, InvitationRevoked, InvitationAlreadyRedeemed, RelationshipNotFound, RelationshipBlocked, RelationshipRevoked, VerificationFailed, IdentityChanged, CapabilityDenied, DiscoveryDenied, SyncConflict, Internal, } }
452. Security, Privacy & Correctness Invariants
Mandatory:
1. SIAR has no global social graph or universal contact identifier.
2. Relationship IDs are scoped and opaque; account, transport, mailbox, payment, and telemetry identities remain separate.
3. Raw address books are local by default and are never uploaded wholesale.
4. Simple hashes of phone numbers or email addresses are not treated as private contact discovery.
5. Contact invitations are scoped, expiring, replay-resistant capabilities and cannot authorize unrelated actions.
6. Accepted relationship, verified identity, and trusted device are distinct states and are never collapsed into one boolean.
7. Blocking and revocation resolve restrictively across multi-device conflicts and cannot be undone by stale sync or backup restore.
8. Revoked relationships require a new invitation/new relationship identity to reconnect.
9. Contact-specific profile, presence, typing, receipts, calls, and file capabilities are relationship-scoped and cannot leak to other contacts.
10. Group membership, managed-directory membership, and federation membership never automatically create pairwise personal contact relationships.
11. Contact analytics, telemetry, and operational logs never contain a remotely queryable user-to-user edge list.
12. Multi-device synchronization may restore relationship metadata but never blindly clones old ratchet/session secrets.
453. Initial Production Scope
Implement first:
typed RelationshipId
pending/active/blocked/revoked relationship state
capability-based invitations
QR/private-link bootstrap
explicit acceptance/message requests
separate familiarity/identity/device trust
QR/out-of-band verification
relationship-scoped profile/presence/call/file capabilities
local address-book linkage only
encrypted multi-device contact sync
restrictive block/revoke conflict handling
relationship revocation epoch
backup anti-resurrection
local contact search
privacy-safe aggregate metrics
contact/social testkit
Then add:
reviewed PSI/OPRF private contact discovery
NFC/bootstrap refinements
advanced relationship portability
federated private contact bootstrap
formal relationship-state verification
privacy-preserving batched profile update fanout
454. Definition of Done
Part 85 is complete when:
- contacts are modeled as scoped cryptographic relationships
- invitation capabilities are expiring/replay-resistant
- relationship acceptance is explicit
- accepted/verified/device-trusted states remain separate
- address books remain local by default
- no simple-hash address-book discovery is used
- public handles do not become global contact IDs
- relationship-specific profile/presence/call/file permissions are enforced
- block/revoke semantics are separate and restrictive
- revoked relationships cannot resurrect from backup/stale sync
- multi-device sync never clones live session/ratchet keys
- managed/group/federation membership never auto-creates personal contact edges
- telemetry contains no centralized social graph
- invite/block/revoke/identity-change/fuzz/formal tests are specified
455. Final Architecture
INVITATION / BOOTSTRAP
│
▼
EXPLICIT ACCEPTANCE
│
▼
CRYPTOGRAPHIC RELATIONSHIP
│
┌────────────┼────────────┐
│ │ │
TRUST PROFILE CAPABILITIES
│ │ │
└────────────┼────────────┘
▼
LOCAL CONTACT STATE
│
▼
ENCRYPTED MULTI-DEVICE SYNC
Social-connectivity safety model:
scoped relationship identity
+
capability invitation
+
explicit acceptance
+
separate trust dimensions
+
local address book
+
relationship-scoped disclosure
+
restrictive block/revoke
+
no centralized graph
not:
upload every phone number, build a global friend graph, and assign everyone a permanent contact ID
456. Final Principle
A contact should be a private relationship between participants, not a globally enumerable edge in a platform-owned graph.
The correct model is:
bootstrap narrowly
+
accept explicitly
+
verify independently
+
share per relationship
+
store graph locally
+
sync encrypted
+
block/revoke durably
+
never centralize the social graph
This architecture gives SIAR a privacy-preserving social-connectivity foundation for direct contacts, message requests, invitations, verification, address books, multi-device contact state, groups, enterprise directories, and federation while preserving the anonymity, least-authority, and local-first guarantees established across Parts 34–84.