- run.sh: add a Buzz-style bare reaction check (kind-7 with an `e` tag but no `p` tag) asserting it still lands on the Reactions channel, and a note that Buzz DM isn't auto-triggered. - README: coverage row for the bare reaction, plus a "Buzz DM (manual)" section with the channel-setup steps (kind-39000 `t=dm` + participant, then post kind-9/40002) since participant-routing needs cached channel metadata. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0122uQ8BLHLeHDni81RBP26r
Notification end-to-end test (Layer 3)
Drives the whole push-notification pipeline on a real device/emulator: a second
identity publishes each notification kind through amy to the account logged
into the phone, and the script reads the system notification shade back over
adb to assert the right notification landed on the right channel — then tests
the two behaviors unit tests can't reach: cold-push metadata enrichment and
dismiss-on-read.
It's written to be run unattended by an agent: every check prints
PASS / WARN / FAIL, and the script exits non-zero if any hard assertion
fails.
What it covers
| Check | How it's triggered | Asserted from the shade |
|---|---|---|
| Mention (+ liveness) | amy event --kind 1 p-tagging A |
MentionsID + "mentioned you" |
| Reply | kind 1 with e+p tags to A's note |
RepliesID + "replied" |
| Reaction | kind 7 to A's note | ReactionsID + "reacted" |
| Buzz bare reaction | kind 7 with e tag, no p tag |
ReactionsID (routed via tagsAnEventByUser) |
| Repost (new kind) | kind 6 to A's note | RepostsID + "reposted" |
| Picture (new kind) | kind 20 with imeta + p |
MediaID + "shared a photo" |
| DM | amy dm send |
PrivateMessagesID + the body |
| Enrichment | cold-start, then publish sender kind:0 | title flips from raw pubkey → display name in place |
| Dismiss-on-read | deep-link the note, then re-check | notification gone |
Zaps (need a Lightning wallet), git/badge/nutzap/onchain (need repo / badge
definition / cashu proofs) aren't automated here — they follow the same
amy event --kind … pattern with the appropriate tags if you want to extend it.
Buzz DM (manual)
Buzz DM notifications (StreamMessageV2Event k40002 / ChatEvent k9 in a t=dm
relay-group channel) are participant-routed off the channel's kind-39000
metadata, so they can't be triggered in one amy event call. To verify by hand:
- Create a Buzz DM channel whose kind-39000 metadata has
["t","dm"]and a["p", <A_hex>]participant tag (use the Buzz UI, oramy relaygroup/amy event --kind 39000as the relay/group admin), on a relay A is connected to. Let A load the channel (open it once) so its 39000 metadata is cached — push only fires when the participant list is known. - As B, post a message into it:
amy event --kind 9 --content "buzz dm hi" --tags '[["h","<groupId>"]]' --relay <groupRelay>(or kind 40002). - Background the app; expect a
PrivateMessagesIDnotification titled with the channel name and bodyB: buzz dm hi, tapping it opens the chatroom.
The gate is intentionally strict (participant metadata must be loaded), matching the in-app feed — a cold push with no cached channel won't notify.
Prerequisites
-
A device/emulator on
adbwith the debug app installed and an account logged in — this is identity A, the receiver. -
amybuilt:./gradlew :cli:installDist(binary atcli/build/install/amy/bin/amy). -
jqonPATH. -
A relay both sides use. It must be in A's inbox/read relays and A's always-on notification service must be enabled, so events arrive while the app is backgrounded. For an emulator with a local relay:
amy serve --port 7777 & # embeds the geode relay adb reverse tcp:7777 tcp:7777 # phone's 127.0.0.1:7777 → host # then add ws://127.0.0.1:7777 to the account's relays in the app
Run
A_NPUB=npub1… RELAY=wss://relay.example ./tools/notification-e2e/run.sh
Reply/reaction/repost need a note authored by A on the relay; if A has none the script warns and skips those three — post one from the phone first for full coverage.
Knobs
| Env | Default | |
|---|---|---|
A_NPUB |
(required) | receiver npub (the phone's account) |
RELAY |
(required) | relay both sides use |
APP_PKG |
com.vitorpamplona.amethyst.debug |
app id |
ADB_SERIAL |
first device | adb -s target |
AMY |
cli/build/install/amy/bin/amy |
amy binary |
TIMEOUT |
40 |
seconds to wait for a notification |
IMG_URL |
a small public jpg | image for the media test |
Notes / limitations
- Verification greps
dumpsys notification --noredactfor the channel id and a content string; it doesn't bind them to the same record, so run it against a reasonably quiet device. - The dismiss-on-read step depends on the note deep-link format; if it can't
confirm the clear it
WARNs rather than failing, so eyeball it once. - It exercises the always-on relay delivery path (no FCM/UnifiedPush server needed). To test the real push transport, send through your push server and keep the rest of the flow identical.