What a member sees, and when
A teaser that never names a party, a sheet one member reads at a time with every view logged, and the packet once they've cleared it. A pass is free and never counted against them.
What does a member see of a job, and when?
Three stages, each opening only when the one before it is done: the teaser, the sheet and the packet. sees chooses the fields of the first two:
grep sees pools/attorneys.ts sees: { teaser: ['act', 'region', 'fee_usd', 'signals'], sheet: ['parties', 'kind', 'amount'] },Every offer is a teaser: the sees.teaser fields plus the minutes the work takes, the fee per estimated hour and the due date. It never carries a party's name, so it is safe as a push payload, and it is the same in the feed and in the push:
→ GET /reviews/tsk_7Hq2 # as mbr_eligible{
"id": "tsk_7Hq2",
"object": "task",
"livemode": false,
"pool": "attorneys",
"role": "attorney",
"status": "open",
"fields": {
"act": "sign",
"region": "US-NY",
"fee_usd": 75,
"signals": [
"collections",
"recipient_elsewhere"
]
},
"est": {
"minutes": 30,
"from": "step"
},
- The minutes are measured. Once a step has
probation.tasksaccepted acts,est_minutesis their median over 30 days, and the rate is the fee over that. Until then it is the step's ownest, and the teaser says which. - In a work register, the teaser adds the window, the distance from the member's base, and whether travel is paid. The address opens only on the claim.
The sheet adds the sees.sheet fields, party names included, and the statements the member attests to clear it. One member reads it at a time, for the Pool's sheet span, and every view is logged:
→ GET /reviews/tsk_7Hq2/sheet # as mbr_7Hq2, offered it first{
"id": "tsk_7Hq2",
"object": "sheet",
"livemode": false,
"pool": "attorneys",
"role": "attorney",
"status": "open",
"fields": {
"act": "sign",
"region": "US-NY",
"fee_usd": 75,
"signals": [
"collections",
"recipient_elsewhere"
],
"parties": [
{
"as": "client",
"name": "Ada Lovelace"
},
While one member has it, another is told to wait:
→ GET /reviews/tsk_7Hq2/sheet # as mbr_eligible, while mbr_7Hq2 has it← 409 task_taken: tsk_7Hq2 is offered to other signers first, until 2026-10-25T15:02:11.000Z.Because a sheet names parties, the client consents before the first Task posts, and check fails sheet_without_consent on a Service that lets one post first.
A pass is free, under the member charter. It is counted against the Task, never against the member, and its reason is one word of five. Under cascade it moves the Task on at once, and the member who passed isn't offered it again until the fee is raised:
→ POST /reviews/tsk_7Hq2/pass {"reason":"fee"} # as mbr_7Hq2← 200 tsk_7Hq2 · open · attorney · sign · US-NY · $75.00 · signals collections, recipient_elsewhere · 30 min · $150.00 an hour · due 2026-10-27 14:02reason | When a quorum passes for it |
|---|---|
fee | the next raise fires now |
scope, area | the next widen fires now |
timing | the due date moves a day |
other, any other word, or none | nothing moves |
The owner reads the views and the passes by reason, never who passed for what:
→ GET /owner/reviews/tsk_7Hq2 # the owner console← views [{"member":"mbr_7Hq2","at":"2026-10-25T14:02:11.000Z"}] · passes {"fee":1} · viewers 1 · jump null · offered mbr_7Hq2 (cascade), mbr_eligible (cascade)Once at least jump.min members have read the sheet since the last rung, and more than half of them passed for one reason, that reason's fill rung fires early. Here three members pass on fee, and the raise due at two hours fires at once:
→ POST /matters {"service":"demand-letter","client":{"name":"Ada Lovelace","email":"signs@example.test"},"recipient":{"name":"Initech","email":"ap@initech.example","org":"Initech Inc"},"claim":"unpaid debt for invoice 1042","amount":4200,"client_region":"US-NY","recipient_region":"US-NJ","evidence":["invoice-1042.pdf"],"max_usd":149,"key":"quorum"}← job_7Hq2 · waiting · on claim · $149.00 held · sign · tsk_7Hq2
→ GET /reviews/tsk_7Hq2/sheet # as mbr_7Hq2
← 200 sheet · fee $75.00
→ POST /reviews/tsk_7Hq2/pass {"reason":"fee"} # as mbr_7Hq2
← 200 tsk_7Hq2 · open · attorney · sign · US-NY · $75.00 · signals collections, recipient_elsewhere · 30 min · $150.00 an hour · due 2026-10-27 14:02
→ GET /reviews/tsk_7Hq2/sheet # as mbr_7Hq3
← 200 sheet · fee $75.00
→ POST /reviews/tsk_7Hq2/pass {"reason":"fee"} # as mbr_7Hq3
← 200 tsk_7Hq2 · open · attorney · sign · US-NY · $75.00 · signals collections, recipient_elsewhere · 30 min · $150.00 an hour · due 2026-10-27 14:02
→ GET /reviews/tsk_7Hq2/sheet # as mbr_7Hq4
← 200 sheet · fee $75.00
→ POST /reviews/tsk_7Hq2/pass {"reason":"fee"} # as mbr_7Hq4
← 200 tsk_7Hq2 · open · attorney · sign · US-NY · $82.50 · signals collections, recipient_elsewhere · 30 min · $165.00 an hour · due 2026-10-27 14:02
→ GET /owner/reviews/tsk_7Hq2 # the owner console
← passes {"fee":3} · viewers 3 · posted $75.00, now $82.50
fired raise 10% 2h · 14:02 · raised to $82.50 · jumpedTo clear a claimed Task, the member attests each clear statement, word for word. That is the seventh predicate of eligibility, and the conflict check runs again with it. Then the packet opens, to that member alone.
| Key | Written | Left out | Does |
|---|---|---|---|
sees | { teaser: string[]; sheet?: string[] } | { teaser: ['act', 'region', 'fee_usd'] } | What a member sees: the teaser before claiming (always with est_minutes, measured or estimated, the rate and the due date, never a party name), and the sheet. |
clear | string[] | { attest: string[]; check?: string[] } | none | What a member attests before the packet opens, and the party inputs checked, hashed, against their ledger. |
sheet | ShortSpan | '10min' | How long one member has a sheet to themselves. |
jump | { min?: number } | { min: 3 } | When passes move the ladder: at least min distinct sheet viewers since the last rung, and more than half of them passing for the same kind of reason. |
contact | 'thread' | 'thread' | Member contact with a party relays through the job's thread, the only value: email and phone never cross either way. |
Worked in: the closers' feed, a teaser before the claim.