Skip to content

1.0.20

Latest

Choose a tag to compare

@rabble rabble released this 17 Aug 08:46
· 16 commits to main since this release
97801bb

Welcome home. We left the light on — or off. Your call.

Light mode has landed. Settings → General → Appearance, then pick System, Light or Dark. Dark's still home base.

Badges, made by you

Mint a Nostr badge and hand it to someone without ever leaving the app. See one on a profile? Tap it and we'll tell you what it took to earn.

The editor got hands

Crop, rotate and flip your stop-motion frames. Cropping moves like it should now, sound waveforms actually look like the sound, and when a render goes sideways we tell you why instead of shrugging.

Your library, your rules

Drafts are one tap from the recorder. Pinch to zoom the grid, long-press and drag to grab a fistful of clips, and file them wherever makes sense to you.

Captions that keep up

Time your captions against the video instead of counting seconds in your head. No captions? We'll say why, and help you write them.

A feed that knows what you've seen

Stuff you've already watched steps aside for stuff you haven't. And when a feed won't load, we'll tell you straight whether it's us or your signal.

You, in charge

Change your Divine email and password in Settings. Link and unlink accounts right here. Your followers sort newest-first, and profiles lead with something friendlier than a wall of characters.

Sounds that travel

Save a sound on one device, find it on the next.

Everyone gets in

Screen readers can now drive the editor, the recorder and your profile tabs. If you've asked your phone to ease up on motion, we listen.

Plus: every language we ship got its missing words filled in, uploads hold on tight when your connection doesn't, deleted videos actually leave, bookmarks stay put, notifications say what really happened, and we tightened up privacy and security throughout.

Go make something. We'll be here.


Full changelog — every pull request in this release

What's Changed

  • fix(library): move clip selection into a sheet footer by @hm21 in #6836
  • fix(a11y): make icons and tight layouts survive system font scaling by @hm21 in #6844
  • fix(drafts): stop the library from restamping and hiding drafts by @hm21 in #6832
  • fix(video-editor): stop speed-render thrash stalling the encoder by @hm21 in #6817
  • test(personal-event-cache): bound provider waits on wall-clock time by @hm21 in #6849
  • fix(notifications): stop labelling video likes "liked your comment" by @rabble in #6805
  • fix(publish): only self-label content language when the user declared one by @rabble in #6804
  • fix(nostr): bound and validate relay-list admission by @realmeylisdev in #6746
  • fix(engagement): resolve the author key before querying likes, votes and reposts by @realmeylisdev in #6819
  • feat(video-recorder): show the remaining shot budget in stop-motion by @hm21 in #6842
  • fix(video-metadata): keep the preview rounded and make the audio credit form readable by @hm21 in #6829
  • test(flake): stop two suites failing on what ran before them by @hm21 in #6874
  • fix(video-metadata): stop painting the clip cover's edits twice by @hm21 in #6893
  • fix(video-metadata): make the post-details flow readable to screen readers by @hm21 in #6887
  • fix(a11y): honour reduced motion in tab transitions and the recorder mode wheel by @hm21 in #6883
  • fix(nostr): keep the relay count when a publish reaches nothing by @rabble in #6681
  • fix(sounds): let a failed audio extraction publish the video anyway by @rabble in #6659
  • fix(local-stack): resolve the local host per platform by @realmeylisdev in #6840
  • fix(feed): make the first tap on a stopped video play it by @realmeylisdev in #6892
  • build(mobile): upgrade patrol to 4.8.0 and pin patrol_cli 4.6.1 by @realmeylisdev in #6925
  • fix(a11y): make library and clip controls readable to screen readers by @hm21 in #6881
  • chore(dependencies): remove cryptography_flutter override by @NotThatKindOfDrLiz in #6923
  • fix(editor): stop the publish OOM on stop-motion clips by @hm21 in #6947
  • fix(a11y): make video editor controls readable to screen readers by @hm21 in #6885
  • fix(feed): page the New feed on the repository's hasMore flag by @hm21 in #6945
  • refactor(video-editor): split the canvas into focused files by @hm21 in #6890
  • fix(feed): clear a stranded page overlay when the shell is uncovered by @realmeylisdev in #6889
  • fix(ios): derive extension versions from Flutter by @NotThatKindOfDrLiz in #6929
  • fix(video): restore deletion copy across surfaces by @NotThatKindOfDrLiz in #6914
  • fix(a11y): announce the branded loading indicator as busy by @hm21 in #6956
  • fix(support): preserve portrait clip imports by @NotThatKindOfDrLiz in #6939
  • fix(support): preserve text edits on imported vines by @NotThatKindOfDrLiz in #6938
  • test(flake): wait for the encoder to actually start, not for a pumped queue by @hm21 in #6895
  • fix(video-recorder): make recorder controls readable to screen readers by @hm21 in #6876
  • fix(comments): show an in-flight video reply on its destination sheet by @realmeylisdev in #6960
  • fix(profile): remove deleted videos from profile tabs by @NotThatKindOfDrLiz in #6942
  • fix(e2e): make the Maestro smoke suite runnable again by @realmeylisdev in #6948
  • fix(imeta): parse positional comment and NIP-94 metadata by @NotThatKindOfDrLiz in #6962
  • fix(collabs): render only confirmed collaborators to third-party viewers by @realmeylisdev in #6970
  • fix(dm): label retired moderation threads and close their dead composer by @realmeylisdev in #6963
  • test(analytics): assert the home feed actually publishes its source detail by @rabble in #6870
  • fix(lists): dismiss editor before relay acknowledgement by @rabble in #6861
  • fix(repositories): stop an unreadable local cache from blocking relay publishes by @rabble in #6867
  • feat(analytics): instrument creator campaign funnel by @rabble in #6871
  • feat(sounds): sync saved sound library across devices by @rabble in #6856
  • feat(seen): client-side seen-video filtering across feeds by @rabble in #6869
  • docs(testing): add 4337 test debt plan by @NotThatKindOfDrLiz in #6915
  • fix(invites): drive invite status from the nostr session readiness contract by @dcadenas in #6981
  • fix(account): clear dm_message_reactions on sign-out and Delete Account by @realmeylisdev in #6991
  • ci(deps): monitor dependency freshness and freeze dependency provenance by @realmeylisdev in #6990
  • docs(maintainability): refresh oversized-file inventory by @NotThatKindOfDrLiz in #6936
  • fix(ios): align firebase_remote_config with the firebase_core 4.4.0 release by @rabble in #7016
  • fix(profile): drop the extra vertical gap around the follower search field by @hm21 in #7011
  • test(relay-discovery): stop the invalid-signature test degenerating by @realmeylisdev in #6995
  • feat(profile): sort the follower and following lists, newest first by default by @hm21 in #6964
  • fix(for-you): rebuild the algorithm header and explainer on the design system by @hm21 in #6851
  • test(recorder): cover capture mode with Maestro E2E by @hm21 in #7018
  • docs(data-foundation): define storage and cache policy by @NotThatKindOfDrLiz in #6972
  • fix(likes): retract a like unliked while its publish is in flight by @realmeylisdev in #7004
  • fix(subtitles): report why captions are missing and let creators write them by @hm21 in #6943
  • ci(deps): stop assigning every dependabot pr to one person by @hm21 in #7033
  • fix(profile): explain profile badges by @NotThatKindOfDrLiz in #6993
  • fix(db-client): move schema repair into drift migration by @NotThatKindOfDrLiz in #6976
  • fix(likes): chunk the reaction REQ filters like the deletion probe by @realmeylisdev in #6997
  • fix(a11y): give the profile tabs and grids real accessible names by @realmeylisdev in #7009
  • test(recorder): cover lip-sync mode with Maestro E2E by @hm21 in #7043
  • feat(badges): make and hand out Nostr badges without leaving the app by @hm21 in #7014
  • fix(badges): translate the profile badge sheet into every locale by @hm21 in #7023
  • ci(deps): bump cloudflare/wrangler-action from 3 to 4 by @dependabot[bot] in #7006
  • ci(deps): bump actions/setup-java from 4 to 5 by @dependabot[bot] in #7008
  • ci(deps): bump actions/upload-artifact from 4 to 7 by @dependabot[bot] in #7007
  • fix(feed): stop the fullscreen feed hanging on a loading placeholder when its source empties by @realmeylisdev in #7034
  • fix(safety): let a blocked conversation stay readable without unblocking by @realmeylisdev in #7026
  • test(explore): keep the popular-tab suite off the real image cache by @hm21 in #7054
  • test(e2e): repair the search and comment smoke flows by @realmeylisdev in #7039
  • ci(e2e): make the service workflow run, and fix the e2e suites it covers by @realmeylisdev in #7005
  • build(ios): refresh the SPM lockfiles for patrol's Swift Package by @hm21 in #7065
  • test(recorder): cover stop-motion mode with Maestro E2E by @hm21 in #7036
  • feat(library): reach drafts from the recorder library by @hm21 in #7031
  • test(notifications): unpin the row layout test from font load order by @hm21 in #7052
  • fix(video-editor): stop the clip picker closing on a short drag by @hm21 in #7056
  • fix(video-editor): make the crop editor feel smooth and on-brand by @hm21 in #7062
  • feat(subtitles): time captions against the video instead of typed seconds by @hm21 in #7060
  • feat(verify): link and unlink accounts without leaving the app by @hm21 in #7028
  • fix(upload): keep the resumable session alive on a chunk 408 by @rabble in #7050
  • test(helpers): give each test process its own path_provider directories by @rabble in #6878
  • feat(trust-safety): block badge claimants by @NotThatKindOfDrLiz in #7082
  • fix(support): vary classics feed sessions by @NotThatKindOfDrLiz in #7083
  • fix(lists): refresh discover list subscriptions by @NotThatKindOfDrLiz in #7097
  • feat(feed): hide small view counts on video cards behind a flag by @rabble in #6872
  • feat(profile): hide a small loop total from profile visitors by @rabble in #7013
  • docs: add the misaligned-plugin cause to iOS SPM troubleshooting by @rabble in #7020
  • ci(supporters): pass the supporter defines through Codemagic builds by @rabble in #6999
  • refactor(settings): move FeatureFlagScreen and four siblings onto go_router by @realmeylisdev in #7087
  • fix(report): carry the uncollapsed report reason on the moderation DM by @realmeylisdev in #6855
  • fix(dm): re-derive the DM publish backstop and bound the crypto chain by @realmeylisdev in #7075
  • fix(bookmarks): reconcile with the relay before reading or publishing kind 10003 by @realmeylisdev in #6966
  • ci(mobile): run Mobile CI on merge_group events by @hm21 in #7058
  • test(recorder): cover classic mode with Maestro E2E by @hm21 in #7078
  • feat(video-editor): crop, rotate and flip a stop-motion frame by @hm21 in #7069
  • fix(dm): recognize divine-web's legacy DM video-share citation by @realmeylisdev in #7108
  • fix(deps): declare permissions_service in the app pubspec by @realmeylisdev in #7116
  • fix(verify): guard kind-10011 identity writes against stale reads by @hm21 in #7115
  • fix(perf): initialize performance monitoring in the critical startup phase by @hm21 in #7126
  • fix(video-editor): reclaim the render a transform superseded by @hm21 in #7113
  • feat(perf): instrument Dart-side HTTP with HttpMetric by @hm21 in #7131
  • refactor(packages): remove Flutter SDK dependencies from repository packages by @realmeylisdev in #7107
  • fix(video-editor): report why a render produced no video by @hm21 in #7138
  • fix(library): restore ink splashes on library rows by @hm21 in #7111
  • fix(bottom-sheet): stop selection pickers closing on a short drag by @hm21 in #7114
  • fix(video-editor): stop the sound preview ring from rewinding by @hm21 in #7149
  • fix(video-editor): scale the sound layer's waveform against its own peak by @hm21 in #7144
  • fix(auth): handle an undeployed resend endpoint and a double-tapped signup by @dcadenas in #7084
  • fix(support): retry account deletion relay confirmation by @NotThatKindOfDrLiz in #7101
  • ci(architecture): ratchet service god-file growth by @NotThatKindOfDrLiz in #6932
  • fix(categories): block moderation-adjacent discovery categories by @NotThatKindOfDrLiz in #6937
  • chore(release): bump app version to 1.0.20 by @rabble in #7110
  • refactor(packages): delete the orphaned nostr_apps fork (#3347) by @realmeylisdev in #7154
  • docs(ci): document ratchet CI placement by @NotThatKindOfDrLiz in #7164
  • fix(db): fail closed when the local database is damaged past classification by @hm21 in #7157
  • feat(library): pinch to zoom the clips grid by @hm21 in #7129
  • fix(library): rework the Sounds tab layout and sound actions by @hm21 in #7155
  • feat(upload): report the nostr blurhash pass as a publish metric by @hm21 in #7127
  • fix(video): play classic Vine originals on iOS by @realmeylisdev in #7171
  • feat(explore): configurable featured hashtag tab by @NotThatKindOfDrLiz in #6858
  • fix(feed): recover from a feed load the relay never answered by @hm21 in #7161
  • fix(perf): keep developer builds out of the production Firebase Performance dataset by @hm21 in #7158
  • fix(db): delete unreadable plaintext reset source by @NotThatKindOfDrLiz in #7173
  • fix(recorder): discard the recording session when leaving the camera by @hm21 in #7142
  • fix(routing): route divine:///saved-videos and close the custom-scheme gate by @realmeylisdev in #7105
  • fix(bookmarks): show save progress while relay reconcile and publish are in flight by @realmeylisdev in #7141
  • fix(db): unblock db_client analyze on newer Dart stable by @realmeylisdev in #7188
  • fix(notifications): keep mid-sentence mentions in comment previews by @realmeylisdev in #7140
  • feat(invites): respect server-controlled invite availability by @dcadenas in #7183
  • fix(feeds): hide blocked reposts and removed videos by @NotThatKindOfDrLiz in #7176
  • feat(captions): scope feed toggle to current video by @NotThatKindOfDrLiz in #6910
  • feat(notifications): open grouped engagement lists by @NotThatKindOfDrLiz in #7190
  • fix(ci): drop the supporters variable group that does not exist yet by @rabble in #7191
  • fix(privacy): sanitize public bug report diagnostics by @NotThatKindOfDrLiz in #6909
  • fix(support): align follower counts by @NotThatKindOfDrLiz in #6911
  • fix(storage): preserve notification prefs during cache recovery by @NotThatKindOfDrLiz in #6920
  • docs(video): clarify bare blob playback failure by @NotThatKindOfDrLiz in #7185
  • fix(clip-reuse): preserve multi-source clip credits by @NotThatKindOfDrLiz in #6928
  • ci: reuse dart hook downloads so merge-queue jobs skip the fetch by @dcadenas in #7199
  • fix(bookmarks): make the share-sheet save affordance reflect the existing bookmark by @realmeylisdev in #7133
  • fix(l10n): stop plural arms rendering a hardcoded number by @realmeylisdev in #7153
  • refactor(profile): inject username and NIP-05 service endpoints by @realmeylisdev in #7167
  • feat(lists): publish private lists to relays with NIP-44 encrypted items by @rabble in #6661
  • test(router): stop the NIP-05 navigation test depending on test order by @hm21 in #7181
  • fix(view-events): restore kind 22236 publishing from the durable queue by @rabble in #7210
  • feat(library): file clips into categories from a filter chip row by @hm21 in #7094
  • test: stop two widget tests depending on test order by @hm21 in #7186
  • fix(analytics): persist the addressable d tag on queued view events by @realmeylisdev in #7182
  • feat(metrics): count every playback start as view with fractional loops by @rabble in #7217
  • chore(lint): enable 18 analyzer rules and fix their violations by @hm21 in #7223
  • fix(analytics): route missing-d-tag drops through ViewEventPublisher by @realmeylisdev in #7221
  • fix(video-metadata): let Save for Later work while the render runs by @hm21 in #7229
  • fix(library): collapse library toolbar actions when the row runs out of room by @hm21 in #7172
  • fix(perf): give each upload leg its own operation-scoped trace by @hm21 in #7132
  • fix(library): scope bulk clip actions to the visible selection by @hm21 in #7215
  • fix(library): tighten the trash bin row layout by @hm21 in #7226
  • ci(pr-issue-link): reuse a PR's tracking issue instead of duplicating it by @hm21 in #7240
  • feat(library): drag a selection across the clips grid with a long press by @hm21 in #7219
  • fix(bookmarks): read NIP-51 private items so saving cannot leak them by @realmeylisdev in #7222
  • feat(l10n): translate every locale's untranslated strings by @hm21 in #7237
  • fix(library): stop the screen flashing black when a clip is trashed by @hm21 in #7233
  • fix(library): scroll the library empty state instead of clipping it by @hm21 in #7249
  • chore(services): retire the remaining bare TODOs by @hm21 in #7258
  • build(mobile): upgrade patrol to 4.9.0 and pin patrol_cli 4.7.0 by @hm21 in #7228
  • refactor(packages): drop dm_repository's Flutter dependency and freeze the boundary by @realmeylisdev in #7252
  • fix(lint): enable invalid_assignment and cast the JSON decode boundaries by @hm21 in #7250
  • fix(video-editor): keep the trim handle at the composition end grabbable by @hm21 in #7256
  • test(settings): stop the scaffold test stranding an open Hive box by @hm21 in #7264
  • refactor(analytics): convert the analytics package's singletons to constructor injection by @realmeylisdev in #7265
  • fix(safety): remove blocked accounts from the public kind-3 follow list by @realmeylisdev in #7262
  • chore(lint): enable eight more analyzer rules and fix their violations by @hm21 in #7251
  • ci(e2e): make the iOS Maestro smoke gate run green on every PR by @rabble in #7208
  • fix(likes): resolve the "Liked by" list through funnelcake so edits cannot strand likers by @realmeylisdev in #7261
  • fix(settings): say what turning off client attribution costs by @realmeylisdev in #7280
  • test(widget-tests): pump a frame between scrolling and tapping by @hm21 in #7214
  • refactor(web): migrate the bug-report downloads off deprecated dart:html by @hm21 in #7255
  • fix(l10n): refresh stale delete-menu subtitles in 14 locales by @hm21 in #7270
  • test(e2e): close the SemanticsHandle race that flakes the first Patrol test by @hm21 in #7271
  • fix(perf): release feed-load trace handles when a load is torn down by @hm21 in #7268
  • fix(sound): rebuild the sound detail screen on divine_ui and slivers by @hm21 in #7235
  • fix(nip07): read the extension's relay list instead of skipping it by @hm21 in #7259
  • fix(packages): stop unawaited futures escaping try/catch in four sites by @realmeylisdev in #7279
  • ci(packages): pin package workflows to the repo Flutter toolchain by @realmeylisdev in #7309
  • fix(routing): gate universal links to /profile, /hashtag, /search and /list by @realmeylisdev in #7253
  • refactor(config): remove legacy backend host references by @realmeylisdev in #7281
  • fix(dm): classify Keycast's 504 as a retryable signer timeout and re-derive the per-op RPC bound by @realmeylisdev in #7282
  • fix(metrics): restart same-video view sessions by @rabble in #7231
  • fix(library): keep sub-second precision in the trash row duration by @rabble in #7313
  • test(bookmarks): pin the mid-decrypt window the racing-sync test missed by @rabble in #7315
  • refactor(nostr): retire the legacy kind 30000 block list by @realmeylisdev in #7283
  • refactor(auth): replace the LocalKeySigner(null) placeholder with a typed keyless signer by @realmeylisdev in #7287
  • fix(theme): migrate the crossposting settings screen to the light palette by @hm21 in #7269
  • fix(divine_ui): align the snackbar with its Figma spec by @hm21 in #7147
  • test(safety): drop the stale kind-30000 assertion from the block e2e by @realmeylisdev in #7349
  • fix(feed): pop the adult-content prompt through the sheet's own context by @hm21 in #7299
  • fix(media-cache): stop reporting recoverable image-cache IO failures by @hm21 in #7305
  • test(media-cache): pin the post-open write-failure orderings by @realmeylisdev in #7360
  • fix(profile): keep the session-expired sheet working after the header unmounts by @hm21 in #7304
  • fix(app-update): present the update dialog through the root navigator by @hm21 in #7300
  • fix(providers): abandon in-flight list provider work after disposal by @hm21 in #7353
  • fix(relay): close the WebSocket sink on idle-timeout disconnect by @hm21 in #7355
  • fix(dm): authenticate the read-marker author before applying read cursors by @realmeylisdev in #7348
  • perf(dm): cut a 1:1 DM from four signer round trips to one via keycast's nip17_wrap_batch by @realmeylisdev in #7288
  • fix(text): sanitize malformed UTF-16 in remote content at the model boundary by @hm21 in #7352
  • fix(uploads): resolve publish-snackbar ancestors nullably by @hm21 in #7363
  • fix(feed): repair a silent relay while the feed load is still waiting by @hm21 in #7365
  • fix(storage): give Hive one home path instead of reassigning it mid-startup by @hm21 in #7276
  • fix(bloc): stop add/emit after close in work that outlives the bloc by @hm21 in #7356
  • chore(post-publish): drop the never-configured Remote Config kill switch by @hm21 in #7361
  • ci(preview): skip web preview build and deploy on draft PRs by @hm21 in #7373
  • fix(observability): stop reporting expected DNS failures to Crashlytics by @hm21 in #7306
  • fix(profile): present the session-expired sheet once instead of stacking it by @hm21 in #7351
  • fix(avatar): match the SVG guard to the parser it protects by @hm21 in #7357
  • fix(media-cache): cap cache filenames so long image URLs stay cacheable by @hm21 in #7364
  • feat(settings): change the Divine-login email and password from Settings by @hm21 in #7368
  • fix(firebase): make Android initialization idempotent by @NotThatKindOfDrLiz in #7396
  • fix(video): avoid stale derivative source after publish by @NotThatKindOfDrLiz in #7400
  • fix(analytics): downgrade non-addressable view drops by @NotThatKindOfDrLiz in #7399
  • fix(blossom): demote ProofMode header budget log by @NotThatKindOfDrLiz in #7394
  • fix(profile): cache author video lists by @NotThatKindOfDrLiz in #7414
  • fix(storage): report cache usage by category by @NotThatKindOfDrLiz in #7415
  • fix(network): remove Vine CDN DNS override by @NotThatKindOfDrLiz in #7412
  • fix(editor): keep playback gated during clip reload by @NotThatKindOfDrLiz in #7402
  • fix(providers): remove DM cleanup Riverpod cycle by @NotThatKindOfDrLiz in #7398
  • fix(video): stop preferring dead stream media by @NotThatKindOfDrLiz in #7413
  • fix(notifications): clear iOS app badge defensively by @NotThatKindOfDrLiz in #7423
  • fix(notifications): always send mark-all read by @NotThatKindOfDrLiz in #7421
  • fix(analytics): name shell route pages by @NotThatKindOfDrLiz in #7418
  • fix(dm): re-drive the parked row when a reel reply retry is tapped by @realmeylisdev in #7382
  • docs(library): name the real reason both icon buttons measure 48px by @rabble in #7314
  • feat(feed): hide small loop counts for everyone, not behind a dead flag by @rabble in #7452
  • feat(startup): log build provenance by @NotThatKindOfDrLiz in #7393
  • fix(c2pa): classify signer credential failures by @NotThatKindOfDrLiz in #7395
  • fix(recorder): defer overlay visibility lifecycle writes by @NotThatKindOfDrLiz in #7401
  • docs: record pre-change baseline for view and loop metrics by @rabble in #7218
  • fix(db_client): consolidate explicit index declarations into Drift schema (fixes #7040) by @NotThatKindOfDrLiz in #7416
  • feat(settings): link account portability flow by @NotThatKindOfDrLiz in #7492
  • fix(feed): track pause-aware overlays by owner by @NotThatKindOfDrLiz in #7500
  • fix(video-editor): make teardown and render cancel idempotent by @NotThatKindOfDrLiz in #7422
  • fix(support): route For You through repository by @NotThatKindOfDrLiz in #7478
  • fix(overlays): make bottom sheets owner-backed by @NotThatKindOfDrLiz in #7503
  • fix(avatars): never request verified-dead v.cdn.vine.co image URLs by @rabble in #7466
  • fix(search): rank people results by video count when follower sort is a no-op by @rabble in #7453
  • docs: record that Divine does not run release freezes by @rabble in #7211
  • fix(share): render share-sheet contacts cache-first, hydrate in background by @rabble in #7451
  • fix(notifications): close app-badge review findings from #7423 by @realmeylisdev in #7447
  • chore(bloc): add a shared close guard and freeze the post-close emit/add count by @hm21 in #7376
  • docs(bookmarks): clarify reconciliation helper docs by @NotThatKindOfDrLiz in #7445
  • test(c2pa_signing_service): add test coverage and fix tech debt by @NotThatKindOfDrLiz in #7432
  • feat(swap_account): support retargeting followers, following, and profile-view routes during account switch by @NotThatKindOfDrLiz in #7467
  • ci: fail when a Codemagic variable group is undocumented by @rabble in #7205
  • ci(deps): bump actions/download-artifact from 5 to 8 by @dependabot[bot] in #7429
  • docs(metrics): the display floor is live for everyone, not feature-gated by @rabble in #7502
  • fix(network): retry Funnelcake reads and stop reporting unreachable as empty by @rabble in #7521
  • refactor(router): extract route locations into a RoutePaths leaf by @realmeylisdev in #7444
  • ci(deps): bump actions/checkout from 4 to 7 by @dependabot[bot] in #7430
  • ci(deps): bump gradle/actions from 4 to 6 by @dependabot[bot] in #7431
  • feat(profile): give the Divine team the profile checkmark by @hm21 in #7419
  • fix(video-detail): stop reporting an unreachable lookup as a missing video by @rabble in #7522
  • fix(comments): enable spell check in the comment composers by @hm21 in #7510
  • fix(analytics): gate view events on signer readiness by @hm21 in #7512
  • feat(settings): make light mode a user-selectable setting, not a feature flag by @rabble in #7523
  • fix(share): anchor every share sheet so iPad stops rejecting it by @hm21 in #7519
  • fix(notifications): render the feed before the mark-all write settles by @realmeylisdev in #7493
  • fix(video-feed-item): address three blocking issues in community warnings by @NotThatKindOfDrLiz in #7425
  • fix(search): rank by followers then video, keep follows boosted first by @rabble in #7513
  • fix(relay): Fix race condition in relay ledger loading during pre-init by @NotThatKindOfDrLiz in #7495
  • fix(zendesk): Synchronize SDK initialization with JWT identity upgrade by @NotThatKindOfDrLiz in #7517
  • fix(dm): unwind group sends on enqueue failure by @NotThatKindOfDrLiz in #7450
  • test(nostr_sdk): pin publish-denominator tracking when relay status lags the socket by @NotThatKindOfDrLiz in #7428
  • fix(follow_repository): follower count stabilization (#6764) by @NotThatKindOfDrLiz in #7449
  • fix(db): stop reporting downstream echoes of a handled DB corruption by @hm21 in #7518
  • feat(analytics): two-phase kind-22236 view reporting (start + end) by @rabble in #7243
  • fix(dm): handle the request preview's loading and error states by @realmeylisdev in #7443
  • fix(auth): normalize email before Keycast auth by @NotThatKindOfDrLiz in #7536
  • fix(video-editor): bump pro_video_editor to 2.11.3 for the cancelled-export crash by @hm21 in #7531
  • fix(support): avoid broken bare blob fallback by @NotThatKindOfDrLiz in #7538
  • fix(theming): default appearance to dark when unset by @NotThatKindOfDrLiz in #7556
  • fix(notifications): initialize local permission state by @NotThatKindOfDrLiz in #7561
  • fix(cache): clarify budget status in log exports by @NotThatKindOfDrLiz in #7569
  • fix(nostr): use raw timestamps for video replacements by @NotThatKindOfDrLiz in #7555
  • fix(profile): suppress repeated unauthorized thumbnails by @NotThatKindOfDrLiz in #7567
  • fix(notifications): mark inbox seen on visibility by @NotThatKindOfDrLiz in #7557
  • fix(analytics): name shell route surfaces by @NotThatKindOfDrLiz in #7563
  • chore(playback): lower handled media processing logs by @NotThatKindOfDrLiz in #7562
  • fix(discover): bound public list relay reads by @NotThatKindOfDrLiz in #7564
  • chore(playback): lower media-processing retry logs by @NotThatKindOfDrLiz in #7577
  • fix(notifications): show pending state for mark-all-as-read by @realmeylisdev in #7581
  • feat(post-publish): offer View and Share on the publish confirmation by @rabble in #7529
  • ci: route review requests with CODEOWNERS by @rabble in #7599
  • chore(agents): add opt-in guard for concurrent sessions in one worktree by @NotThatKindOfDrLiz in #7272
  • fix(bookmarks): decrypt NIP-04 private items instead of refusing them by @realmeylisdev in #7589
  • fix(theme): resolve brand green through accentPositive on light surfaces by @rabble in #7590
  • docs(bookmarks): say what the absence-confirmation TTL actually bounds by @realmeylisdev in #7592
  • fix(video): retry deep-link lookup when relays connect mid-fetch by @rabble in #7600
  • fix(nostr): distinguish zero-relay participation from an empty query result by @realmeylisdev in #7594
  • test(divine-ui): pin info card tone tokens by @NotThatKindOfDrLiz in #7609
  • test(divine_ui): refresh light accent assertions by @NotThatKindOfDrLiz in #7614
  • fix(auth): bound the NIP-46 callback relay handoff by @realmeylisdev in #7611
  • fix(bookmarks): serialize global bookmark syncs and publishes by @realmeylisdev in #7598
  • docs(architecture): clarify service god-file ceiling is a hard gate with no escape hatch by @NotThatKindOfDrLiz in #7613
  • test(nostr): pin that a failed auth-gated send still counts as participation by @realmeylisdev in #7593
  • refactor(ui): remove leftover ARB keys for deleted bookmark-set feature by @realmeylisdev in #7591
  • fix(bookmarks): tell the Saved tab's empty state from a failed load by @realmeylisdev in #7623
  • fix(analytics): handle partial creator stats failures by @NotThatKindOfDrLiz in #7615
  • test(authentication): add offline terminal-state regression test by @NotThatKindOfDrLiz in #7570
  • docs(branding): correct the claim that the icon plate is flat Brand Green by @realmeylisdev in #7644
  • fix(feed-tuning): stop macOS edge back-swipe from tuning by @NotThatKindOfDrLiz in #7622
  • fix(dm): Add deduplication logging to diagnose duplicate messages by @NotThatKindOfDrLiz in #7633
  • fix(support): stop expired oauth sessions leaking into key logins by @NotThatKindOfDrLiz in #7630
  • fix(comments): Resolve PR #6960 blockers for optimistic comment UI and relay echo timing by @NotThatKindOfDrLiz in #7662
  • feat(identity): show social proof instead of a truncated npub by @rabble in #7601
  • refactor(theming): tokenise video editor selected controls by @NotThatKindOfDrLiz in #7624
  • feat(storage): add a developer footprint diagnostic for unexplained disk usage by @hm21 in #7642
  • test(divine-ui): extend the a11y contract to app bar, sheets, and snackbars by @realmeylisdev in #7658
  • fix(bookmarks): stamp kind 10003 past the revision it replaces by @realmeylisdev in #7635
  • test(ui): restore golden coverage and gate it in CI by @realmeylisdev in #7657
  • test(video_metadata_update_service): add clip-source tag preservation test by @NotThatKindOfDrLiz in #7645
  • fix(comments): pin relay echo grace window and remove unreachable guard by @NotThatKindOfDrLiz in #7671
  • fix(dm): prevent NIP-04 cleartext leak on first message send by @NotThatKindOfDrLiz in #7664
  • fix(tools): refuse to guess when the dark-parity base has no merge base by @NotThatKindOfDrLiz in #7667
  • docs: verify caption edit revert fixes (#6474) by @NotThatKindOfDrLiz in #7575
  • fix(nostr): count an initial subscription's pre-EOSE events for pagination by @rabble in #7681
  • test(tools): hoist the duplicated git helper in the dark-parity tests by @NotThatKindOfDrLiz in #7686
  • chore(scripts): add a safe merged-branch prune report by @NotThatKindOfDrLiz in #7669
  • fix(auth): report password-reset outcomes accurately by @dcadenas in #7568
  • test(comments): assert pending replies keep options closed by @NotThatKindOfDrLiz in #7666
  • feat(explore): disclose paid partnerships on the featured tab by @NotThatKindOfDrLiz in #7676
  • test(nostr_sdk): cover closed relay settlement shapes by @NotThatKindOfDrLiz in #7698
  • fix(skills): stop routing divine-context PRs through a /tmp worktree by @rabble in #7660
  • feat(feed): say whether a failed feed is our outage or your network by @rabble in #7699
  • fix(profile): stop resolving fullscreen playback from a relay subscription by @rabble in #7689
  • test(l10n): register delegates on bare MaterialApp test roots and freeze the count by @realmeylisdev in #7703
  • refactor(profile): finish endpoint injection and fix NIP-98 URL canonicalization by @realmeylisdev in #7696

New Contributors

Full Changelog: 1.0.19...1.0.20