arrow_backAll canvases
FullCircle · Requests inbox
Deciding whether to take a task
Variants and decision logs for the requests inbox — what a helper needs to see to say yes, and which actions belong on the row. Each set closes with a log of what we considered and how we got there. Earlier lifecycle screens live in Companion MVP — M3 Revision.
check_circleCurrent screens · build from these
The inbox as decided
Every decision made so far, applied: greeting header with the availability switch (8a), four tabs, no SOS in the inbox, Save · Decline · Accept inline on every row (5a), and saved requests reachable as a filter chip rather than a screen of their own (9b), plus the three network states the API build needs (10a–10c). These eight frames are the spec — the rounds below are the record of how we got here, and their older chrome is superseded, not current. Round 11 adds the location model the nearby query needs: home is the anchor, the chip always says so, and live location is a session-only override (11a–11e). Round 12 then bought the list its room back: 12c's 149dp four-line row and 12a's merged chip row are applied in 7a and 10a above — R11's own frames still show the taller pre-R12 chrome, since they were drawn to settle location, not density. 12b's collapsing top bar is the agreed next step, not built.
checkR5 · inline accept (5a)
checkR7 · chrome & empty states
checkR8 · availability switch (8a)
checkR9 · saved as a filter (9b)
checkR10 · loading & failure
checkR11 · location anchor (11a)
checkR12 · row density (12c)
pendingR12b · collapsing top bar
pendingR6 · declined-row undo
Available · verified
9:41battery_full
home_pinKondapur · 5 km
bookmark_border3
filter_list
swap_vert
timerExpires in 24 min
₹1,140
Hospital Visit
Today, 4:00 PM · 3 hrs
local_taxiApollo, Sector 22 · 4.2 km from home
bookmark_border
closeDecline
checkAccept
timerExpires in 2 hrs
₹918
Errand & Bank Visit
Tomorrow, 11:00 AM · 2 hrs
directions_carGachibowli · 2.1 km from home
bookmark_border
closeDecline
checkAccept
timerExpires in 3 hrs
₹760
Discharge Pickup
Tomorrow, 4:00 PM · 2 hrs
keyFortis, Sector 62 · 6.8 km from home
bookmark
closeDecline
checkAccept
timerExpires in 6 hrs
₹460
Medicine Pickup
Tomorrow, 9:00 AM · 1 hr
directions_walkKondapur · 1.4 km from home
bookmark_border
closeDecline
checkAccept
The screen as decided, at
12c density: 149dp rows, four content lines, transport as an inline mode icon, and the anchor leading a single scrolling chip row (
12a). Four rows visible where three used to be. Customer name and coverage moved to task detail; the 40dp action row is untouched.
Paused by choice
9:41battery_full
Requests near you
6 waiting
timerExpires in 24 min
Meera R. · Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22 · 4.2 km
local_taxiCab by customerBoth ways
timerExpires in 2 hrs
Anil N. · Aug 2, 11:00 AM · 2 hrs
Sector 14 · 2.1 km
directions_carYour 4-wheelerBoth ways
pause_circle
You're paused
6 requests waiting near you
Start receiving requests
One summary a day while you're paused.
Same locked-preview component as 7d — count badge, blurred rows, centred overlay — with the icon, title and action swapped. Blur isn't a tease here: if the rows were legible a paused helper could still cherry-pick, and pause would mean nothing. When the count is zero, the badge and blur block are both hidden and only the resume button remains.
Quiet · nothing nearby
9:41battery_full
Waiting for tasks
We'll notify you as soon as a new task becomes available in your area.
Your built screen, moved onto the Requests tab and stripped of its KYC subtitle. It now covers exactly one cause — quiet — because paused has its own screen and unverified has 7d.
Unverified · gated
10:13battery_full
Hi Mani 👋
You're almost ready to earn
Setup progress2 of 3 steps
check_circleProfile
check_circleSkills
errorKYC
Verify your identity to start earning
Aadhaar details + a quick selfie. Takes about 3 minutes.
START KYCarrow_forward
Requests near you
25 waiting
timerExpires in 3 hrs
Customer · Today, 4:00 PM · 3 hrs
Sector 22 · 2.1 km
local_taxiCab by customerBoth ways
timerExpires tomorrow
Customer · Tomorrow, 11:00 AM · 2 hrs
Sector 14 · 4.0 km
directions_carYour 4-wheelerBoth ways
timerExpires in 6 hrs
Customer · Today, 6:30 PM · 1 hr
Sector 9 · 1.4 km
directions_walkNo transport
lock
Complete KYC to unlock
25 requests waiting near you
Your built screen, with "Tasks" reading "Requests" and a four-tab nav. The blurred rows are now the real row — same timer, payout, meta and transport tags — so the shape doesn't change when it unlocks. Content is redacted at the source though: "Customer", sector only, no venue. An unverified device shouldn't hold names and addresses that a screenshot or a CSS toggle would expose.
Turning availability off
9:42battery_full
Meera R. · Jul 30, 9:00 AM · 3 hrs
Pause new requests?
You won't be shown new requests until you turn this back on.
event_available
Tasks you've already accepted go ahead as planned.
notifications
You'll still get one summary a day, so you don't miss a busy week.
Tapping the Available chip opens this sheet — pausing is indefinite, so it's worth one confirmation. It answers the question helpers actually have: no, this doesn't cancel what I've already taken. Resuming is the opposite: chip tap or the 7b button, applied immediately with a snackbar and no sheet.
First load
No spinner — ghost rows in the real 149dp row anatomy, so the list doesn't jump when data lands. Greeting and nav are real: the name and the availability switch are local state, not fetched, and blanking them would make the whole app look broken. The chip row is absent, not ghosted — nothing to filter yet, and the anchor chip would be claiming a place we haven't confirmed. Last rows fade to say the list continues.
Couldn't load · nothing cached
9:41signal_cellular_off
cloud_off
Can't reach FullCircle
We couldn't load requests just now. Check your connection and try again.
refreshTry again
event_available
Tasks you've already accepted are saved on this phone. Open Schedule
Header and nav survive — the failure is the list's, not the app's, and a helper must still be able to reach Schedule and Earnings. The line below the divider answers the question a helper actually panics about when this screen appears: the task I already took — is it gone? Nothing in the copy blames the helper's phone specifically; it could be us, and saying "check your internet" when our API is down is a small lie that costs trust. The availability switch dims because we can't push a state change we can't send.
Refresh failed · rows kept
10:07signal_cellular_off
cloud_off
Showing requests from 9:41 AM. Couldn't refresh.
RETRY
timerClosing in 8 min
₹1,140
Hospital Visit
Today, 4:00 PM · 3 hrs
local_taxiApollo, Sector 22 · 4.2 km from home
bookmark_border
closeDecline
checkAccept
scheduleNeeds a helper by 9:00 PM
₹1,320
Airport Drop
Tomorrow, 5:30 AM · 1 hr 15 min
local_taxiKondapur · 3.6 km from home
No connection — nothing was sent.
RETRY
Cached rows stay and stay legible — not dimmed, not blurred. The banner carries the doubt instead, and it states an as-of time rather than "offline", because the useful question isn't our connection status, it's how old this list is. Countdowns keep running: a deadline is an absolute instant, so the clock is still telling the truth even with no signal. What we can't vouch for is whether a row is still open — so Accept stays tappable and fails honestly. Chip row is hidden: filtering a stale list invites the helper to trust it.
Decision log · Round 10
Loading, and the three ways a fetch fails
Added because the API milestone needs them and the prototype never had a network. Three states, split by
what the helper has in hand — nothing yet (
10a), nothing at all (
10b), something stale (
10c).
Settled
· Skeleton, not spinner. Ghost rows in the real row anatomy mean the list doesn't reflow when data lands. A centred spinner tells the helper nothing about what's coming.
· Chrome never fails with the list. Greeting, switch and nav are local state; blanking them turns a failed request into an app that looks dead. Every failure state keeps a route out to Schedule and Earnings.
· Answer the accepted-task fear on the failure screen. A helper who can't load the inbox assumes the task they already took is gone too. 10b says it plainly and links to Schedule.
· Stale rows are kept and left legible. Dimming them punishes the helper for our network. The as-of-time banner carries the uncertainty instead.
· "Showing requests from 9:41 AM", not "You're offline". The helper's real question is how old this list is; connection status is our problem stated as theirs.
· Countdowns keep running offline. A deadline is an absolute instant — the client can honour it with no signal. Freezing the timer would invent a doubt that doesn't exist. This is why the API must send an instant and a band, never a pre-rendered "Closing in 8 min" string.
· Accept stays enabled offline and fails out loud. Nothing is queued. A snackbar says nothing was sent, because the one thing worse than a failed accept is a silent one that lands twenty minutes later on a task someone else already took.
· No filter or sort chips in any of the three. Nothing to filter, or a stale list you shouldn't be encouraged to trust.
Considered and dropped
· Greying out the stale rows. Reads as expired, which is a different and more final thing. Expiry already owns that treatment.
· Disabling Accept while offline. A dead primary button on every row makes the whole feed look broken, and a helper on a spotty connection often succeeds on the second tap.
· Queueing an offline accept. Tempting, and wrong — a promise we can't keep, on a race we'll usually lose.
· Auto-retry with no banner. Silent recovery is nice until it doesn't recover; then the helper is reading an hour-old list with no way to tell.
Open
· Staleness ceiling. At some age a cached list should stop being shown at all and fall back to 10b. An hour? A shift? Needs a number, and it should come from how fast requests actually turn over.
· Pull-to-refresh vs. the banner's RETRY. Both, probably — but if pull-to-refresh exists, the banner may not need its own action.
Decision log · Round 7
Sixteen calls, and what they cost
Settled
·
Four tabs, not three. Requests / Schedule / Earnings / Profile — the shipped app grows two tabs, and Help folds into Profile.
·
Greeting header on Requests only; Schedule, Earnings and Profile get plain M3 app bars. The subtitle disappears once verified — it exists to carry setup status, and there's nothing to say after that.
·
SOS is active-task only. It leaves the inbox entirely. A helper alone with a customer needs it; a helper reading a list does not, and a permanent red button trains people to stop seeing it.
·
Availability is a labelled switch in the greeting (8a, supersedes the chip), because that's where the consequence lands. Pause is indefinite, resume is a filled button, pause is a chip tap — the easy direction is back on.
·
Push keeps running while paused, softened and batched to one a day, and tapping one offers to resume. Without it an indefinite pause is a one-way door.
·
Empty is two states, not three. Quiet reuses your built screen; paused gets its own, because "we'll notify you" is false for someone who asked not to be.
·
KYC screens are done. Under review, failed, approved sheet and the setup-progress card all ship as built — Round 6's banner is deleted, not revised.
Decided without you, say the word to change
· Blur and count aren't alternatives — your screenshot ships both, so 7d keeps the blurred rows behind the lock and the "25 waiting" badge above them. The blur needs an accessible fallback in code: the rows must not reach a screen reader at all, or a helper on TalkBack hears three tasks they can't act on.
· 7b and 7d are one component. Count badge, blurred rows and centred overlay are shared; icon, title, sub-line and action are props. What must never merge is the meaning — lock is a gate the helper can't pass without three minutes of KYC, pause is a state they leave with one tap. If those two ever share a CTA, the paused screen starts reading as a penalty.
· Zero requests hides the count. "0 waiting" over a resume button argues against resuming — in 7b the badge and the blur block both drop out, leaving just the resume button.
· Sort folded into the filter chip row, since the app bar that held the sort icon no longer exists.
Availability, precisely
· Off: tap the Available chip → confirm sheet (7e) → chip turns grey "Paused", list is replaced by the locked preview, snackbar "You're paused" with Undo.
· On: tap the Paused chip, or the filled button in 7b. No sheet, no confirmation — applied immediately, list repopulates, snackbar "You're available".
· Asymmetric on purpose. The direction that costs the helper money gets a speed bump; the direction that earns it doesn't.
· Pausing never touches accepted work — that's stated in the sheet, because otherwise every helper assumes it does and pauses only when they have nothing on.
· The chip is the only control. No duplicate switch in Profile: two places to set one state means one of them is eventually wrong.
Now unresolved because of these answers
Two tabs have no screens. Schedule and Earnings were assumed by Rounds 4–6 and don't exist in the build — and "open but empty with a line explaining why" is only a holding answer for an unverified helper. There's also no home for Help now that the third tab is gone. Rounds 4–6 below still show the old app bar; their content stands, their chrome doesn't.
Round 12 · Room for the list · decided: 12c + 12a now, 12b next
The header grew. The row is the bigger problem.
On a 360×800dp phone the chrome above the list is ~165dp — status 24, greeting 52, anchor chip 45, filter row 43 — plus 60 for the nav, leaving ~575dp of list. One request row is ~193dp, so the helper sees 2.9 rows, and 2.6 when the widened-radius notice is up. Header trims alone buy a third of a row; the row is where the space is. Three candidates below, each with its measured cost. The frames are 620px crops, not 800dp phones — read the per-row numbers, not the number of rows you can see in the bezel.
12aOne chip row · anchor leads it
9:41battery_full
home_pinKondapur · 5 km
bookmark_border3
filter_list
swap_vert
timerExpires in 24 min
Meera R. · Today, 4:00 PM · 3 hrs
Apollo, Sector 22 · 4.2 km from home
local_taxiCab by customerBoth ways
bookmark_border
closeDecline
checkAccept
timerExpires in 2 hrs
Anil N. · Tomorrow, 11:00 AM · 2 hrs
Gachibowli · 2.1 km from home
directions_carYour 4-wheelerBoth ways
bookmark_border
closeDecline
checkAccept
timerExpires in 3 hrs
Kamala S. · Tomorrow, 4:00 PM · 2 hrs
Fortis, Sector 62 · 6.8 km from home
keyTheir car, you driveReturn only
bookmark_border
closeDecline
checkAccept
−45dpanchor folded into the chip row
−18dpgreeting 21→17px, switch 48→42px
row 193dpunchanged — the list still shows 2.9 rows, now 3.2
Cheapest to build and the weakest win. Four chips do not fit 360dp: Filter and Sort go icon-only, the anchor loses its chevron, and the row still scrolls (note the fade). So this costs three things at once — the anchor reads as a filter, which is what R11 was for; Filter/Sort lose their labels; and the radius is the first thing that will get dropped next time the label runs long.
12bCollapses on scroll · shown scrolled
9:41battery_full
Requests
home_pinNear home · Kondapur · 5 kmexpand_more
timerExpires in 24 min
Meera R. · Today, 4:00 PM · 3 hrs
Apollo, Sector 22 · 4.2 km from home
local_taxiCab by customerBoth ways
bookmark_border
closeDecline
checkAccept
timerExpires in 2 hrs
Anil N. · Tomorrow, 11:00 AM · 2 hrs
Gachibowli · 2.1 km from home
directions_carYour 4-wheelerBoth ways
bookmark_border
closeDecline
checkAccept
timerExpires in 3 hrs
Kamala S. · Tomorrow, 4:00 PM · 2 hrs
Fortis, Sector 62 · 6.8 km from home
keyTheir car, you driveReturn only
bookmark_border
closeDecline
checkAccept
−95dpgreeting and filter row both scroll away; anchor persists as the bar subtitle
row 193dpunchanged — 3.5 rows while scrolling, 2.9 at rest
costmost build; first screen unchanged
Standard M3 collapsing bar, and the only option that sacrifices nothing permanently — greeting and filters are still there at the top of the list, and all three filter chips keep their labels. The anchor survives the collapse as a subtitle, which is right: it's the one piece of chrome that must be readable at any scroll position. But the win arrives only after the helper scrolls, and the first screenful — the one that decides whether the app feels full or empty — is exactly as it is today.
12cFour-line row · recommended
9:41battery_full
home_pinKondapur · 5 km
bookmark_border3
filter_list
swap_vert
timerExpires in 24 min
₹1,140
Hospital Visit
Today, 4:00 PM · 3 hrs
local_taxiApollo, Sector 22 · 4.2 km from home
bookmark_border
closeDecline
checkAccept
timerExpires in 2 hrs
₹918
Errand & Bank Visit
Tomorrow, 11:00 AM · 2 hrs
directions_carGachibowli · 2.1 km from home
bookmark_border
closeDecline
checkAccept
timerExpires in 3 hrs
₹760
Discharge Pickup
Tomorrow, 4:00 PM · 2 hrs
keyFortis, Sector 62 · 6.8 km from home
bookmark_border
closeDecline
checkAccept
timerExpires in 6 hrs
₹460
Medicine Pickup
Tomorrow, 9:00 AM · 1 hr
directions_walkKondapur · 1.4 km from home
bookmark_border
closeDecline
checkAccept
−63dpheader: merged chip row + smaller greeting
row 149dpwas 193 — the two 24dp chips go, transport becomes a 14dp inline icon on the place line, and the customer name line goes with it
4.2 rowsvs 2.9 today, on a 360×800dp phone
Four content lines instead of six. The saving is real only because two lines leave rather than get rearranged: the transport and coverage chips collapse into an inline mode icon, and the customer name goes (it's on the detail screen, and the identity topic below already argues "Meera R." protects nobody). Coverage moves to detail too. The 40dp action row is untouched — that's a touch target, not decoration. Cost: no coverage on the row, and mode is an icon you have to learn. Settles R4, open since round 4.
recommendRecommendation
12c now, 12b next
Only 12c moves the number that matters — 2.9 rows to 4.2 — because only 12c removes content rather than repacking it. 12a's 45dp is the smallest win and the highest conceptual cost. 12b is the better long-term shell and should follow, but on its own the first screenful is unchanged.
Both 12a and 12c depend on the merged chip row, and it only fits 360dp with Filter and Sort icon-only. If that's unacceptable, the anchor keeps its own line and 12c still delivers 3.6 rows on the row change alone — which is the honest fallback.
What I'd not do: shrink the 40dp action row, drop Save from the row, or move Accept behind task detail. Reclaiming space by making the primary action harder to hit trades a real cost for a cosmetic one.
The widened-radius notice (
11b) costs another 50dp while it's up. With 12c it can stay persistent; without it, collapse it into the chip after first read.
Round 11 · Where "nearby" is measured from · decided: 11a
A task is an appointment, not a dispatch
The nearby query needs a reference point. Home address, live GPS and a helper-set working area were all on the table, plus five hybrids — and the call turns on one fact: rows carry a start instant hours or days out, so where the helper is standing right now is false precision. 11a is the V1 model: home as the anchor, always stated on screen, with an adaptive radius and a session-only live override. 11f–11h are what happens when the helper taps it. Note these frames predate 12c — the anchor behaviour here is current, the row and header density is not.
11aAnchored to home · default
9:41battery_full
home_pinNear home · Kondapur· 5 kmexpand_more
filter_listFilter
swap_vertSort
bookmark_borderSaved3
timerExpires in 24 min
Meera R. · Today, 4:00 PM · 3 hrs
Apollo, Sector 22 · 4.2 km from home
local_taxiCab by customerBoth ways
bookmark_border
closeDecline
checkAccept
timerExpires in 2 hrs
Anil N. · Tomorrow, 11:00 AM · 2 hrs
Gachibowli · 2.1 km from home
One outlined chip states the anchor and the radius in the same breath, because "nearby" is meaningless without both. It sits under the greeting, above the filter row — it's not a filter, it's the frame the whole list is drawn in. Distance is labelled from home, not bare "4.2 km", so a number can never quietly change meaning when the anchor does. No permission asked, nothing to configure, works on the first launch after KYC. Filter · Sort · Saved stay exactly where R7 put them — the anchor is a frame above them, not a replacement: filtering narrows what's in the list, the anchor decides what got into it.
11bThin pool · radius widened
9:41battery_full
home_pinNear home · Kondapur· 15 kmexpand_more
filter_listFilter
swap_vertSort
bookmark_borderSaved3
info
Nothing within 5 km right now, so we widened to 15 km.
timerExpires in 5 hrs
Sudha K. · Tomorrow, 10:30 AM · 2 hrs
Secunderabad · 11.4 km from home
two_wheelerYour 2-wheelerBoth ways
bookmark_border
closeDecline
checkAccept
Kamala S. · Sat, 5:30 AM · 1 hr 15 min
Shamshabad · 13.8 km from home
Widening is declared, never silent. Without the line, a 13.8 km task in a list promising "nearby" reads as a bug — and the helper's trust in every distance drops with it. The notice is neutral grey, not amber: a thin pool is information, not a warning, and it isn't the helper's fault. The chip's radius updates to match, so chip and rows can't disagree. Server returns the radius it actually used; the client never guesses. Filter and Sort still apply, but only within the widened pool — which is why the notice has to come before them.
11cAsking, at the moment of intent
9:41battery_full
Meera R. · Today, 4:00 PM · 3 hrs
Show tasks near where you are now?
Right now we're showing tasks near your home in Kondapur.
schedule
We check your location once, for this visit only.
visibility_off
Customers never see where you are. We don't track you between tasks.
Our sheet before the OS dialog, fired by the helper tapping the chip — never on launch, where a permission ask with no context is refused and then refused permanently. It answers the two things a helper on a gig platform is actually weighing: are you following me around, and can the customer see this. "Not now" is a real option with no penalty and no second ask this session; the inbox behind it already works.
11dCurrent location · this visit only
9:43battery_full
my_locationNear you · Ameerpet· 5 kmclose
Just for now — next time we'll show tasks near home again.
filter_listFilter
swap_vertSort
bookmark_borderSaved3
timerExpires in 40 min
Rafiq A. · Today, 12:30 PM · 1 hr
Ameerpet · 1.1 km from you · 14 km from home
directions_walkNo travel needed
bookmark_border
closeDecline
checkAccept
Vinod M. · Today, 2:00 PM · 45 min
Punjagutta · 2.4 km from you · 12 km from home
The one tonal-teal chip on the canvas that isn't a task status — justified because this is an active, temporary override the helper must be able to spot in a glance and cancel with the same tap that made it. Rows now carry both distances: the near one is why the task is here, the home one is the trip they still have to make at 12:30. Expiring at session end is deliberate — a persistent live anchor is a saved pin with none of the visibility. Filter · Sort · Saved are untouched by the override; Saved still counts the same 3 requests, wherever the helper is standing.
11eDenied · and empty at 30 km
9:44battery_full
home_pinNear home · Kondapur· 30 kmexpand_more
inbox
No open requests near home
We looked as far as 30 km from Kondapur. New requests usually come in through the morning.
notifications_activeNotify me
edit_location_alt
Working somewhere else today? Set a different area
Location is off — showing tasks near home.
SETTINGS
Denial is a snackbar, not a wall — it states the anchor we fell back to and offers Settings once, then never nags. The empty state names the radius it exhausted, so "no requests" reads as a true fact about the city and not a suspicion about the app. Chips are absent here for R10's reason — an empty list has nothing to filter, and Saved is reachable from the nav. Two escapes, both honest: wait (notify) or move the anchor. That second link is where a saved area would earn its way in — asked for at the moment the helper feels the need, instead of a settings screen built on a guess.
11fTapping the chip · the anchor sheet
9:41battery_full
Meera R. · Today, 4:00 PM · 3 hrs
Where should we look for tasks?
radio_button_checked
Near my home
Kondapur · from your profile
radio_button_unchecked
Near where I am now
Checks your location once, for this visit
adjust
We start at 5 km and widen on our own if there's nothing close by.
Change my home address
Two choices, and the selection applies on tap and closes — no Done button to confirm a decision that's one tap to undo. Radius is stated, not offered: a manual radius slider makes the helper responsible for tuning a pool they can't see, and the adaptive ladder already does it better. The home-address link is the only way out to profile — it's the one thing here that should live in settings, because it's a KYC fact, not a preference.
11gSame sheet · permission blocked
9:44battery_full
Meera R. · Today, 4:00 PM · 3 hrs
Where should we look for tasks?
radio_button_checked
Near my home
Kondapur · from your profile
radio_button_unchecked
Near where I am now
Location is turned off for FullCircle
SETTINGS
adjust
We start at 5 km and widen on our own if there's nothing close by.
Change my home address
The blocked option stays visible and disabled rather than disappearing — a row that vanishes teaches the helper the feature doesn't exist, and they never find it again after fixing the setting. It states the reason in the row and puts SETTINGS next to it, which is the only place the deep link belongs. Tapping the row itself does nothing; we can't re-prompt after a hard denial, and a dialog that pretends otherwise is a dead end.
11hTapping the X · back to home
9:46battery_full
home_pinNear home · Kondapur· 5 kmexpand_more
filter_listFilter
swap_vertSort
bookmark_borderSaved3
Back to tasks near home.
UNDO
The X is the only tap that changes the anchor without the sheet — it's a dismissal of a temporary state, so making it cost two taps would be worse than the mistake it prevents. The list re-fetches, so rows go to skeleton rather than to stale distances measured from a place we've stopped using. UNDO exists because the tap is small and sits next to the chevron; it re-applies the same fix with no second permission ask.
Decision log · Round 11
Where "nearby" is measured from
The backend needs a reference point for the nearby query. Three candidates were on the table — home address, live GPS, helper-set working area — plus five hybrids. The call turns on one fact about this product: a FullCircle task is an appointment, not a dispatch. Rows carry a start instant hours or days out. So the question is never "what's near the helper's body right now", it's "can they get there at task time, from where their day starts and ends" — which is home. GPS precision here is false precision.
Settled
·
Option A is the V1 model — home address as the anchor. No permission, no settings surface, works on first launch, works offline, already implemented server-side. It also measures the trip the helper actually makes.
·
Adaptive radius on top, 5 → 15 → 30 km, and it says so (11b). Silent widening is worse than an empty list: one 28 km row in a "nearby" feed devalues every distance on the screen.
·
The anchor is always visible (11a). Anchor and radius in one chip, under the greeting, above the filter row. This is the difference between a list a helper can reason about and a mystery list.
·
Distances are labelled with their origin — "4.2 km from home", not "4.2 km". A bare number silently changes meaning the moment the anchor does.
·
Live location is a one-tap, session-only override (11d), in the inbox header, never in settings. One fix per load. No polling, no background permission, no battery story.
·
Permission is asked at the moment of intent (11c), in our sheet first, and it answers the gig-worker questions: are you tracking me, can the customer see this. A launch-time ask gets denied once and denied forever.
·
Denial is a non-event (11e). Snackbar, fall back to home, offer Settings once, never nag. The inbox was already working before the tap.
·
The override reverts at session end. A live anchor that persists is a saved pin with none of the visibility — and the failure mode of a stale pin is that it looks exactly like a correct one.
·
The chip body always opens one sheet (11f), in every state. Two radio options, applied on tap, no confirm. Blocked options stay visible and disabled (
11g) rather than vanishing.
·
The X on the live chip is a one-tap revert (11h), no sheet, with UNDO. Changing the anchor always re-fetches — never re-labels the rows that are already on screen.
·
Radius is stated in the sheet, never adjustable. A slider hands the helper a tuning problem they have no data to solve.
·
Offline, the sheet still opens but switching fails out loud — the same snackbar as an offline Accept (R10), and the anchor stays where it was. Consistent with everything else on this screen: we never pretend a change landed.
·
Missing home = empty state routing to profile, not a city-wide query. If KYC is incomplete there is no anchor, and guessing one produces a list that's confidently wrong.
Considered and dropped
· B as primary (live GPS every load). Buys accuracy we don't need for appointments, and pays for it in permission friction on the one screen that must work on day one. Kept as the opt-in override instead.
· C as primary (saved working area). A settings screen we don't have, that helpers must remember to maintain, whose staleness is invisible. Revisit when data shows a real population working far from home — the entry point is already seeded in 11e.
· Multiple saved zones. Right pattern, wrong stage — it's a power-user tool for a product with no evidence of power users yet. Ship one anchor, learn how often it's wrong.
· Shift-start declaration. Presumes an Online/shift concept strong enough to justify a blocking question. Our availability switch is a quiet preference, not a clock-in. Promote this only if that switch becomes central.
· Demand or earnings clustering as the primary filter. "Nearby" is the promise; payout is a sort within the nearby set. A high-paying row 40 km away wins one tap and loses the helper.
· Continuous location polling. Nothing on this screen changes minute to minute. The battery cost would be entirely spent on precision the task times don't use.
What the API owes the client
· Request may send anchor {lat, lng, source: home | device}. No coordinates means home — the existing fallback stands.
· Response must echo the anchor and radius actually used, with a display label ("Kondapur"). The chip renders what the server did, never what the client asked for — otherwise 11b's chip and rows can disagree.
· Per task, distance_from_anchor_km, named for its origin so no one later mistakes straight-line for road distance. When the override is on, send home distance too — 11d shows both.
· Eligibility filtering and PII redaction stay server-side (per R10) — a widened radius must not widen what's disclosed.
Open
· The radius ladder is a guess. 5/15/30 km fits Hyderabad-scale travel; the widening trigger ("thin pool") needs a number — fewer than 3 open rows? Tune once there's density data.
· Does the ladder cap at 30 km, or at travel time? 30 km across the city and 30 km down a highway are not the same trip, and the helper is the one who eats the difference.
· Should accepting a far task offer to move the anchor? The cheapest possible path to Option C, driven by behaviour instead of a settings screen.
· Instrument the gap. Log anchor source per session and distance-from-home on accepted tasks. If the override gets heavy use, C stops being a guess.
visibility_offOpen topic · not yet decided
Customer identity on the request row
Current rows read "Meera R." — which is the worst of both options: it pays the full cost of disclosure and buys almost none of the protection. Below: why the name is the wrong field to argue about, what should occupy that line instead, and what gets disclosed when. Nothing applied to the current screens.
"Meera R." protects nobody
In India the given name carries most of the religion, region and often caste signal. The surname initial removes the least informative half.
So the honest positions are only two: show the full name, or show no name at all. The initialled middle ground is a comfort measure for us, not a protection for her.
Same applies to a photo and to "Apollo, Sector 22" as a pickup — a hospital plus a first name is identifying in a small locality.
The reason is bias, not privacy
Name + hospital + payout is enough to sort customers by identity. This is invisible in our metrics — you cannot see it in accept rates without already knowing the attribute being acted on.
group_offDocumented in ride-hailing on exactly this pattern: visible identity before the accept decision.
shieldStructural fixes work because they don't depend on anyone behaving well. Withholding identity from the decision is one of the few available.
Worth stating plainly: we cannot audit this after the fact, so the design has to prevent it rather than detect it.
29 of 30 never serve her
Every helper in radius currently sees a named person, a hospital and a date. That is health information about an identified individual, disclosed to strangers with no relationship, no agreement and no audit trail.
The person exposed often isn't the person who agreed. An adult child books for a parent who never saw our consent screen.
Disclosure scales with radius: widening the search to fill a task multiplies the exposure of the customer least likely to be served well.
Proposed principle
Disclosure follows relationship, not funnel stage.
The pre-accept value of a name is really "I know Kamala, I've driven her to Fortis three times". That value needs the relationship, not the name — so give the name to helpers who already have one, and withhold it from those who don't.
Served her before
full name, prominent
Side benefit: repeat matching stops being an invisible side effect and becomes a feature the helper can see and value.
Staged, not one gate
Browsing
Who they'll assist and what help is needed. No name, no photo, no street address. Area and landmark only.
On accept
First name. Enough to speak about the person; not enough to look them up.
T-2 hrs, or "Start travel"
Full name, exact address, masked call. The helper must have all of this before arriving or they can't find the building or identify her to staff.
Hole: accept-then-cancel harvests the name for free. The gate is only real if cancelling after accept costs something.
The address, not the name
We've been debating the least dangerous field. A destination landmark is fine to publish. The pickup address is the home of an elderly person who often lives alone.
Distance & sector
browsing
Destination landmark
browsing
Street / building
on accept
Flat no. & door instructions
on start travel
Gate this harder than the name. It's the field with a physical consequence.
Deliberately asymmetric
Withholding should not be even-handed. The helper is the person entering someone's home, so the customer sees more, earlier.
Customer sees helper
name, photo, KYC, on assignment
Helper sees customer
staged, as above
This is also the easier story to defend publicly, in both directions.
A cheap way to find out
Withhold names for new customers and watch accept rate and time-to-fill.
If nothing moves, names were never decision-useful — which settles the argument. If accepts fall, the interesting question is which requests stopped being accepted, and that answer is worth having either way.
MVP scale makes this cheap now and expensive later, once helpers have formed habits around seeing names.
Candidate row treatments
The name currently occupies the row's most valuable line while saying nothing about whether the helper can do the job. What replaces it is the real design question.
y0Today · for comparison
Meera R. · Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22 · 4.2 km
A name that enables sorting by identity, sat next to a hospital and a date. Nothing here helps the helper judge the work.
y1No name · assistance instead
Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22 · 4.2 km
accessibleWoman, 74 · uses a walker
The line now carries something that changes the decision. Mobility needs tell a helper whether they can actually do this; a name never did. Open: age and gender are still identity — but they're operationally necessary in a way a name isn't.
y2Repeat customer · name shown
Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22 · 4.2 km
historyKamala Sundaram · your 4th task together
Nothing left to protect, so the name goes in full and gets emphasis. This is the row that should win the helper's attention — and it makes continuity a visible feature.
y3Initials only · rejected
M. R. · Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22 · 4.2 km
Included to name the trap. It reads as anonymised while a single initial plus locality often isn't, and it gives the helper nothing usable. Worse than either honest position.
y4After accept · partial
person
Meera
Woman, 74 · uses a walker
location_onSector 22 · exact address at 7:00 AM
callCalling opens 2 hrs before start
First name on accept; address and contact still pending, with the time stated so it doesn't feel withheld arbitrarily. Saying when is what makes staging tolerable.
y5On start travel · full
person
Meera Raghavan
Woman, 74 · uses a walker
call
location_onB-402, Green Meadows
Sector 22 · gate code 4471 · lift on the left
Calls are masked. Her number is never shown.
Everything needed to arrive and identify her, and not before. Masking the number is the one piece that should persist permanently — it's what keeps contact from outliving the task.
Still open
·
Is age + gender just identity by another route? y1 replaces a name with "Woman, 74". That enables a different sort — helpers preferring easier customers — but unlike a name it's operationally necessary. Possible mitigation: describe the
assistance ("needs support walking") and leave age out.
·
Accept-then-cancel harvesting. Staged disclosure is only real if cancelling after accept has a cost. That interacts with
5a inline accept, which deliberately makes accepting cheap.
·
Does the customer get to choose? Some will happily be named; some would rather not be listed at all. A per-booking visibility setting is honest but adds a decision to a booking flow we want short.
·
Repeat detection across bookers. A daughter books for her mother from her own account. Continuity should key on the
person assisted, not the account — otherwise
y2 misses genuine repeats.
·
Ops and support see everything. Whatever we withhold from helpers is visible internally. That needs its own access rule, or the protection is cosmetic.
·
Does withholding read as distrust? Helpers may hear "we don't trust you". Framing matters: the same rule applied to their own data, stated plainly, is the difference between a protection and an insult.
scheduleOpen topic · not yet decided
Request expiry
The current rows all say "Expires in…", which quietly assumes one clock, one rule and one visual treatment. There are three clocks, the rule is lead time rather than task type, and only one band of tasks should show a countdown at all. Notes and candidate treatments below — nothing here is applied to the current screens yet.
Three clocks, currently one label
1
Offer expiry
This helper's chance to accept. Ends the instant another helper accepts — competition, not time, usually closes it.
2
Fulfilment deadline
Last moment anyone can be assigned and still arrive: start − travel − prep. This is what our rows are actually showing.
3
Customer patience
When we must admit we failed — early enough that they can still arrange something else. Ops-facing, never on the helper's row.
The helper only ever needs #2. Conflating it with #1 is why "Expires in 24 min" is ambiguous today.
Lead time drives it, not type
deadline = start − travel − prep
Falls out of the booking. A hospital visit next Tuesday and a discharge pickup in 90 minutes are the same type with nothing in common.
Type modifies two inputs
keyPrep burden. Customer's-car tasks need licence and insurance checks plus a vehicle handover — a longer minimum lead time than a cab errand.
priority_highCriticality. A missed appointment can't be rescheduled; a bank errand can. This changes how hard we escalate — not when the task dies.
So: one derived deadline per task. No per-type constant to maintain.
Only one band wants a countdown
Booked days ahead
Show the date. A 26-hour countdown is noise, and the offer stays open until filled.
Same day, hours out
A timer earns its place here. This is the only band it should appear in.
Needed now
Arguably not a browsable row at all — a sequential offer or a push race, so it isn't left to whoever happens to open the app.
If every row ticks, helpers learn to ignore ticking — and the signal is gone exactly when it matters.
Expiry is the last rung
The person waiting is usually elderly with a fixed appointment. Letting a task quietly expire is a slow failure.
Widen the radius
Cheapest fix. Nobody is told anything yet.
Raise the rate
Visible on the row — a reason to look again.
Hand to ops
A human calls known helpers directly.
Tell the customer
While they can still act — not at the deadline.
Ladder timings are relative to the deadline, so an urgent task climbs it in minutes and a scheduled one over days.
Candidate row treatments
One deadline line per row, four states. Colour only enters at the point a helper can still do something about it.
x1Booked ahead · no timer
eventTue, Aug 18 · 9:00 AM
Meera R. · 3 hrs
Apollo, Sector 22 · 4.2 km
Open until a helper accepts
Date replaces the countdown entirely. The quiet closing line tells the helper there's no rush without inventing a number.
x2Same day · calm
scheduleNeeds a helper by 3:20 PM
Anil N. · Today, 4:00 PM · 2 hrs
Sector 14 · 2.1 km
A clock time, not a countdown — it doesn't move while the helper reads, and it's checkable against their own day. Neutral grey: still hours of slack.
x3Closing soon · escalated
timerClosing in 42 min
Kamala S. · Today, 4:00 PM · 2 hrs
Fortis, Sector 62 · 6.8 km
trending_upRate raised ₹120 — still unfilled
Second rung of the ladder made visible. The raise is the honest reason to look again, and it says why — a bare higher number reads as arbitrary pricing.
x4Last call
timerClosing in 8 min
Sundar V. · Today, 2:15 PM · 3 hrs
Max, Sector 19 · 3.1 km
Appointment can't be moved. Leave within 20 minutes.
The only state that gets red, and the only one that states the physical commitment. Tension: this urgency plus 5a's inline accept is exactly the combination that produces regret-cancellations — this row may need to force the detail view.
x5Expired in place
historyNo longer available
Anil N. · Today, 11:00 AM · 2 hrs
This doesn't affect your rating.
Goes inert where it sits and clears on next refresh. Rows vanishing under a moving thumb is how helpers tap the wrong task — and the rating line matters because missing one looks like a penalty.
Thresholds, first pass
Over 6 hrs of slack
date only
6 hrs → 1 hr
grey clock time
Under 1 hr
amber countdown
Under 15 min
red countdown
Numbers are a starting point, not research. The shape is what matters: three quarters of rows show no countdown, so the ones that do are believed.
Still open
· Sort conflict. Default sort is "Best rate first", so urgent-but-cheap tasks sit at the bottom and starve. Either urgency becomes a sort option, or closing rows get pinned above the sort — pinning is a stronger lever and a bigger intrusion.
· Low-supply demoralisation. Where thirty helpers see a request, competition closes it long before any deadline. Countdowns therefore only really bite in thin markets — where watching one tick out teaches the helper that nobody wants it, them included. Possible answer: no countdown at all when the helper is one of very few eligible, and route those tasks through ops instead.
· Does the helper see the raise history? Showing "raised ₹120" invites waiting for the next raise. Showing nothing wastes the strongest signal we have. Leaning towards showing it only once, on the final rung.
· Saved tasks that expire. A helper who saved a request needs to be told it's gone — otherwise Saved becomes a list of dead links.
· Prep time is a guess until we measure it. Travel we can compute; licence checks and vehicle handovers we can't, so the first version of the deadline will be wrong for customer's-car tasks specifically.
Exploration record · newest first
Kept for the reasoning, not the pixels. Where a round's chrome differs from the current screens above, the current screens win.
Round 9 · Where saved requests live · decided: 9b
The bookmark had no destination
Every row carried a Save button and nothing in the app could reach the result — no tab, no list, no filter. Four options were on the table; 9b is built into the current screens above. The others are recorded here because the case for cutting Save entirely is strong enough to revisit after launch.
9aCut Save · not taken
Two actions, full width
For: requests are perishable — most saved items are gone within minutes, so the list is mostly disappointments. Frees the third action slot, which 5a made tight at 258px.
Against: the calendar-check case is real. A helper with a 2 PM task can't judge a 4 PM request without looking, and with nowhere to park it they just decline.
Still the fallback: if Save is used on under ~10% of rows post-launch, cut the button and give Decline/Accept the width.
9bFilter chip · chosen & built
9:41battery_full
filter_listFilter
swap_vertSort
bookmarkSaved3
timerClosing in 42 min
Today, 4:00 PM · 2 hrs
Fortis, Sector 62 · 6.8 km
bookmark
closeDecline
checkAccept
scheduleNeeds a helper by 3:20 PM
Today, 4:00 PM · 2 hrs
Sector 14 · 2.1 km
historyTaken by another helper
Aug 16, 9:00 AM · 3 hrs
Doesn't affect your rating.
You can shortlist up to 5 requests
No new navigation, and the row component is reused untouched — so countdowns, rate raises and Accept stay live by construction rather than by remembering to sync a second screen. Sort collapses to "Sort" to make room for three chips — applied to the current screens above, with flex:none on all three so a longer label can never silently wrap.
9cSection in Schedule · not taken
9:41battery_full
SAVED · 3
Not yours yet · closing in 42 min
CONFIRMED · TODAY
errorWhy it lost: "might do" sits one row above "doing". Mistaking the two ends with a customer waiting at a hospital — the single worst failure in this product.
Schedule genuinely owns dated things, and the section labels do try to separate them. Not worth the risk: no label reliably beats proximity when someone is scanning at 8 AM.
9dFifth tab · not taken
Saved as its own tab
inboxRequests
bookmarkSaved
eventSchedule
paymentsEarnings
personProfile
For: unmissable, and a count badge sits naturally on a tab.
Against: five tabs at 290px crushes the labels, and it spends permanent global navigation on a feature used for thirty seconds at a time. A tab that's usually empty teaches helpers to stop tapping it.
Also duplicates row state into a second screen — two places to keep countdowns and rate raises correct.
Rejected on navigation cost, not on the idea. If Save turns out to be heavily used, this is the upgrade path from 9b.
check_circleBuilt · 9b rules
What Save now means
"Shortlist while I check my calendar" — not a durable collection. The icon stays a bookmark; the behaviour is a shortlist.
Entry point
3rd filter chip
Dead items
inert in place (x5)
Notification
1 batched/day max
First-save toast
until Saved opened (9f)
Never one push per expiry — a helper who shortlisted four requests would get four notifications telling them they lost. Batched, once, plainly: "2 saved requests are no longer available."
Ties into
Request expiry: the saved-item death states are the same treatments as x5, so decide them together.
9eBookmark states · built
Two states, one silhouette
bookmark_border
Not saved
bookmark_border · neutral outline
bookmark
Saved
bookmark filled · tonal teal
Two states only — no transient flash. bookmark_added and bookmark_remove were tried and dropped: they made one tap show three glyphs inside a second, and the thumb covers the button for most of it. The only frame the helper reliably sees is the last one, so the intermediate tick just briefly misstates what happened.
The container is the feedback. Outline-on-white → filled-teal-on-tonal changes background, border, glyph weight and colour at once — a larger delta than most M3 toggles. A 150ms colour crossfade is enough; nothing swaps glyph shape.
And the tick stays unique. Accept owns the only checkmark on the row, 8px away. Two ticks meaning different things was the real risk.
Font axis fixed. The symbol font was pinned at FILL 0, so every .fill icon in the file — active tabs, KYC ticks, the call button — was silently rendering outline. Now loaded as 0..1.
The filled state
is the confirmation, and it sits under the thumb — better placed than a snackbar.
Open: it confirms "saved" but not "findable under that chip", which a first-time saver has no reason to connect. That's a one-time discovery problem, answered by the retiring toast in
9f rather than permanent chrome.
9fFirst-save toast · built
9:41battery_full
filter_listFilter
swap_vertSort
bookmarkSaved1
scheduleNeeds a helper by 3:20 PM
Today, 4:00 PM · 2 hrs
Sector 14 · 2.1 km
bookmark
closeDecline
checkAccept
eventTue, Aug 18 · 9:00 AM
3 hrs · Apollo, Sector 22
Saved. Find it under Saved above.
View
Sits above the nav bar, never over the row just saved — the helper needs to see the button they pressed turn teal at the same time.
check_circleToast rules
It teaches, then stops
The filled button already confirms the save. The toast's only job is naming the destination — so once the helper has opened the Saved filter, it has nothing left to say.
Retires after
1st Saved-filter open
Duration
2.5s, dismissable
Rapid saves
replaces, never stacks
Why not every time. A helper shortlisting three requests in a row would get three toasts telling them something they already know, each one covering the list they're reading.
Open: the cap message (5 of 5) is a different, non-retiring toast — it's a refusal, not a hint, and has to appear every time.
Saved · empty & capped
Nothing shortlisted
bookmark_border
Nothing shortlisted
Tap the bookmark on a request to hold it while you check your day.
At the cap
info5 of 5 shortlisted. Remove one to add another.
Revisit trigger
Save appears on fewer than ~10% of viewed rows → drop to
9a. Saved rows convert to accepts at a materially higher rate than unsaved → consider
9d.
The empty state has to explain the job, not just the absence — "shortlisted" is a word helpers won't have met yet.
Round 8 · Availability as a switch · decided: 8a
Three places a toggle can live
The chip had one real flaw: it sits 8px above a row of actual filter chips, so it reads as a filter, not a control. A switch fixes the affordance — the question is only where it goes and whether the state word survives. All three keep the confirm sheet on the off direction and instant on the on direction.
8aSwitch in the greeting · chosen
9:41battery_full
filter_listFilter
swap_vertSort
bookmark_borderSaved3
timerExpires in 24 min
Meera R. · Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22 · 4.2 km
bookmark_border
closeDecline
checkAccept
timerExpires in 2 hrs
Anil N. · Aug 2, 11:00 AM · 2 hrs
Sector 14 · 2.1 km
Cheapest swap — same slot, zero vertical cost, and the label keeps the state readable in words. Off state reads grey "Paused" with the thumb left. Risk: at 48px the switch competes with "Hi Mani" for the eye, and the label has no room to explain what availability affects.
8bIts own row · not taken
9:41battery_full
Taking requests
Within 10 km of Sector 22
filter_listFilter
swap_vertSort
bookmark_borderSaved3
timerExpires in 24 min
Meera R. · Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22 · 4.2 km
bookmark_border
closeDecline
checkAccept
timerExpires in 2 hrs
Anil N. · Aug 2, 11:00 AM · 2 hrs
Sector 14 · 2.1 km
A standard M3 outlined row: label, supporting line, switch — the whole card is the target, so it's the only version that clears 44px comfortably. The supporting line earns the extra 54px by answering "requests from where?", which the chip never could, and it's the natural home for the radius setting later.
8cToggle in Profile, status in inbox
9:41battery_full
person
Mani Kandan
Verified helper · Sector 22
WORK PREFERENCES
Taking requests
Within 10 km of Sector 22
Task types you accept
chevron_right
Transport & vehicle
chevron_right
Notifications
chevron_right
HOW THE INBOX SHOWS IT
Chip becomes read-only status. Tapping it jumps here.
Availability sits with the other preferences it belongs to, and the inbox keeps a clean read-only status chip. Costs two taps and a tab change to pause — acceptable for a weekly action, wrong if helpers pause reactively between tasks.
Switch states · off & pending
On
Taking requests
Within 10 km of Sector 22
Off
Taking requests
Paused since Aug 1 · 6 waiting nearby
Not yet verified
Taking requests
Available once your KYC is approved
Why the switch beats the chip
· Affordance. A pill 8px above a filter chip row looks like a filter. A switch never does.
· Bidirectionality. A chip shows state; a switch shows state and that you can change it, in both directions.
· Off is now visible. The paused chip relied on grey to mean "tap me"; a left thumb is unambiguous.
What doesn't change
Off still opens the confirm sheet (
7e) and the switch animates only after Pause is confirmed — never optimistically, or a cancel leaves the thumb lying. On applies instantly with a snackbar. Accepted tasks are untouched either way.
Disabled-until-verified matters: it replaces
7d's silence about why the helper can't work with a one-line reason in the control itself.
Round 6 · When the row isn't a happy path
Empty, lost, blocked, expired
The four states a helper hits in week one. All stock M3: full-width tonal containers for status, standard list rows, one filled button per screen, no new colour beyond the palette.
6a · Empty — new helper
9:41battery_full
inbox
No requests yet
You'll get a notification the moment a task near Sector 9 matches your services. Most helpers see their first request within 3 days.
Adding more services and a wider work area gets you more requests.
Review my services
Names the area we're matching against and sets a real expectation, so silence doesn't read as a broken app. The action is the one thing that actually changes their volume.
6a² · Empty — other two reasons
Same layout, different cause
One empty screen with three copy sets. Cause is known server-side, so we never guess.
pause_circle
You're not taking work
Requests are paused since Aug 1. Turn availability back on to start receiving them.
Turn on availability
schedule
Nothing right now
You've completed 13 tasks. Requests in your area are busiest 8–11 AM on weekdays.
See saved requests
The paused case is the only one that gets warning amber — it's the only one the helper caused and can undo instantly.
An experienced helper with an empty inbox needs different reassurance from a new one. Generic "No requests" serves neither.
6b · Taken by another helper
9:44battery_full
person_checkAnother helper took this task
Accepted 40 seconds ago. Nothing to do — this doesn't affect your rating.
Jul 30, 9:00 AM · 3 hrs · Apollo, Sector 22
timerExpires in 2 hrs
Anil N. · Aug 2, 11:00 AM · 2 hrs
Sector 14 · ~9 min away
directions_carYour 4-wheelerBoth ways
notifications_activeAlert me faster
Notify for hospital visits in Sector 22
chevron_right
Neutral grey, not error red — the helper did nothing wrong, and saying so explicitly protects the relationship. The old task dims in place rather than vanishing, and the screen pivots straight to what's still open.
6c · KYC incomplete
9:41battery_full
badgeFinish verification to accept tasks
Aadhaar and address are done. Police verification is pending — usually 2 working days.
Check verification status
You can browse what's coming. Accepting unlocks once verification clears.
timerExpires in 24 min
Meera R. · Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22 · ~22 min away
bookmark_border
lockAccept locked
timerExpires in 2 hrs
Anil N. · Aug 2, 11:00 AM · 2 hrs
Sector 14 · ~9 min away
bookmark_border
lockAccept locked
The block sits on the row, not sprung at the moment of accepting. Save still works, so a helper can queue up what they want the day they clear. Amber, because it's resolvable by them.
6d · Expired & declined rows
2:20battery_full
Open · 1Closed · 2
timerExpires in 5 hrs
In-Home Companionship
₹900
Rohit M. · Aug 3, 2:00 PM · 3 hrs
Review & acceptchevron_right
CLOSED · CLEARS IN 24 HRS
timer_offExpired · you didn't respond
Meera R. · Jul 30, 9:00 AM · Apollo
notifications_activeNotify me for similar tasks
blockDeclined · too far from me
Anil N. · Aug 2, 11:00 AM · Sector 14
undoI'm interested after all
Closed requests clear automatically. Nothing here counts against you.
Expired and declined share one Closed section with a stated clear-out window — silent deletion is what makes helpers think requests vanish at random. Each dead end offers one forward action, and declines stay recoverable while the task is still open.
Decision log · Round 6
The non-happy paths, and why these four first
What we found missing
Ten gaps, ranked by how likely a helper hits them in week one. Built here: empty inbox, lost the race, KYC-incomplete, expired row — all "the row isn't a happy path" states, so they share styling and are cheap together.
Next: filter/sort sheet (two app-bar icons currently lead nowhere), availability-off, loading skeleton and stale-data banner, push-notification entry point. Post-MVP: concurrent-task cap, accept success state.
Calls made
· Empty is three states, not one. New helper / paused by choice / verified but quiet. The cause is known server-side, so we never guess — and a generic "No requests" serves none of them. Only the paused case gets amber, because it's the only one the helper caused and can undo instantly.
· Lost the race is neutral, never an error. Grey container, explicit "this doesn't affect your rating", and an immediate pivot to what's still open. The lost task dims in place rather than disappearing, so the helper can see what happened.
· KYC-blocked helpers still see requests. An empty inbox teaches them nothing; seeing real tasks is the motivation to finish verification. But the lock sits on the row, not sprung at the moment they tap Accept — and Save still works, so they can queue up what they want for the day they clear.
· Closed rows persist for 24 hrs. Expired and declined share one Closed section with the clear-out window stated. Each offers one forward action — notify-me-for-similar on expiry, undo on a decline while the task is still open — which turns a dead end into matching signal.
· Nothing here is punitive. Every state says plainly that it doesn't count against the helper, because the ones that do (cancellation) need to stay distinguishable.
Open · worth deciding
Does "I'm interested after all" on a declined row reopen it silently, or tell the customer? Silent is simpler and kinder to the helper; telling the customer is more honest but invites "why did they decline me first". Recommendation: silent for MVP — the decline never reached the customer in the first place.
Reopen silently
Tell the customer
Drop undo entirely
Hold — decide later
{{ r6Line }}
Round 5 · Actions on the row
Triage without opening the task
Accept, decline and save from the list. The question is only whether accept belongs there too — it's the one action with a penalty attached, and the facts that prevent regret live on the detail screen. 5c adds swipe on top of whichever button layout wins.
5a · Full actions inline
9:41battery_full
timerExpires in 24 min
Meera R. · Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22 · ~22 min away
local_taxiCab by customerBoth ways
bookmark_border
closeDecline
checkAccept
timerExpires in 2 hrs
Anil N. · Aug 2, 11:00 AM · 2 hrs
Sector 14 · ~9 min away
directions_carYour 4-wheelerBoth ways
bookmark_border
closeDecline
checkAccept
Decline and Accept carry equal width with icon and label — declining matters as much as accepting, and an unlabelled X on a row this dense is a mis-tap waiting to happen. Save stays icon-only as the tertiary action. Costs ~60px per row, and accepts happen without the scope ever being read.
5b · Save & decline inline, accept in detail
9:41battery_full
timerExpires in 24 min
Meera R. · Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22 · ~22 min away
local_taxiCab by customerBoth ways
Review & acceptchevron_right
timerExpires in 2 hrs
Anil N. · Aug 2, 11:00 AM · 2 hrs
Sector 14 · ~9 min away
directions_carYour 4-wheelerBoth ways
Review & acceptchevron_right
timerExpires in 5 hrs
In-Home Companionship
₹900
Rohit M. · Aug 3, 2:00 PM · 3 hrs
Block C, Sector 9 · ~35 min away
directions_walkNo transport
Review & acceptchevron_right
Reversible actions inline as icon buttons; the commitment stays one tap away behind "Review & accept". Rows stay compact, so more tasks fit per screen.
5c · Swipe as an accelerator
9:41battery_full
check_circleReview
timer24 min
Hospital Visit
Meera R. · Jul 30, 9:00 AM
₹1,140 · ~22 min away
blockDecline…
timer2 hrs
Errand & Bank Visit
Anil N. · Aug 2, 11:00 AM
₹918 · ~9 min away
timerExpires in 5 hrs
In-Home Companionship
₹900
Rohit M. · Aug 3, 2:00 PM · 3 hrs
Block C, Sector 9 · ~35 min away
directions_walkNo transport
Review & acceptchevron_right
swipeSwipe right to review, left to decline. Both open the same screens as the buttons — nothing is final on release.
Same rows as 5b, with gestures layered on: top row mid-swipe right, second mid-swipe left. The trailing ellipsis on "Decline…" signals the reason sheet follows. Coaching strip shows for the first few sessions, then retires.
Decision log · Round 5
Should accept live on the row?
The trade
Save and decline are reversible or low-stakes, so inline is straightforwardly better. Accept is a commitment with a cancellation penalty, and the facts that prevent regret — scope boundaries, who drives, pickup point, waiting rate — only exist on the detail screen. Every accept made without them is a candidate cancellation, which costs the customer a re-match and costs us the trust.
Considered
· Accept everywhere (5a) — fastest, but ~60px per row means fewer tasks visible, and it optimises the wrong metric: accepts, not completions.
· Accept behind review (5b) — one extra tap, rows stay compact, and the tap is where the scope is.
· Conditional accept — allow inline accept only for repeat customers or task types the helper has done before, where there's nothing new to read. Best of both, but it's a rule helpers have to learn from behaviour, and an inconsistent row is hard to trust.
· Swipe actions (5c) — revisited and now viable, but only as an accelerator on top of visible buttons, with both gestures landing on a confirm step rather than acting outright.
Either way
Inline decline opens the reason sheet (Round 3 · 03) rather than acting immediately — but the reason itself is optional, with a "decline without a reason" escape. Save is a true one-tap toggle with no confirmation, since it commits to nothing.
On swipe (5c)
Viable with three conditions: buttons stay visible so the gesture is an accelerator and not the only path; swipe-left opens the reason sheet rather than declining outright; swipe-right opens the detail screen rather than committing. Net effect — it saves a tap on decline, and none on accept. Worth building only if triage volume is high enough that the decline tap is the bottleneck.
Decided
Decided: 5a. Accept lives on the row. Recommendation was 5b, so the risk we accepted is regret-cancellations from accepts made without reading scope — mitigated by keeping the row body tappable to detail, and by watching cancel-within-1hr as the metric that would send us back to 5b. 5c can still layer on later.
Go with 5a
Go with 5b
Go with 5c
Conditional accept
Hold — decide later
{{ r5Line }}
Round 4 · Inbox decision variants
What a helper needs to say yes
Three ways to answer "is this worth my day?" in the list itself. Same rows, different amount of maths done for the helper. Travel is measured from their registered area for future dates, from their previous drop point when the task is same-day — and the row says which.
V1 · Quiet meta line
9:41battery_full
timerExpires in 24 min
Meera R. · Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22
local_taxiCab by customerBoth ways
~22 min from your area · blocks ~3h 45m
timerExpires in 2 hrs
Anil N. · Aug 2, 11:00 AM · 2 hrs
Sector 14
directions_carYour 4-wheelerBoth ways
~9 min from your area · blocks ~2h 20m
timerExpires in 5 hrs
In-Home Companionship
₹900
Rohit M. · Aug 3, 2:00 PM · 3 hrs
Block C, Sector 9
directions_walkNo transport
~35 min from your area · blocks ~4h 10m
Adds only the two facts payout can't express: how far, and how much of the day it eats. No new colour, no new chips. Safest option — nothing here can be gamed or argued with.
V2 · Effective rate, all-in
9:41battery_full
swap_vertBest rate firstNearest
timerExpires in 2 hrs
Anil N. · Aug 2, 11:00 AM · 2 hrs
Sector 14 · ~9 min from your area
directions_carYour 4-wheelerBoth waysBlocks 2h 20m
timerExpires in 24 min
Meera R. · Jul 30, 9:00 AM · 3 hrs
Apollo, Sector 22 · ~22 min from your area
local_taxiCab by customerBoth waysBlocks 3h 45m
timerExpires in 5 hrs
Rohit M. · Aug 3, 2:00 PM · 3 hrs
Block C, Sector 9 · ~35 min from your area
directions_walkNo transportBlocks 4h 10m
Does the maths for them: payout ÷ blocked time, with sorting to match. Honest and popular with helpers — but it makes far tasks look bad in a way that's hard to unwind, and invites comparison against your own pricing. Amber on the weakest rate is deliberate; drop it if that feels like editorialising.
V3 · Grouped by day, fit-aware
9:41battery_full
THU, JUL 30 · day free
timerExpires in 24 min
Meera R. · 9:00 AM – 12:00 PM
Apollo, Sector 22 · ~22 min away
local_taxiCab by customerBoth ways
event_availableBlocks 8:38 AM – 12:22 PM
SAT, AUG 2 · 1 task booked, 1–3 PM
timerExpires in 2 hrs
Anil N. · 11:00 AM – 1:00 PM
Sector 14 · ~9 min away
directions_carYour 4-wheelerBoth ways
event_availableFits — ends 2 hrs before your 1 PM task
timerExpires in 3 hrs
Kamala S. · 3:00 PM – 5:00 PM
Fortis, Sector 62 · ~28 min away
keyTheir car, you driveReturn only
event_busyClashes — your 1 PM task runs to 3 PM, 28 min away
Answers "does this fit my day?" rather than "is this a good task?". Day headers show existing load, and each row states the real blocked window or the clash. Most work to build — needs the helper's calendar in the list query — and it prevents the accepts that turn into cancellations.
Decision log · Round 4
How we got to these three
The question
What does a helper need in the inbox to decide "is this worth my day?" — payout alone can't answer it.
Considered, ranked by decision impact
Distance and travel time from where they'll be · total time blocked door-to-door · effective ₹/hr all-in · schedule conflict with existing tasks · repeat or recurring customer.
Held for the detail screen: effort demands (stairs, wheelchair transfer, long queues), payment certainty, overrun likelihood, language and gender-preference match, late-night return viability.
Settled along the way
· Transport is never a yes/no. Task type decides whether transport exists; only provider, vehicle class and legs vary, carried as one derived string.
· Three transport modes, including customer's vehicle driven by the helper — designed rather than left to ops, at the cost of a licence + insurance KYC check and a handover step.
· Legs are independent of provider — onward only, return only, or both — because they change the stage list and the payout.
· Green is status only. Neutral facts (transport, distance) stay grey; teal is reserved for confirmed and in-progress.
· Timers never wrap; the transport tags take the remaining width and wrap instead.
How travel and blocked time are computed
Requests can be days out, so we don't use live GPS. Anchor falls back in three tiers, and the row names which one it used: previous task's drop point (same-day, task already booked) → live location (same-day, nothing booked) → registered base address, which onboarding already collects and which doubles as the work area ("from your area"). Travel uses typical time-of-day duration for that weekday and hour, never live traffic, always prefixed "~". Blocked time = travel out + duration + travel back; the return leg is unpaid but real, so it counts. For tasks more than 48h out, show a range and collapse to a point estimate on the day.
Decided
Recommendation is V1 now, V3 next, V2 held. V2's effective ₹/hr is the most useful number to a helper but it bakes a judgement into the marketplace — distant tasks will visibly rate worse and stop being picked up unless pricing responds. Ship it only as a deliberate pricing decision, not a UI side-effect.
Go with V1
Go with V2
Go with V3
Hold — decide later
{{ decisionLine }}