Commit Graph
18117 Commits
Author SHA1 Message Date
Claude 26795fb9a8 fix(concord): address private channels by their own key, not the community root
Every path derived every channel's Chat Plane from the `community_root`,
`private: true` ones included — at six independent call sites (plane
registry, subscription planner, session re-fold, and three send paths).
CORD-03 §1 keys a private channel by the per-member `channel_key` delivered
in the kind-13302 bundle, at that channel's own epoch.

The consequence was not a weakly-enforced ACL but no ACL at all: a private
channel sat on an address every member of the community could derive, so it
was readable *and postable* by people never granted its key. Symmetrically,
a private channel created by a conformant client was addressed somewhere we
never looked, which is the "renders an empty room" symptom. `privateChannel`
had exactly one caller in the tree — a Quartz test — and `private` was
consulted on no send or subscribe path.

Introduce `ConcordChannelPlanner`: one resolver mapping (entry, folded
state) to per-channel plane coordinates — a `write` plane and the `reads`
that span held epochs. Public channels resolve off the root as before;
private channels off the bundle key. Every consumer now reads it, so the
choice of secret is made once rather than re-decided per call site.

The epoch travels with the plane. A private channel's wraps bind to its
channel epoch, so passing the root epoch would have rejected every one of
them on arrival even with the right key — the session's current-plane map
carries the epoch for the same reason.

A private channel we hold no key for is omitted from the channel list and
the Messages inbox, matching the reference client's `channelsView`, and no
write coordinate exists for it, so no send path can fall back to the root.
Reaching one anyway (a stale route) now yields `PostingGate.NoKey` instead
of a composer that would publish nowhere valid.

Migration: "private" channels created by earlier Amethyst builds keep their
history on the root-derived plane, which is no longer read for a private
channel. That history is orphaned deliberately — reading it would mean
continuing to accept traffic on a plane the whole community can write to.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3KXHjmCpUDzrSRyxatbyB
2026-07-30 02:55:57 +00:00
Claude 4bb44de5e2 feat: explain every reason a chat room blocks posting
A boolean `canPost()` can hide the composer but cannot say why, so each new
gate degraded into blank space above the keyboard. That is how a banned
Concord member came to get an empty slot and no explanation: the screen's
only explanatory branch tested `dissolved`.

Model the reason instead. `PostingGate` is a sealed interface — Allowed, or
a Blocked subtype (Banned, Dissolved, NoKey, NotAMember, InviteOnly) — and
both channel types now derive it, with `canPost()` defined as
`postingGate() == Allowed` so the answer and the explanation cannot drift.
Adding a gate later is a compile error at the render site until it is given
copy of its own, which is the property the boolean could not express.

One `PostingGateNotice` renders all of them, replacing the Concord-only
dissolved notice and the NIP-29-only join notice; the forum thread list
reuses the same sentence instead of a flat "read-only". The Concord screen
also now collects the channel's metadata flow, so a ban or dissolution
landing mid-session flips the composer instead of waiting for a re-entry.

Only reasons a protocol can produce today are modeled. A Buzz tenant ban
(9040) or timeout (9042) is not among them: the relay decides at publish
time and reports it in an `OK false` no send path surfaces yet, so there is
no local state to derive it from. Nothing is claimed for archived Buzz
channels either — neither the relay contract nor our code refuses writes
there, so gating them would have hidden a composer the relay accepts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3KXHjmCpUDzrSRyxatbyB
2026-07-30 02:10:08 +00:00
Claude 94f042050b docs: audit which community statuses reach the UI
Adds a per-status UI-coverage pass over the matrix, graded shown / implied /
invisible, plus four more gaps that are UI-only (the state is tracked
correctly, nothing tells the user).

The notable ones: a ban is never explained to the person banned — in Concord
the composer just vanishes because the explanatory branch only covers
`dissolved`, and on Buzz a tenant ban/timeout is an `OK false` that no send
path surfaces. Stranding after a Refounding is log-only, so it renders as an
ordinary empty community. Buzz tenant moderation (9031/9032/9040-9043) has no
write path at all, and neither does Concord dissolution. Concord's private
channels show a lock and then navigate into a permanently empty room.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3KXHjmCpUDzrSRyxatbyB
2026-07-29 22:20:03 +00:00
Claude 31e1e362f1 docs: map every Buzz and Concord user status
Documents the full status matrix for both community protocols, split by who
decides each status: the relay/community side (authoritative, event-backed) or
our own device (local bookkeeping like "Add to Messages").

Covers Buzz/NIP-29 per-channel membership (39001/39002 + the NIP-43 tenant
fallback, the client-only PENDING, NIP-OA virtual membership) and the 39000
flags that change what each status can do; the per-relay/workspace tenant
statuses (owner/admin/member, banned, timed out, archived identity); Concord's
owner-rooted OWNER/ADMIN/MEMBER/BANNED/NONE plus dissolved, epoch, stranded and
the Three Removals; per-channel Concord state; and the device-local layer
(kind-10009 vs kind-13302, invites, dismissals, stars, workspaces, dialect,
view modes, unread), including why remove-from-Messages, ignore and leave are
three different actions.

Also records the gaps the mapping surfaced: private Concord channels are listed
but their plane keys are never derived, RoleScope is decode-only so a
channel-scoped role grants community-wide power, Concord Kick (3309) and NIP-RS
read state are unwired, and Buzz presence (20001) still collides with geohash
presence in EventFactory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3KXHjmCpUDzrSRyxatbyB
2026-07-29 22:05:50 +00:00
Vitor PamplonaandGitHub 09902fe470 Merge pull request #3816 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-07-29 16:17:43 -04:00
Vitor PamplonaandGitHub 14b615b10d Merge pull request #3810 from dmnyc/feat/nip73-comment-previews
feat(nip73): show rich previews for external-content comments
2026-07-29 16:17:30 -04:00
vitorpamplonaandgithub-actions[bot] 8678c88db6 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-29 20:15:13 +00:00
Vitor Pamplona 6fac964d16 Improving the shape of the mention icon 2026-07-29 16:11:40 -04:00
Vitor PamplonaandGitHub 96a896f78e Merge pull request #3814 from vitorpamplona/claude/corcord-buzz-height-difference-8fp108
Remove facepile from channel rows, simplify layout
2026-07-29 15:41:17 -04:00
Vitor PamplonaandGitHub 1c24ba9cf6 Merge pull request #3815 from vitorpamplona/claude/push-notification-icons-branding-dy4egx
Add Nostr badge watermark to notification icons
2026-07-29 15:40:58 -04:00
Claude 9e4aedee05 fix: enlarge the media Amethyst peak another 10%
Gem height 9.68 -> 10.65.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:39:11 +00:00
Claude eae0ca814d fix: raise the media Amethyst peak 2%
cy 15.62 -> 15.14.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:36:43 +00:00
Claude ec60834046 fix: enlarge the media Amethyst peak 10%
Gem height 8.8 -> 9.68.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:31:48 +00:00
Claude 2684d2d4a8 fix: nudge the media Amethyst peak down 1% and right 2%
cx 15.28 -> 15.76, cy 15.38 -> 15.62.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:29:55 +00:00
Claude fd6696da82 fix: lower the media Amethyst peak another 1%
cy 15.14 -> 15.38.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:28:40 +00:00
Claude 00c46bcc92 fix: nudge the media Amethyst peak slightly down and right
cx 14.8 -> 15.28, cy 14.9 -> 15.14.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:26:41 +00:00
Claude 26ad072993 fix: raise the media Amethyst peak 5%
Move the gem back up (cy 16.1 -> 14.9) for a better balance with the mountain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:21:32 +00:00
Claude 52643fb48f fix: lower the Amethyst peak in the media icon ~10%
Move the gem down (cy 13.7 -> 16.1) so it sits lower against the mountain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:20:22 +00:00
Claude 097c3e874d feat: media icon uses the Amethyst crystal as a mountain peak
Drop the second mountain and the sun; place the Amethyst gem on the ground
as the second peak beside a single triangular mountain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:15:03 +00:00
The Daniel adc36017d1 fix(nip73): honor data-saver gate and fix preview icon touch target
Review feedback from PR #3810:

- Gate both new preview call sites behind settings.showUrlPreview(), so a
  user on WIFI_ONLY over cellular or NEVER no longer triggers an outbound
  OpenGraph request and image download per external-scoped comment. Falls
  back to the plain link chip / URL header.
- Wrap the open-in-browser icon in an IconButton so it gets a real touch
  target instead of a 14dp one nested inside the card's own clickable,
  where a near-miss silently navigated instead.
- Only show that icon when onCardClick is set; without it the icon and the
  card tap did the same thing, so existing note-body link cards stay as-is.
- staticCompositionLocalOf for LocalCurrentExternalScope (constant per
  screen, avoids read tracking per feed row).
- Inset the loading/error URL header to match the card, and use the
  hoisted Size14Modifier.
2026-07-29 15:12:41 -04:00
Claude 65073c351c fix: nudge the mention ostrich 3% back left
Shift the ostrich centre from x=13.2 to x=12.48.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:11:08 +00:00
Claude 34633624cc fix: nudge the mention ostrich ~5% right
Shift the ostrich centre from x=12 to x=13.2.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:09:21 +00:00
Claude 9f367269e6 fix: tuck the mention bridge ends behind the ostrich
Pull the bridge's inner endpoints toward the logo centre so their raw ends
hide under the ostrich (drawn on top) instead of showing as stubs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:05:55 +00:00
Claude 9f77245860 fix: enlarge the mention ostrich ~10%
Grows the Amethyst ostrich in the @ from 9.45 to 10.4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 19:02:05 +00:00
Claude b185f58ada fix: keep the @ bridge and enlarge the ostrich 5%
Drop only the inner "a" circle from the @ outline, keeping the bridge
segments that connect the ring to the "a", and size the ostrich up 5%
(9.0 -> 9.45).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 18:59:43 +00:00
Claude f79741e611 fix: remove the @'s inner ring so the ostrich stands alone
The leftover inner "a" ring sat in front of the ostrich, making the logo
look like it was behind the circle. Drop the inner-a segments from the @
outline, leaving just the outer ring + tail, and size the ostrich so it
reads clearly as the "a".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 18:55:25 +00:00
Claude ff40d49b78 fix: shrink the mention ostrich so it reads as the bird
Smaller centered Amethyst gem inside the @ so the ostrich is distinct
rather than a blob filling the a-space.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 18:49:02 +00:00
Claude 439bc5d5f9 feat: mention = Material @ outline with the gem as the "a"
Reuse the original Material @ shape (keeping its native tail and opening),
drop its inner "a" circle, and place the Amethyst gem there instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 18:33:47 +00:00
Claude bde562b4a6 chore(concord): remove now-unused facepile helpers
Delete ConcordAuthorFacepile and the ConcordChannel/RelayGroupChannel
recentAuthorHexes extensions, orphaned after the channel rows dropped the
recent-posters facepile.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017x22okBh6HbiCrJN3zf5xn
2026-07-29 18:13:06 +00:00
Claude 1793ee5ffe Merge remote-tracking branch 'origin/main' into claude/push-notification-icons-branding-dy4egx 2026-07-29 18:06:34 +00:00
Vitor PamplonaandGitHub 07267e254b Merge pull request #3813 from vitorpamplona/claude/notecompose-media-rendering-f4k7nh
Consolidate NIP-71 video event types under shared interface
2026-07-29 14:04:45 -04:00
Claude 16030599d9 fix(concord): align top-bar height and simplify channel rows
Route the Concord community screen and hub through ShorterTopAppBar (50dp)
instead of the raw Material3 TopAppBar (64dp default), so the top bar — and
its 3-dot overflow menu — sits at the same height as the Buzz/relay-group
community screen, which already uses the shorter bar.

Also drop the recent-posters facepile from the Concord and Buzz channel
rows, and move the last-message time up to the first line (next to the
channel name), leaving the unread-message badge on the second line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017x22okBh6HbiCrJN3zf5xn
2026-07-29 17:18:29 +00:00
Claude ee8623bd20 refactor: dispatch all NIP-71 video kinds via the VideoEvent interface in NoteCompose
RenderNoteRow matched the four concrete video subtypes (VideoNormalEvent 21,
VideoShortEvent 22, VideoHorizontalEvent 34235, VideoVerticalEvent 34236) with
four identical branches. Collapse them into a single `is VideoEvent` branch,
matching how ThreadFeedView's NoteMaster already dispatches, so any future
VideoEvent subtype renders through VideoDisplay automatically instead of
falling through to the text fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QCKP4tD2seoDpr3ZcdPJNx
2026-07-29 17:01:53 +00:00
David KasparandGitHub 7e6170390d Merge pull request #3808 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-07-29 18:52:04 +02:00
Claude de1c4905cc Revert "fix: make mention connector a solid tapering wedge"
Back to the curved thin connecting stroke.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 16:44:17 +00:00
vitorpamplonaandgithub-actions[bot] 0279938e05 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-29 16:41:58 +00:00
Claude 536d3cf1a5 fix: make mention connector a solid tapering wedge
Fill the connector as a solid region: thick at the gem's right side,
tapering to the gem's bottom tip and merging into the ring's upper opening.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 16:38:52 +00:00
Vitor PamplonaandGitHub 979ce7a96f Merge pull request #3812 from vitorpamplona/claude/buzz-channel-delete-persist-e3lex3
NIP-29: Channel deletion, archival, and Buzz community UI
2026-07-29 12:38:42 -04:00
Vitor PamplonaandGitHub 7cda707380 Merge pull request #3811 from vitorpamplona/claude/draft-note-expansion-threadview-u2u32l
Make draft posts in thread view open edit screen on tap
2026-07-29 12:36:44 -04:00
Claude b58543fb2d fix: curve the mention connecting stroke
Replace the flat bar with a curved stroke that sweeps down from the gem and
up into the ring's upper opening, reading as a natural @.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 16:33:30 +00:00
Claude 707cffec6d fix: connect mention tail to the upper end of the ring opening
The bridge now joins the gem to the ring's upper-right end (~3 o'clock),
leaving the lower-right as the ring's free opening — the correct @ side.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 16:29:15 +00:00
Claude d44264a1ac feat(buzz): fix channel/forum type on the create screen from the caller
The create screen no longer shows a "Forum channel" toggle — the type is decided
by the community's per-section "+" (Channels vs Forums) and a Buzz channel's
channel_type isn't editable anyway (the relay's 9002 has no such key). The screen
loads with the fixed isForum parameter and creates the right type; its top-bar
title reads "New forum" when isForum, "New channel" otherwise (on Buzz).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016MNVEKhaAu4vQRZnXv3rfG
2026-07-29 16:22:34 +00:00
Claude 04243d8dfa fix: open edit-draft screen when tapping a draft in ThreadView
Tapping a note in the thread view toggles the collapse/expand state of
its children. For the user's own drafts, tap now opens the edit-draft
screen (via routeEditDraftTo) so the post can be resumed, matching the
behavior everywhere else a draft is tapped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQCNuxdYkfouNN3ujxm3mR
2026-07-29 16:19:17 +00:00
Claude 60161e3fae fix: mention tail connects the gem to the ring
Bridge the tail from the gem's bottom down into the ring's lower opening,
like the inner "a" stem joining the circle in an @.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 16:14:33 +00:00
Claude ca61eb107d fix(buzz): drop deleted channels that leaked as bare UUID rows
A channel deleted elsewhere (or before this device saw its metadata) keeps its
kind-44100 membership — the relay never retracts it — but the relay soft-deletes
its 39000, and it does NOT serve a channel_deleted 40099 for an already-deleted
channel, so the discovery fetch can't catch it. Such a channel arrived with no
metadata and was shown optimistically: a bare UUID row with "No messages yet".

The reliable signal is that very metadata absence. BuzzRelayImportViewModel.discover
now drops channels the relay serves no 39000 for — but only when the fetch clearly
worked (some channel returned a 39000); if none did, the read failed (auth/
connectivity) and the whole set is kept rather than blanking the community. A
genuinely new channel whose 39000 is merely slow returns on the next bind once its
metadata is cached, so the prune is live (not persisted) and self-correcting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016MNVEKhaAu4vQRZnXv3rfG
2026-07-29 16:09:11 +00:00
Claude 9d2c5e0cee fix(buzz): show the channel/forum "+" on any community, not gated on an unloaded roster
The "+" was gated on BuzzCommunityMembership (kind-13534), but that roster is only
fetched by the Members screen — nothing on the channel-list screen subscribes to
it, so isMember read false and the "+" hid even from admins. Match the workspace
overflow menu's approach instead: offer create on any Buzz community and let the
relay reject a non-member's kind-9007 (its own doc: "any member sees them, the
relay only serves the owner/admin ones").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016MNVEKhaAu4vQRZnXv3rfG
2026-07-29 16:07:07 +00:00
Claude e6bce31249 feat: add connected @ tail to the mention ring
The tail now flows out of the ring's upper opening end and hooks to the
right, connected to the ring rather than floating beside it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 16:05:44 +00:00
Claude 38e5c848a4 feat: add @ opening to the mention ring
Cut a clean gap in the lower-right of the circle for the @ opening, with no
separate tail curve.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 15:54:25 +00:00
The Daniel ac426531f3 feat(nip73): show rich previews for external-content comments
Kind 1111 comments scoped to a NIP-73 external identifier (e.g. a web
article) rendered as a bare URL with no context. Reuse the existing
OpenGraph preview pipeline so feed rows, expanded threads, the
reply-compose banner, and the URL thread screen all show a rich
image/title/description card instead, and give the URL thread screen
a proper scrolling header instead of a bare title.
2026-07-29 11:50:17 -04:00
Claude 967d51b6f9 fix: mention is a gem inside a clean complete circle
Drop the @ tail attempts, which read as a drooping curve. The mention is
now just the centered Amethyst gem with a clean full circle around it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfHYcViokBQRtqCW9vLQi
2026-07-29 15:46:21 +00:00