Mission cards¶
A mission card tells the explorer who to be and what to try. Cards are JSON
files in collector/examples/missions/<app>/, one card (or a list of cards) per
file. <app> is the job's app_key.
{
"id": "explore-careless-typist",
"app": "bug-garden",
"title": "Fill every form badly",
"persona": "A careless typist in a hurry who never reads labels.",
"goal": "Add a plant and edit one, filling every field with awkward values: empty, very long, decimals in number fields, leading spaces. Save each time.",
"success": "Every invalid value gets a clear message and nothing crashes.",
"budget": { "steps": 60, "minutes": 20 },
"surfaces": ["touch"],
"screens": ["edit", "detail"],
"setup_flow": "bug-garden/sign-in.yaml"
}
Fields¶
| Field | Required | What it does |
|---|---|---|
id |
yes | Unique per app. Cards whose id starts with bench- are bench cards |
app |
Defaults to the directory name | |
title |
yes | Shown on findings and in the trajectory sheet |
persona |
yes | Who the model pretends to be, in a sentence |
goal |
yes | What to try, in a sentence or two |
success |
How the judge decides the goal held, read against the final screen. Without it there is no goal check | |
budget.steps |
Model steps, 3 to 300. Default 40 | |
budget.minutes |
Wall time. Default 30 | |
surfaces |
touch, dpad or both. A card is skipped on a device of the other kind |
|
screens |
Screen words this card tends to reach, matched against today's changes | |
allow |
Dangerous classes this card may touch: delete, purchase, invite, sign_out. See the leash |
|
block |
Extra patterns this card must not touch, as case-insensitive regular expressions over the control's label | |
setup_flow |
A Maestro flow, relative to the flows directory, run after reset to sign in | |
launch_args |
Launch arguments. See below | |
check |
A bench card's end state. See bench cards |
Writing a good card¶
- Give a reason to go somewhere. "Add a first plant" reaches the edit form, validation and the list; "use the app" reaches whatever the first screen links to.
- Make the persona do something specific. "A careless typist" types decimals into number fields; "a German speaker" changes the language first. Both find bugs a polite user would not.
- Name the screens.
screensis what lets a day's commit toPlantDetailScreen.ktmove this card to the front. - Say what success looks like in terms the final screen can show: "a plant named Basil is in the list", not "the plant is saved correctly".
- Keep budgets honest. 40 steps is about fifteen minutes at twenty seconds a step. A card that needs 100 steps is two cards.
Production data¶
A debug build that talks to a production backend must not be explored with write access. The GreenFolio Android debug build does, so its cards stay signed out and block anything that creates or sends:
The signed-in GreenFolio card is read-only by block, and runs only when the
job supplies credentials for a test account. Where an app has an offline or
fixture mode, prefer it: the GreenFolio iOS cards launch with
-UITesting -UITestingSignedOut -UITestingOffline, so the backend is never
reached at all.
Launch arguments¶
- iOS and tvOS: process arguments, passed straight through
(
["-uiTestStubCatalog"]). - Android: there are no process arguments, so each must be
key=valueand becomes a string intent extra (--es key value). Anything else is refused by name, so a card written for iOS fails loudly on Android instead of launching a different state of the app. - Conditions add their own: a language condition on iOS adds
-AppleLanguages (<tag>) -AppleLocale <locale>.
Setup flows¶
A setup flow is an ordinary Maestro flow. ${APP_ID} is always provided; any
other ${NAME} must come from the job's credentials:
"credentials": { "account": "showcase@example.com", "email_var": "GREENFOLIO_TEST_EMAIL", "password_var": "GREENFOLIO_TEST_PASSWORD" }
The password is read from the executor host's Keychain (service
fleet-ui-test, account as given) and never appears in a job spec. A flow that
carries its own test account, like the bug garden's, needs nothing.
Bench cards¶
A bench card has an id starting bench- and a check the harness can
evaluate without a model:
{
"id": "bench-delete-plant",
"title": "Delete Aloe Vera",
"persona": "Someone tidying up their list.",
"goal": "Delete the plant called Aloe Vera.",
"budget": { "steps": 12 },
"allow": ["delete"],
"launch_args": ["garden_defects=false"],
"check": { "screen": "home", "text": ["8 plants"], "absent_text": ["Aloe Vera"] }
}
check field |
Passes when |
|---|---|
text |
Every string appears in some element's text, label (content-desc) or value on the final screen. Case-insensitive substring |
absent_text |
None of these appears anywhere on the final screen |
focused_label |
The focused element's label contains it (TV cards) |
screen |
The final screen's name contains it |
Bench cards run only in bench mode (params.bench: true), unless missions
names them, and exploration cards only outside it. Bench missions run with no judge and file nothing; the number
that comes out is how many end states the model reached. See
Measuring a model.
The cards that exist¶
| Directory | Cards |
|---|---|
bug-garden/ |
7 exploration, 20 bench, all on the fixture app |
greenfolio/ |
3 Android: the sign-in gate, forgot password, a read-only signed-in tour |
greenfolio-ios/ |
2 iOS, offline: the sign-in gate, creating an account with no network |
dozehound-tv/ |
Android TV / Fire TV: 3 exploration, 10 bench |
dozehound-tvos/ |
tvOS: 1 exploration, 10 bench, end states taken from a hand walk on a tvOS 26.5 simulator |
fakeroku/ |
10 bench, for tvloop's fake Roku |