Files
amethyst/docs/changelog/v1.14.00.md
T
Vitor PamplonaandClaude Opus 5 68c1e4d1fe docs(changelog): credit the translators Crowdin recorded without a language
scripts/translators.sh buckets contributors whose sinceLastTag entry carries
an empty languages list under "(unknown language)". Dropping that bucket, as
the first draft did, silently uncredited 18 people who did translate this
cycle — the language is what is missing, not the contribution.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gs2gi3sZfQ7SHrVm2njLMw
2026-08-22 13:04:48 -04:00

295 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# v1.14.0: Highlights, Relay Login, and a Much Faster Start
Highlights:
- Improves **NIP-84 Highlights** — composer, feed, and share intent.
- Redesigns **relay login (NIP-42)** and ends the per-relay prompt storm.
- Adds Share targets to **Pictures, Videos, Shorts and Torrents** feeds.
- Adds a screen that explains **why every relay subscription exists**.
- Fixes the cold-start **out-of-memory kill** and cuts time to first paint.
- Brings **Desktop** to parity on profiles, DMs, settings and key backup.
- Adds **Trusted Lists** (kinds 30392–30395) to Quartz.
## New Features
### Highlights (NIP-84)
- Adds a Highlight composer, with an annotation field, a passage editor, and a
source reference that can be a Nostr event or a web URL.
- Adds a Highlights feed, filterable by authors, follows, hashtags and geohashes.
- Accepts shared text from any app as a new highlight.
### Feeds and Composing
- Adds four home feed content types: Pictures (NIP-68), Videos and Shorts
(NIP-71), and Torrents (NIP-35), each with its own toggle.
- Adds "New Picture", "New Short" and "New Video" share targets, so media shared
into Amethyst opens the matching composer instead of a text note with a link.
- Adds a bulk audience picker to the short-note composer: search people lists and
follow packs, review the members, then add them all at once.
- Adds a poll results page with per-option vote counts and a filterable voter
list, replacing the feed card's four-avatar preview.
- Shows rich previews for comments scoped to external content (NIP-73), both in
the "replying to" line and as the thread's title.
- Offers a "Copy Original / Copy Translated" chooser when copying a note that has
been translated.
- Opens the edit screen when a draft reply is tapped in a thread.
### Relay Login (NIP-42)
- Redesigns the relay login permissions screen. Explicit exceptions, relays
blocked by your block list, and recent logins are now three separate sections.
- Starts new accounts on "always log in" instead of deciding per relay.
- Remembers a login for the rest of the session when you answer without ticking
"remember", so a reconnect stops asking again.
- Honors "always log in" for relays your own account does not publish to.
- Makes the "reading someone I follow" toggle reachable — it sat behind a
first-party gate that could never be true.
- Counts NIP-29 groups and Concord communities as rooms you joined, so their
host relays authenticate under "my relays and venues".
- Waits for an auth challenge to resolve rather than letting the fetch time out.
### Relay Traffic, Explained
- Records why every relay-bound filter exists — its purpose, the entities it
serves and the account that asked — and renders that back on a new screen.
- Fixes the multi-account subscriptions that screen exposed as never running.
- Breaks the resource ledger down by cause, so it reports *why* relay data was
spent, not just how much.
- Stops the automatic "High resource usage detected" dialog on app open. The
ledger keeps recording and Settings still shows the report.
### Chats, Groups and Communities
- Mutes a public chat from a long press in Messages or from the channel menu.
- Deletes (kind 9008) and archives NIP-29 channels, with the Buzz community UI to
match.
- Keeps a channel invite's replies, reactions and zaps inside the relay that sent
the invite, instead of broadcasting them to your outbox.
- Derives Buzz channel invites from cached membership notices, so they stop
appearing and disappearing.
- Redesigns channel invite cards as feed rows, with the person who added you as
the row's author.
- Shows the hosting relay's name chip on relay group message headers.
- Splits the Concord Control Plane's stream key so a staff-held `control_root`
write-gates it (CORD-02 §2).
- Closes the Concord CORD-05/06 invite lifecycle: an Invite List, a re-mint on
Refounding, and revocation.
- Stops pinning Concord entities whose chain crosses a Refounding, which was
discarding their newer state on every refold.
- Closes seven Concord soft-ban holes — a banned member kept `control_root`, half
the Control Plane never read the banlist, and the invite button still worked.
### Everything Else
- Makes the left drawer configurable, so entries you don't use can be hidden.
- Adds ngit-specific search to the Git Repositories screen.
- Supports IPv6 overlay relays (Yggdrasil) with RFC 5952 canonical addresses,
fixing one relay counting as two and Tor-proxying an unreachable overlay.
- Adds a Nostr badge watermark to the notification icons, reshapes the mention
icon, and adds dedicated reply and mark-as-read action icons.
- Runs verified NIP-5D artifacts in an opaque `srcdoc` sandbox behind a first-head
CSP, and advertises only the NAP domains actually implemented.
## Performance
- Scans NIP-19 entities, hashtags and legacy `#[n]` references without ICU. On
Android, `Regex.matchAt` copied the whole note content into native memory per
candidate, which grew a cold start to ~1.9 GB and got the app killed.
- Scans note content by literal instead of restarting the regex engine at every
position in every note.
- AOT-compiles the relay ingest path with a baseline profile. Release cold-start
ingest was spending 36× more CPU interpreting bytecode than verifying
signatures.
- Demotes the ~650 relay and ingest worker threads below the UI thread, so the
connect storm cannot starve the first frames (~40% faster first paint).
- Reclaims memory under heap pressure and stops leaking sandboxed WebView
Activities.
- Bounds the duplicate-frame decoder cache in both size and age.
- Stops blocking coroutine workers on synchronous OkHttp calls, which released
their CPU permits and starved the dispatcher.
- Stops the outbox getting slower with every publish — it rebuilt an immutable map
per send, copying every pending entry.
- Stripes the subscription-state lock per relay, ending the ANR convoy that had
37 of 52 workers spinning on one lock.
- Memoizes Concord guestbook envelope opens, so the fold stops re-decrypting the
whole buffer on every arrival.
- Caches the painter on its first miss in `painterRes`.
- Optimizes the proof-of-work mining hot loop for the Android runtime.
- Skips the ~220 ms system call when the app locale has not actually changed.
- Confines the Blossom cache probe and server resolver to the IO dispatcher, and
re-probes it when the toggle flips.
- Releases dead subscription rows, so connect and disconnect stop scanning every
subscription ever created.
- Prefetches NIP-73 external-content preview URLs so those cards stop popping in
mid-scroll.
- Adds fixed-size hex codecs for 32- and 64-byte values.
## Improvements and Bug fixes
- Settles the keyboard inside navigation, so leaving a screen mid-animation stops
stranding `imePadding` across the whole app.
- Routes the draft-saving editors through `KeyboardAwareBackHandler`, so a
predictive back gesture no longer races the IME close.
- Raises the keyboard again when you tap a field in an embedded tab that was
already focused.
- Pads for the soft keyboard in full-screen napplet hosts on Android 15+.
- Fixes the crash when switching between two pinned web-app tabs.
- Stops drawing a blank parent card above a top-level community post.
- Fixes Cashu wallet balances reading low: proofs are now backfilled past the
relay's page cap and history is paged.
- Keeps PDF previews stable — the page ratio is cached, so scrolling back no
longer collapses the card and replays the grow-in animation.
- Stops rendering non-media NIP-94 files as video.
- Repairs `imeta` MIME types written as a bare subtype, so those images can be
shared again.
- Works around a fatal media3 crash on Low-Latency HLS streams.
- Drives the "Can't reach this relay over Tor" banner from live socket state
instead of a bare six-second timer.
- Stops a lone repost from being bundled into the always-on service notification,
where it inherited the ongoing flag and refused to swipe away.
- Fails push registration loudly on an HTTP error, instead of caching a token for
a device that will never receive anything.
- Listens for location only while foregrounded, and fixes the meter that reported
7 hours of listening against 9 seconds of foreground.
- Excludes quote characters from parsed URLs.
- Fixes the OpenGraph meta parser losing every tag after an apostrophe inside a
comment or script, which broke link previews on some sites.
- Requests the follower-count provider's kind 30382 cards, so the count stops
rendering as `--`.
- Gives the invite roster line's member count its unit, so a bare number no longer
reads as counting the avatars beside it.
- Removes the recent-poster facepile from Concord and Buzz channel rows.
- Renders every NIP-71 video subtype through the shared interface.
- Reworks the chat bubble reply swipe on lower-level pointer APIs, so it only
claims the gesture once the motion is clearly horizontal.
- Turns the default log into a boot narrative instead of a firehose.
- Converts the drawer's hidden-count to a plural, fills the untranslated backlog
for Czech, German, Swedish and Brazilian Portuguese, restores placeholders
dropped from German and Polish plurals, and drops an unused plural.
## Desktop
- Enriches the DM composer and message list: emoji picker with custom emoji,
@mentions, reply-quoting with jump-to-original, Nostr-native GIF search, rich
message rendering, per-message image quality, and encrypted file uploads.
- Redesigns Settings as a searchable accordion of labeled cards, with
expand/collapse-all and a filter over titles and keywords.
- Brings the profile screen to parity: banner, rich-text bio, a CLINK offer field,
six new tabs (Followers, Following, Relays, Bookmarks, Yours, Zaps received) and
header actions.
- Adds a guided "save your keys" step on first run and a key backup in Settings.
Android gets a soft nudge after signup.
- Loads metadata and reactions only for what is on screen, through the shared
finders in `commons`, and unsubscribes when it leaves.
- Enables the master notification switch when the OS permission is already
granted.
- Publishes Windows arm64 and Linux arm64 desktop builds.
## Cli
- Gives `amy` the Concord key lifecycle it was missing: accept a promotion, follow
a Refounding, perform one, and recover when left out of it.
- Publishes Windows and Linux arm64 assets for `amy` and `geode`.
- Reports "no relays" only when there really were none, and pins the buzz wrapper
copies against the argument surface they call.
## Quartz
- Adds Trusted Lists (kinds 30392–30395), the aggregate counterpart to NIP-85
Trusted Assertions, and indexes their labels for NIP-50 search.
- Fixes a `SharedKeyCache` collision that could return one peer's shared secret
for another peer's message, and compares MACs in constant time.
- Measures NIP-66 relay health from traffic the client already makes, streams
probe verdicts as relays answer, checks read and write separately, lets a
monitor publish what it learned without dialling, and merges verdicts into the
record they replace instead of overwriting it.
- Measures `rtt-open` as the transport handshake, not the time the call spent
queued in the dispatcher.
- Records sync coverage per kind rather than one interval per filter, keys its
persistence with a typed band, closes a drained leg, and terminates a paged walk
against a relay that ignores `until`.
- Strikes a host out and tracks its unreachability with publish-safe semantics,
so a dead host stops being retried at the same rate as a live one.
- Sizes negentropy reconcile windows from the caller's own index, states the
relay's cap, and lets a caller decline an id before its body crosses the wire.
- Normalizes every accessory timeout to an idle window, drops the `maxTotalMs`
ceiling that cut healthy fetches, and stops `fetchAllPages` cropping a streaming
page.
- Stops COUNT inheriting the REQ page size, which capped a count at 500.
- Suspends the incoming-message chain down to `SubscriptionListener.onEvent`, so a
consumer that cannot keep up no longer blocks every shared worker.
- Compares every filter in `FiltersChanged`, not just the first.
- Fixes an `InProcessWebSocket` race that delivered a connect-time AUTH challenge
before `onOpen`.
- Adds `StoreQueryContext`, carrying the NIP-42-authenticated caller identity into
observer-relative stores.
- Adds a NIP-50 search grammar (quoted phrases, negation) with weighted field
extraction, and shares the store-semantics rules across implementations.
- Parses metadata leniently everywhere, and recovers blank, single-element and
malformed kind-0 content instead of dropping the profile.
- Parses `ServiceType` without splitting on a separator that may not be there.
- Declares pointer hints on Report, ChatMessage, Classifieds and ChannelCreate.
- Refreshes `created_at` while mining, so a post that takes minutes to mine does
not publish stale.
- Decouples the `LocalCache` and `Account` god classes into single-purpose
collaborators, 3,800 lines lighter, with no behavior change.
## Build & Documentation
- Adds a `:baselineprofile` module that records a real startup journey, replacing
the hand-authored profile's wildcards.
- Notarizes the macOS DMG and verifies it, adds `libegl1` to the arm64 `.deb`
dependencies, and moves the Homebrew and Winget bumps onto a maintainer machine.
- Shrinks the mirror-sync throughput corpus on CI, which had been timing out the
`test-geode` job for weeks.
- Confines the QUIC stream drainer to the producer's event loop, deflaking it
under parallel test load.
- Hardens `workflow-ship.sh` and pins it with a regression harness.
- Adds three store-implementer skills: event store semantics, NIP-85 trusted
assertions and searchable events.
- Bumps 30+ dependencies plus Gradle, Compose, Firebase, Media3, Ktor and OkHttp.
## Contributors
- @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- @npub1e2yuky03caw4ke3zy68lg0fz3r4gkt94hx4fjmlelacyljgyk79svn3eef
- @npub12cfje6nl2nuxplcqfvhg7ljt89fmpj0n0fd24zxsukja5qm9wmtqd7y76c
- @npub1aeh2zw4elewy5682lxc6xnlqzjnxksq303gwu2npfaxd49vmde6qcq4nwx
- @npub1uac67zc9er54ln0kl6e4qp2y6ta3enfcg7ywnayshvlw9r5w6ehsqq99rx
- @npub1q3sle0kvfsehgsuexttt3ugjd8xdklxfwwkh559wxckmzddywnws6cd26p
- @npub1gvv9ahktvavf9qjtrgm62le7gplmmchd5usp5wpfhr85hf79kncqj8xchs
## Translations
- Chinese Simplified by @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- Czech by @npub1e2yuky03caw4ke3zy68lg0fz3r4gkt94hx4fjmlelacyljgyk79svn3eef and @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- Dutch by @npub1w4la29u3zv09r6crx5u8yxax0ffxgekzdm2egzjkjckef7xc83fs0ftxcd and @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- German by @npub1e2yuky03caw4ke3zy68lg0fz3r4gkt94hx4fjmlelacyljgyk79svn3eef and @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- Hindi by @npub1ww6huwu3xye6r05n3qkjeq62wds5pq0jswhl7uc59lchc0n0ns4sdtw5e6 and @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- Hungarian by @npub1dnvslq0vvrs8d603suykc4harv94yglcxwna9sl2xu8grt2afm3qgfh0tp and @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- Latvian by @npub1l60stxkwwmkts76kv02vdjppka9uy6y3paztck7paau7g64l687saaw6av
- Polish by @npub16gjyljum0ksrrm28zzvejydgxwfm7xse98zwc4hlgq8epxeuggushqwyrm and @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- Brazilian Portuguese by @npub1e2yuky03caw4ke3zy68lg0fz3r4gkt94hx4fjmlelacyljgyk79svn3eef and @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- Slovenian by @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- Swedish by @npub1e2yuky03caw4ke3zy68lg0fz3r4gkt94hx4fjmlelacyljgyk79svn3eef and @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- Additional translations, with the language not recorded by Crowdin, by
@npub106efcyntxc5qwl3w8krrhyt626m59ya2nk9f40px5s968u5xdwhsjsr8fz,
@npub10ug9xs24ay5339agakaqk556t6zvq9qn5vm0vlhc4pu25cx0l32qxhrm9e,
@npub13qtw3yu0uc9r4yj5x0rhgy8nj5q0uyeq0pavkgt9ly69uuzxgkfqwvx23t,
@npub16gjyljum0ksrrm28zzvejydgxwfm7xse98zwc4hlgq8epxeuggushqwyrm,
@npub19jk45jz45gczwfm22y9z69xhaex3nwg47dz84zw096xl6z62amkqj99rv7,
@npub1cdy4mhznq7dex8u8ylnlws5vj0ckzgnxyyxq4h87pyk8m6s0pf3ssspdkl,
@npub1cpazafytvafazxkjn43zjfwtfzatfz508r54f6z6a3rf2ws8223qc3xxpk,
@npub1gd8e0xfkylc7v8c5a6hkpj4gelwwcy99jt90lqjseqjj2t253s2s6ch58h,
@npub1luhyzgce7qtcs6r6v00ryjxza8av8u4dzh3avg0zks38tjktnmxspxq903,
@npub1qqqqqqz7nhdqz3uuwmzlflxt46lyu7zkuqhcapddhgz66c4ddynswreecw,
@npub1raspu6ag9kfcw9jz0rz4z693qwmqe5sx6jdhhuvkwz5zy8rygztqnwfhd7,
@npub1tr66yvqghfdgwv9yxhmg7xx6pvgvu5uvdc42tgdhsys8vvzdt8msev06fl,
@npub1ust7u0v3qffejwhqee45r49zgcyewrcn99vdwkednd356c9resyqtnn3mj,
@npub1vm0kq43djwdd4psjgdjgn9z6fm836c35dv7eg7x74z3n3ueq83jqhkxp8e,
@npub1w4uswmv6lu9yel005l3qgheysmr7tk9uvwluddznju3nuxalevvs2d0jr5,
@npub1wujmwnq0we8qs44fhxsducavekk3r2y3ln3kplhstk99n4spaqpqpzamjm,
@npub1ww8kjxz2akn82qptdpl7glywnchhkx3x04hez3d3rye397turrhssenvtp,
@npub1x3azxuysp5vmfer4vgs4jn5tmfcx4ew8sh0qnev7gczljxsr7jwqa3g4el.