feat: Phase 3 recipes file, spotify_play, and locked-screen refusal
Phase 3 of AGENTS.md section 11.
Recipes file (FR-5)
- recipes/ holds one hand-editable file per task; recipes/spotify_play.recipe
is the first one.
- internal/recipe parses directives, guards, parameters and steps, and runs
them with a per-step and a whole-run timeout (FR-11).
- Steps name text ("tap the element whose text is Search"), never coordinates.
- guards name screens Artemis must never tap on, so a signed-out or
first-run Spotify fails with its own reason (FR-8).
- Every run appends task, params, steps, result and duration to
logs/runs.jsonl (FR-10).
spotify_play
- launch, search, play, then wait for the transport button to say "Pause".
- internal/ui/rows.go adds tap_row: a result row is a clickable container with
a title and a subtitle, so a one-line search suggestion is not a result, and
the tap lands on the row's centre rather than on its "More options" button.
This fixes a real wrong tap: a plain text tap hit a 126x12 pixel
"More options for song Honky Tonk Women - Live" button.
Locked screen (AGENTS.md section 13 Q2, decided)
- Artemis fails loudly on a secure keyguard and never types a PIN. No secret is
stored. A non-secure keyguard is still dismissed.
- internal/ui/keyguard.go reads the KeyguardServiceDelegate block plus
cmd lock_settings is-user-secure.
- Every acting command wakes the screen before it checks the keyguard: a dozing
phone reports showing=false, because the lock screen is not drawn yet.
- AGENTS.md records the decision and that storing a PIN for auto-unlock is
rejected for now.
Verified live: the phone locked itself mid-session, and keyguard, tap and
run spotify_play all refused with "phone is locked; unlock it and retry".
The live end-to-end playback run still needs an unlocked phone.
This commit is contained in:
63
recipes/spotify_play.recipe
Normal file
63
recipes/spotify_play.recipe
Normal file
@@ -0,0 +1,63 @@
|
||||
# spotify_play — search Spotify for a song and play it.
|
||||
#
|
||||
# Edit this file by hand. Steps name the text Artemis must find on screen; it
|
||||
# taps the centre of the element it matched. There are no coordinates here on
|
||||
# purpose, so this recipe survives a Spotify redesign (FR-4).
|
||||
#
|
||||
# Run it with:
|
||||
# artemis run spotify_play query="Rolling Stones Honky Tonk"
|
||||
|
||||
task: spotify_play
|
||||
description: Search Spotify for a song and play it.
|
||||
app: com.spotify.music
|
||||
|
||||
# The caller must supply these.
|
||||
param: query
|
||||
|
||||
# Spotify's list rows: title + subtitle inside one clickable container. Naming
|
||||
# the container keeps the tap on the row itself and off the row's buttons.
|
||||
row_id: com.spotify.music:id/row_root
|
||||
|
||||
step_timeout: 20s
|
||||
total_timeout: 150s
|
||||
|
||||
# Screens Artemis must never tap on. Each one fails the run with the reason, so
|
||||
# a wrong tap is impossible (FR-8).
|
||||
guard "Log in" => Spotify is signed out; sign in on the phone and retry
|
||||
guard "Sign up free" => Spotify is signed out; sign in on the phone and retry
|
||||
guard "Log in to Spotify" => Spotify is signed out; sign in on the phone and retry
|
||||
guard "Continue with Facebook" => Spotify is showing its welcome screen; sign in on the phone and retry
|
||||
guard "Continue with Google" => Spotify is showing its welcome screen; sign in on the phone and retry
|
||||
guard "Update Spotify" => Spotify wants an update; update it on the phone and retry
|
||||
guard "What's new" => Spotify is showing an announcement screen; dismiss it on the phone and retry
|
||||
|
||||
steps:
|
||||
# 1. Make sure Spotify is up. Launching an app that is already open is a
|
||||
# no-op, so this is safe to repeat.
|
||||
- launch
|
||||
- wait "Search" 30s
|
||||
|
||||
# 2. Open the search tab. Spotify remembers the last tab, so a search screen
|
||||
# with the previous query can come back: clear that box only when the
|
||||
# clear button is actually on screen.
|
||||
- tap "Search"
|
||||
- tap_if "Clear search query"
|
||||
- wait "What do you want to listen to?" 30s
|
||||
- tap "What do you want to listen to?"
|
||||
|
||||
# 3. Type the query. The clear button proves the text landed.
|
||||
- type "{query}"
|
||||
- wait "Clear search query" 30s
|
||||
|
||||
# 4. Wait for the results to replace the "Recents" list, so the next step can
|
||||
# never match something from the history instead of a search result.
|
||||
- wait_gone "Recents" 30s
|
||||
|
||||
# 5. Play the result that matches the query. tap_row scores every visible
|
||||
# result row against the query words and taps the best one; equal matches
|
||||
# go to the highest row, which is how Spotify ranks them.
|
||||
- tap_row "{query}" 40s
|
||||
|
||||
# 6. Playback started when the transport button says "Pause". Exact match, so
|
||||
# Spotify's "Paused" labels do not count.
|
||||
- wait exact "Pause" 40s
|
||||
Reference in New Issue
Block a user