Skip to content

docs: proposal — simplify circles, connection confirmation & profile visibility - #1062

Open
Seifert69 wants to merge 34 commits into
mainfrom
circles-visibility-proposal
Open

docs: proposal — simplify circles, connection confirmation & profile visibility#1062
Seifert69 wants to merge 34 commits into
mainfrom
circles-visibility-proposal

Conversation

@Seifert69

Copy link
Copy Markdown
Member

Summary

Adds CIRCLES_VISIBILITY_PROPOSAL.md — a discussion document (no code changes) proposing:

  • Retiring the "Vetted" terminology, which users misread as official approval/verification
  • One consistent mental model: circles = my groups for sharing more and granting permissions; being in any circle = reviewed and connected
  • A Public / My circles visibility picker per profile field, with an easy "Any of my circles" default and optional per-circle selection (enables e.g. a photo visible only to one circle)
  • A single combined confirm-connection modal that makes the privacy consequence explicit
  • Contacts-list filter chips + circle pills, and a card-based Circles tab with explainer
  • A three-phase rollout (rename first, picker + Circles tab second, per-circle overrides last)

Open questions for the team are listed in section 8 of the doc.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k

Adds a discussion document proposing a single circles-based mental
model for connections, connection confirmation, and profile field
visibility, with terminology changes, per-screen UX changes, and a
three-phase rollout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown

JVM Test Results

3 654 tests  +11   3 646 ✅ +11   2m 37s ⏱️ +6s
  454 suites + 1       8 💤 ± 0 
  454 files   + 1       0 ❌ ± 0 

Results for commit 4ff080c. ± Comparison against base commit 23c0e08.

♻️ This comment has been updated with latest results.

Seifert69 and others added 15 commits July 11, 2026 20:43
…ected"

Separates "reviewed" (= confirming the connection) from "granted access"
(= circle membership). Confirming without selecting circles is now a
first-class outcome: the contact becomes Connected (public profile only,
chat still works) instead of being stuck in the New queue. Adds the
adaptive confirm button, the three contact-list states, the Connected
terminology row, and resolves open question 1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
The reviewed fact can't be derived once the Confirmed Connections
system circle is gone (today's server-computed vetted flag) and a
Connected contact has zero circle grants. Specify ContactLocalAppDataJson
with connectionReviewedAt, stamped on confirm-dialog completion, riding
fileMetadata.localAppData like ConversationLocalAppDataJson — synced to
the owner's other clients, never transferred to the peer. Includes
state-derivation table and legacy migration notes; added to Phase 1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
…irmed

States outright that introduced, auto-connected, and plain direct
connections all start (and stay) in New until the confirm dialog is
completed — today's Unvetted bucket maps 1:1 onto New, and connection
alone never promotes a contact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
Drops the "now it's a real connection" framing: confirm-with-no-circles
changes nothing about an already-real connection, so the review is
recast as triage with four outcomes (circles / keep as plain connection
/ disconnect / block). Confirm modal gets two completion paths — Confirm
(circles + visible default toggles like auto-follow) and a quieter Keep
as connection (everything off) — both stamping connectionReviewedAt.
New open question 5: what confirming actually grants server-side; if
nothing beyond circles, the two buttons collapse into one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
…n un-overloaded

Terminology section rebuilt: "connection" is reserved as the constant
noun for the wire (request/new/disconnect), never a state name. Two
candidate sets for the three states, team to pick: New/Chat/Circle
(capability ladder) vs New/Known/Trusted (trust ladder), with emoji
triples 👋💬⭕ vs 👋🤝🛡️ and trade-offs. Review-form buttons name
destination states (Add to circles / Chat only); "confirm" demoted to
the verb for completing a review. Doc now uses option A as working
terms; new open question 6 for the choice. Also removes the double use
of "lightweight connection" for both pre- and post-review states.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
Replaces the two-button review form with one button whose label + emoji
track the selection: ⭕ Add to circles with ≥1 circle selected, 💬 Chat
only with none. The label change is the feedback that deselecting
circles changed the destination. Deselecting the last circle flips the
visible default toggles off (re-enablable). Cross-references updated
(section 3 option bullets, section 8 stamp comment and derivation, Q1,
Q5 — button count no longer depends on Q5, only the defaults strip).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
Every labeled exit from the review now names the destination state
(⭕ Add to circles / 💬 Chat only / 👋 Keep as new); the escape hatch is
a no-op dismiss (no stamp) and scrim/back keep plain cancel behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
States classify inbound access (what they get of mine); following is
outbound consumption (what I take from them) and grants the followed
person nothing. Public feed needs no connection (follow-only identities
get a follow indicator, never a state pill); encrypted feed requires
connection + membership in THEIR circles — the mirror image of the
proposal. Disconnect downgrades a follow to public-only. The review
modal's follow toggle is an orthogonal convenience, not a tier default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
…New, scale

Folds in the subscriber discussion: circles get a PERSONAL | AUDIENCE
designation (enum, set by the owning app, riding the in-progress
app-owned circles backend; per-circle, not per-app — emergency location
is personal, feed Subscribers is audience). Contact states derive from
personal circles only; audience approval never stamps the review or
counts toward the New badge; audience members never materialize as local
contact records (paged server queries in the owning app; audit via
server-backed All-connections search). Also: chat = chat-drive write,
granted to New connections at connect time, so New → Chat is purely the
review stamp — a plausible "nothing" answer to Q5. New Q7 (audit view
placement); Q6 gains the subscriber-must-not-read-Trusted argument.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
States render as monochrome Homebase-tinted vector icons in a fixed
trailing slot (emoji color fonts can't be tinted); user-chosen circle
emoji render full-color on the row's second line — different visual
species, so nothing needs reserving in the picker. Circles without an
emoji fall back to a name pill, optionally vowel-dropped "Hebrew style"
(Family → fmly); full name in roomy contexts and always the
contentDescription. Schema: optional emoji field rides the same circle
registration record as the PERSONAL|AUDIENCE enum (ZWJ/no-substring and
desktop-font-fallback cautions noted). Phase 1 coordination bullet and
Phase 2 gain the emoji work.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
@Seifert69

Copy link
Copy Markdown
Member Author

We should implement circles and drives under Apps before taking this on. In all probability the contact manager should/ can only allow the user to toggle on circles that are under the chat KMP app (it might show other circles the contact is a member of, potentially even allow removing them, but not add a circle to a contact unless it's a circles owned by the app)

Seifert69 and others added 12 commits July 30, 2026 07:12
…owers clarifier

Folds in review feedback: the middle state is defined functionally
(reviewed, default grants only, no read access beyond public —
internally "deposit-only") with "Chat" as its display name; the enum
gains its third case SERVICE (hotel → Receipts drive, bank statements,
tax accountant — write-only vendor/institution circles that must never
render as Circle contacts); the read-access rationale is documented with
designation kept as the normative rule; and the following section states
explicitly that followers/following are not contacts and need no
connection-table linkage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
…entation

"Chat" is the display name for the default connection state in the Chat
app specifically; another app would name the same state by its own
default capability. The personal-circles-only derivation is likewise a
presentation rule scoped to this app (profile, contacts, feed, chat,
moments) — SERVICE circles don't merely not count, they don't appear in
this app's UI at all; the shared piece is only the designation enum on
the circle record.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
… connected ACL collapse

Fourth enum case SYSTEM (platform plumbing, hidden everywhere, never
affects states). Inventory table: Confirmed Connections retires (with
three migration items: grant inventory = Q5 concrete, Vetted
profile-field re-ACL, baseline-carrier question); Auto Connections
survives as the default-grants carrier, designated SYSTEM and removed
from UI — clients then delete their hardcoded GUID pinning/renames.
SecurityGroupType: collapse connected/autoconnected into plain
connected, replaced by designation-qualified tiers
connected(PERSONAL|AUDIENCE|SERVICE) — the dynamic ACL realization of
"Any of my circles" ("birthday visible to connected — personal");
designation thereby joins the access-control model and must be immutable
after creation. New open questions 8 and 9.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
Both system circles now dissolve into per-app AUTO_CONNECT /
VERIFIED_CONNECT default circles (backend spec deferred to odin-core's
drive-addressing.md as single source of truth); deposit-only invariant
makes "states measure read access" an enforced property. The
connected(PERSONAL) qualified-ACL idea is replaced by retire-the-tier +
app-maintained enumerated "Any of my circles" ACLs, with the rejected
alternative recorded (ambient authority on a distributed judgment).
Inventory findings folded in: connected ACLs admit unreviewed
auto-connections today (new Current Problems bullet); Q5/Q8/Q9 resolved;
review-modal defaults strip = per-app verified toggles; SYSTEM
designation redefined as hidden per-app default circles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
…ownership

Designation enum back to PERSONAL | AUDIENCE | SERVICE; app default
circles carry no designation — rendering keys off Enrollment (no pill,
no state, distinct Circles-tab group with member list and owner toggle).
Formal definition added: a circle is a named list of people plus grants
defined by its owning app — Friends/Family are the profile app's
circles (grants = profile-attribute reads), the list is referenceable by
any app (moments distribution); Emergency Location Access = the location
app's PERSONAL circle. "Chat-only" naming bonus recorded (state =
circle membership made visible; removal = soft mute). VERIFIED_CONNECT
designation coupling noted (PERSONAL verified toggle counts as a circle
selection). Review-modal toggles are suite-aware (suite collapses to a
summary row; foreign apps always explicit). Q3 resolved: inline circle
creation in both dialogs, minted under the profile app.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
"Service" reads as something technical; VENDOR matches the examples
(hotel, bank, accountant) and stays unambiguous in UX copy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
…ta rule

Records the review-never-revokes rule (verified circles carry only the
delta beyond their app's auto circle; auto membership persists — today's
system circles, with five of six grants duplicated, are the cautionary
fossil of the superset design). Adds the decomposition table for Todd
and Bishwa: today's system-circle bundle split into per-app AUTO_CONNECT
deposits (Chat-only, Mail, Lists, Moments, Feed + anonymous-read keys,
Profile keys) and VERIFIED_CONNECT deltas (Secured feed distribution,
Introductions + settings-gated read keys), with ShardRecovery and
TransientTemp deliberately excluded and a sum check showing the
decomposition reproduces today's bundles exactly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
…; spell out Write+React

The feed app creates an AUDIENCE circle per encrypted channel drive
(read grant = the subscription); the review toggle enrolls into
default-shared channels, and distribution eligibility becomes channel
audience membership, replacing the Confirmed check in
FeedDriveDistributionRouter. W|R expanded to Write+React with a
footnote: React is a deposit (writing a reaction), not a read.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
…faults.md

The enrollment model was split out of drive-addressing.md into
docs/connection-defaults.md on the same odin-core PR; drive-addressing
keeps only the dormant schema columns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
A checked toggle for an app whose keys this client doesn't hold is
recorded and queued (backend: Cross-app verified enrollment,
connection-defaults.md); the toggle renders pending — checked but not
yet active — until that app processes its queue, so the dialog never
claims access that doesn't exist yet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
Updated proposal title to include versioning and added reference to previous documentation.
Seifert69 and others added 6 commits August 3, 2026 09:55
Section 8 revisions per part 2's "The security ladder, recut": the
connected tier is recut (777 = Reviewed, assigned from ReviewedAt on
the connection registration; unreviewed connections rank as
Authenticated; wire string kept, autoconnected deleted; migration is
intent-restoring — legacy connected ACLs tighten to reviewed-only,
finally delivering what "Vetted" claimed). Recording-the-review is
revised: ReviewedAt lives server-side on the ICR (no schema),
satisfying the privacy shape of the earlier localAppData design plus
ACL participation; the localAppData connectionReviewedAt is kept only
as a rejected-alternative note, and the state derivation reads
GetConnectionInfo. Current Problems bullet notes the fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
…ction pointer

Recording-the-review gains: the owner-private promise requires part 2's
viewer-scoped redaction (third parties get an identity list, never
judgment fields; vetted -> reviewedAt on the owner/app shape, legacy
field parsed until V2 lands). Client contact API: isReviewed() derived
from reviewedAt via connection info (single source for states and
filters) and setReviewed(Boolean) — true = chat-only review via the
atomic endpoint, false = un-review back to New/Authenticated, valid
only with zero personal circles. Server-side contact API explicitly
needs nothing — review is connections-API domain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
…mplete the client API

The membership side of the state derivation: personalCircles() filters
memberships to Designation == PERSONAL regardless of owning app
(emergency location counts; profile app is merely the minting home);
isInAnyPersonalCircle() is its non-empty check — with isReviewed()
these two are the whole state machine. Client-side only, computed from
data already held; deliberately no server endpoint (a server-side
personal-circle predicate is connected(PERSONAL) by another door). The
one legitimate server-side designation use: the review endpoint rejects
un-review while personal memberships exist, since circleIdList ACLs
check membership not tier.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
…ob field

Points at part 1's DDL; the pagination/filtering need at audience scale
is why.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
Mirrors odin-core: Circle.GrantOn ∈ {None, Connect, OwnFlowConnect,
Review} replaces the Enrollment enum plus the AppRegistrations flag;
values realign with the recut ladder (Review, not VERIFIED_CONNECT);
OwnFlowConnect covers the vendor-consent-flow case; default-circle
rendering keys off GrantOn.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdUJ3MoWHjvRJ7XkTag78k
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants