Skip to content

Benchmark rows

Scores every company in your niche on one measure and sends each its private row, its gap and one free fix, naming no low scorer.

Channel
Email and inboxes
Run oneMode try
You, to your agent

Hand our latest ready row to the SDR agent and show me what it chose and why. Don’t send.

curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Monitor.checked%22%2C%20%22Form.submitted%22)&limit=1" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"

# Not live yet (gaps #7)
curl -X POST "https://api.sb/leaseline.app/triggers/fire?mode=try" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"like":"event_1423"}'

# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22organization_144%22" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"

# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/actions?where=on%20%3D%20%22organization_144%22" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
import { $ } from 'startup-builder'

const { events: [last] } = await $.Event.list({ where: 'name in ("Monitor.checked", "Form.submitted")', limit: 1 })   // { play } compiled to this Play’s Trigger Events
const { subject } = await $.Trigger.fire({ like: last.$id }, { mode: 'try' })   // the same Event again, in try mode · Not live yet, gaps #7
const { decisions: [decision] } = await $.Decision.list({ where: `on = "${subject}"` })   // what it chose, and why · Not live yet, gaps #7
const { actions } = await $.Action.list({ where: `on = "${subject}"` })   // what it did, with its checks · Not live yet, gaps #7
return { decision, actions }
npx startup-builder do Event.list --json '{"where":"name in (\"Monitor.checked\", \"Form.submitted\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1423"}' --try   # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"organization_144\""}'   # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"organization_144\""}'   # Not live yet (gaps #7)
{
  "name": "do",
  "arguments": {
    "code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Monitor.checked\", \"Form.submitted\")', limit: 1 })   // { play } compiled to this Play’s Trigger Events\nconst { subject } = await $.Trigger.fire({ like: last.$id }, { mode: 'try' })   // the same Event again, in try mode · Not live yet, gaps #7\nconst { decisions: [decision] } = await $.Decision.list({ where: `on = \"${subject}\"` })   // what it chose, and why · Not live yet, gaps #7\nconst { actions } = await $.Action.list({ where: `on = \"${subject}\"` })   // what it did, with its checks · Not live yet, gaps #7\nreturn { decision, actions }",
    "mode": "try"
  }
}
Response200application/json
{
  "decision": {
    "$id": "https://api.sb/leaseline.app/decisions/decision_495",
    "$type": "Decision",
    "choice": "send-the-row",
    "reason": "Brookstone Rentals scores 41 against the median 58; its renewals page names no notice date, a fix it can copy from the method page, and its operations lead has a verified address",
    "stakes": "low",
    "options": [
      "send-the-row",
      "send-as-you",
      "ask-to-be-named",
      "send-the-movement",
      "re-read-it",
      "not-now"
  …
sample · 4 Not live yetPreview

On POST /{namespace}/processes/{process}/enableOff POST /{namespace}/processes/{process}/pauseTake this one POST /{namespace}/tasks/{task}/claim

action_3 is the row note to Brookstone’s operations lead, held 2 minutes, with a link to its private row page; the row page is noindex, and only Brookstone sees its own score.

+7.9 acting per 100 rows · ■□□□ Too early to tell · n 169 matured · path → arr

Try another: the companyChoiceReason
Brookstone Rentals: 41 against a median of 58, no notice date on its renewals pagesend-the-rowa gap, a free fix, and a verified address
Calloway Residential: 72, ranked 4thask-to-be-namedin the top 10: it asks for a yes to name them
Northgate Lettings: 49 to 61 after adding online renewalsend-the-movementup 12 points and 21 percentiles
Harlow Lettings: “Your reading of our fees page is wrong”re-read-ita disputed reading
Wrenfield Rentals: a Customernot-nowCustomers get no row note

Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Row action rate → New Leads → New Customers ↑ → ARR added each week → ARR

Worth’s formula: about +7.9 acting companies per 100 rows × 95 rows a month × 0.43 actions to Leads × 0.12 Leads to paid × $650 first order ARR ≈ +$250. Under First signal: About 4 months to tell a +8 lift at 95 rows a month with 10 % held back; at 300 companies, the 30-day read pools with Other Startups’ results.

sample · api.sb/leaseline.app · 41 Customers at 2026-10-19 · on Monitor.checked · first row sent 2 days after the index published · 4 keys Not live yet

Runs inside: Proof-of-work outreach, as one of its options; this page keeps its own record and URL.

Start it this week

Terminal
npx startup-builder add play benchmark-rows   # 1 · writes plays/benchmark-rows.mdx (Not live yet, gaps #5)

# 2 · dry run; below, its 422 on the day-0 Startup (clock at 2026-08-24)
curl -X POST "https://api.sb/leaseline.app/campaigns?mode=try" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"play":"benchmark-rows"}'

# 3 · keep it, at You approve each one for the first 25 rows
curl -X POST https://api.sb/leaseline.app/campaigns \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"play":"benchmark-rows"}'

# on
curl -X POST https://api.sb/leaseline.app/processes/outbound/enable \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"

# off: no row note sends; the index stays published
curl -X POST https://api.sb/leaseline.app/processes/outbound/pause \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
422Refusedbenchmark-rows can’t start yet: 2 checks fail and 1 warns.
CheckFixThen
owned-by-a-person pass · Not live yet, gaps #80 of 640 companies have a Lead or open Deal a person ownsPOST /{namespace}/tasks/{task}/assign
use-when pass · Not live yet, gaps #8640 property managers with public renewal pagesPOST /{namespace}/metrics/query
baseline warn · Not live yet, gaps #8n 640: the held-back 10 % is your comparison from day 1.POST /{namespace}/metrics/query
approved-pages fail · Not live yet, gaps #8Publish the method page; every row links to it.POST /{namespace}/sites/{site}/publish
domain-authenticated passleaseline.app: 3 of 3 records resolvePOST /{namespace}/domains/{domain}/authenticate
mailbox-warm fail · Not live yet, gaps #1Wait for the warm-up to finish, 14 days from day 0; the index publishes meanwhile.POST /{namespace}/mailboxes/{mailbox}/warm
role-unstaffed warn · Not live yet, gaps #8Staff the AE, or leave it: replies come to you.POST /{namespace}/roles/{role}/staff
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "benchmark-rows can’t start yet: 2 checks fail and 1 warns.",
  "checks": [
    {
      "check": "owned-by-a-person",
      "status": "pass",
      "observed": "0 of 640 companies have a Lead or open Deal a person owns",
      "doc": "/plays/benchmark-rows#check-owned-by-a-person",
      "then": "Task.assign"
    },
    {
      "check": "use-when",
      "status": "pass",
      "observed": "640 property managers with public renewal pages",
      "doc": "/plays/benchmark-rows#check-use-when",
      "then": "Metric.query"
    },
    {
      "check": "baseline",
      "status": "warn",
      "observed": "0.8 hand-raises per 100 of these companies in 90 days, n 640",
      "doc": "/plays/benchmark-rows#check-baseline",
      "fix": "n 640: the held-back 10 % is your comparison from day 1.",
      "then": "Metric.query"
    },
    {
      "check": "approved-pages",
      "status": "fail",
      "doc": "/plays/benchmark-rows#check-approved-pages",
      "fix": "Publish the method page; every row links to it.",
      "then": "Site.publish"
    },
    {
      "check": "domain-authenticated",
      "status": "pass",
      "observed": "leaseline.app: 3 of 3 records resolve",
      "doc": "/plays/benchmark-rows#check-domain-authenticated",
      "then": "Domain.authenticate"
    },
    {
      "check": "mailbox-warm",
      "status": "fail",
      "doc": "/plays/benchmark-rows#check-mailbox-warm",
      "fix": "Wait for the warm-up to finish, 14 days from day 0; the index publishes meanwhile.",
      "then": "Mailbox.warm"
    },
    {
      "check": "role-unstaffed",
      "status": "warn",
      "roles": [
        "sales-lead"
      ],
      "owned": 0,
      "doc": "/plays/benchmark-rows#check-role-unstaffed",
      "fix": "Staff the AE, or leave it: replies come to you.",
      "then": "Role.staff"
    }
  ]
}

It says no, says why, and names the fix.

CheckFix (one call)Your timeWait
owned-by-a-person · use-when · baseline · pass · pass: 640 companies · warn: 0.8 per 100 (gaps #8)POST /{namespace}/metrics/query on row-action-rate1 minnone
approved-pages · fail: no method page (Not live yet)POST /{namespace}/sites/{site}/publish the method, the aggregate and the top 1025 minnone
domain-authenticated · mailbox-warm · pass · fail: sdr@ and rows@ warmed 0 of 14 daysPOST /{namespace}/mailboxes/{mailbox}/warm2 min14 days
role-unstaffed · warn (gaps #8): no AE, so replies come to youPOST /{namespace}/roles/{role}/staff, or leave it0 minnone

Your number · Before 0.8 hand-raises per 100 · Now 13.8 acting per 100 rows · Target 15 by Dec 31 · ■□□□ Too early to tell · n 169 matured · held back at random

Each reading costs $0.01 a page, at most 10 pages a company; each row note costs $0.04 from your Domain (Worker cost), and contact data for the role that owns the fix costs $0.02 (POST /{namespace}/contacts/{contact}/enrich). That comes to about $6 a month at 95 rows and a weekly re-read.

When it starts

WhenTrigger idStarts onWindowHow it gets in
A row passes the gap floor and the fix test, with a verified addressrow-readystate on Monitor.checked where gap over the floor, a reproducible fix, and a verified address for the owning rolethe note within 1 d; dropped after 7 dthe weekly POST /{namespace}/monitors/{monitor}/check
A re-read moves a company up by a real changerank-movethreshold on Monitor.checked where value moved by the smallest real change, and percentile by 5 points or morethe note within 24 h, or droppedthe same
A company asks for a re-readregrade-requestevent on Form.submitted where form = 'regrade', from the row Page or a replywithin 24 hthe row page’s Form, through POST /{namespace}/forms
+ 5 more for index dates, public changes, live fixes, disputes and read-me requests (?lanes=all)
One signed delivery · StartupBuilder-Signature
{
  "$id": "https://api.sb/leaseline.app/events/event_1423",
  "$type": "Event",
  "name": "Monitor.checked",
  "at": "2026-10-19T06:30:19Z",
  "seq": 1423,
  "data": {
    "monitor": "renewal-readiness",
    "organization": {
      "$id": "https://api.sb/leaseline.app/organizations/organization_144",
      "name": "Brookstone Rentals"
    },
    "score": 41,
    "median": 58,
    "gap": 17,
    "fix": "state the notice date on the renewals page"
  }
}
Reproduce it in test
# each delivery is signed with the Watch’s secret
curl -X POST https://api.sb/leaseline.app/watches \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"selector":"Monitor.checked","url":"https://leaseline.app/hooks/sb"}'
npx startup-builder trigger Monitor.checked --like event_1423   # replays the ready row
npx startup-builder clock advance --by 7d   # runs the weekly re-read, which finds a fix if it shipped

Who runs it

SDR · your agent (role:prospector, worker_2) holds the Key Result. It hands replies to AE · Priya Shah (person) (role:sales-lead, worker_3, staffed on day 9), and top-tier rows, re-reads that change a score and the top 10 to you (Dana Okafor, person, worker_1). Your number links to Did it work.

OptionRung todayEvidence (passed of n)Moves up atDrops back whenYou can
Send their row · Send the movementIt does it, you can stop it25 of 25 approved unedited, then 166 of 166met on day 19 (the first 25 rows); capped herea dispute or removal Stop → You approve each onePOST /{namespace}/actions/{action}/cancel inside the hold
Send it as you · Ask to be namedYou approve each one, on every rung6 of 6 · 10 of 10never—POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse
Re-read itIt does it; a changed score waits for you4 re-read, 1 changed and approved——POST /{namespace}/approvals/{approval}/approve
Not nowIt does it389 held——POST /{namespace}/actions/{action}/redirect
Never: a low scorer named in public, a number no reading holds, the index without you named as its stewardTo a person, every time1 refused, 0 sentnever—POST /{namespace}/processes/{process}/pause

What it reads · What it may call. It reads public pages only, at a rate Limit, and stores each reading with its page and time. A company’s own row goes only to that company; public text names only a top-10 company that said yes. Its tools are POST /{namespace}/messages/{message}/schedule, POST /{namespace}/monitors/{monitor}/check, and any other call becomes an Approval under the Role’s Mandate.

The brief (folded): compiled Agent-register Markdown · play:benchmark-rows@1 · each line names its record key
You hold the SDR Key Result: 15 acting companies per 100 rows by 2026-12-31.     ← worker, metric
On each ready row, re-read or request, choose one option and say why.            ← triggers, chooses
Every number in a note matches a stored reading under 7 days old.                ← number-match, fresh-reading
Every row note gives one fix the company can make for free.                      ← your file, line 4; fix-gate
Name nobody outside the top 10, and them only with their yes.                    ← your file, line 5; named-score

The slow loop. The weekly Decisions kept the 8-point gap floor and the one-fix rule, and no Change was merged in the window, so there is no replay or read-back to print.

Bring your own agent (folded) starts at You approve each one when it trails the seated agent on unmatched numbers, and at It does it, you can stop it when it matches.

Terminal
npx startup-builder eval --scenario benchmark-rows-191 --agent "claude -p" --seat prospector   # seated: 13.8 acting per 100, 0 unmatched numbers, $0.06 a row · yours: 12.9, 2 unmatched → You approve each one

What it can do next

OptionPicked whenDecided byRunsHands toIf it’s just you
Send their row send-the-rowa gap, a free fix and a verified addressAgent’s call, with its reasonrow-first-touch → row-watch for those who claim the rowon reply, POST /{namespace}/tasks/{task}/assign → AE · Priya Shah, due 60 min · Take this oneyou, within 60 min
Send it as you send-as-youover 500 unitsYour rule (line 6)row-first-touch-founder from dana@, after your OKyou approve each one · Take this oneyou
Ask to be named ask-to-be-namedin the top 10Your rule (line 5)top-ten-ask: one ask for a yes to be namednobodythe same
Send the movement send-the-movementup by a real change and 5+ percentilesYour rule (the movement Limit)row-movement: one note per 30 days, upward onlynobodythe same
Re-read it re-read-ita re-read request or a disputeAgent’s call, with its reasonPOST /{namespace}/monitors/{monitor}/check twice, 24 h apart; a changed score waits for youyou, due 2 business days · Take this oneyou
Not now not-nowno fix, under the floor, a Customer or open Deal, or no addressYour rule (the send list)nothing; the company stays in the index and its aggregatenobodythe same
When they write backFixture replyWhat happensWho answersBy whenCall
Interested“Fixed the notice date. What else would move us?”offers times with the AE; the Brief goes to her (When it hands to you)AE · Priya Shah (person)60 minPOST /{namespace}/meetings/book
Send me pricing“What does Leaseline cost for 180 units?”answers with the Pricing Page’s list Price and one next stepSDR · your agent5 minPOST /{namespace}/conversations/{conversation}/answer
Not now“Interesting. Maybe after year-end.”no further note but one upward movement; the row page stays theirsSDR · your agentat oncePOST /{namespace}/leads/{lead}/nurture
Wrong person“Our web team owns that page.”asks them to forward the row; it never writes to a name from their textSDR · your agent1 business dayPOST /{namespace}/conversations/{conversation}/answer
Out of officean auto-reply until Nov 4any movement note waits for the return date, and drops if 24 h pass after a re-readnobodythe return datePOST /{namespace}/messages/{message}/schedule
Question it can’t answer“How do you weigh online payments against notice timing?”To you, the question in the Brief; the method page answers what it canyou1 business dayPOST /{namespace}/conversations/{conversation}/escalate
Stop“Remove us from your index.”no note sends, and their row leaves every output; the aggregate re-runs without themnobodyat oncePOST /{namespace}/suppressions

When it hands to you

Replies go to AE · Priya Shah (person); top-tier rows, the top 10 and any re-read that changes a score come to you. Before day 9 every reply came to you. What lands in each queue, as captured: one Brief per Role, then the Approval (brief, draft, route and checks are Not live yet, gaps #7).

What lands in each queue · sample
[
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_297",
    "$type": "Task",
    "assignee": "worker_3",
    "due": "2026-09-25T15:04:00Z",
    "on": "lead_72",
    "brief": {
      "who": "Mei Tanaka, Northgate Lettings",
      "said": "Fixed the notice date. What else would move us?",
      "chose": "send-the-row",
      "why": "scored 49 against 58; shipped the fix in 6 days",
      "row": "61 after the re-read, up 21 percentiles",
      "never": [
        "another company’s score",
        "a price beyond the list"
      ]
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_301",
    "$type": "Task",
    "assignee": "worker_1",
    "due": "2026-10-02T17:00:00Z",
    "on": "organization_151",
    "brief": {
      "who": "Harlow Lettings",
      "said": "Your reading of our fees page is wrong.",
      "chose": "re-read-it",
      "why": "a disputed reading",
      "reread": "2 reads 24 h apart: 44 and 52; their fees page changed on Sep 29"
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/approvals/approval_86",
    "$type": "Approval",
    "verdict": null,
    "deadline": "2026-10-02T17:00:00Z",
    "draft": "Harlow’s row moves from 44 to 52 after the Sep 29 change to its fees page.",
    "route": "re-read-it",
    "checks": [
      {
        "check": "number-match",
        "status": "pass"
      },
      {
        "check": "fresh-reading",
        "status": "pass"
      }
    ]
  }
]

Each receiver answers with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, POST /{namespace}/actions/{action}/redirect, POST /{namespace}/approvals/{approval}/approve or POST /{namespace}/approvals/{approval}/refuse, each a one-call window, and an Approval unanswered by its deadline expires and the score stays as read. Once a person claims, the row notes to that company stop, and every reply goes to the claimer’s queue. A Task nobody claims by its due time goes up a Role through POST /{namespace}/tasks/{task}/escalate (AE to you), and person-promise fires.

On time: AE · Priya Shah, 8 of 8 replies claimed within 60 min, median 26 min, ■■□□ Early sign, n 8; you, 17 of 17 approvals by their deadline, n 17. Your queue: counted by kind: in weeks 1 to 3, 25 row approvals, the method page and 10 top-10 asks; since, about 1 hand-off and 1 re-read a week.

The fixed line: POST /{namespace}/deals/{deal}/assign sets owner to the receiving person, the agent is never a Deal’s owner, and Meetings land on the owner’s calendar under the owner’s name.

When it won’t send

Check (refuses one send)RefusesFixThen
owned-by-a-person (rule j; Not live yet, gaps #8)a row note to a Contact whose Lead or open Deal a person ownsLeave it to the person who owns it: the draft waits in their queue.POST /{namespace}/tasks/{task}/assign
number-matcha number in a row, note or post that matches no stored readingUse the stored reading, or re-read the page first.POST /{namespace}/monitors/{monitor}/check
fresh-readinga note that states a reading over 7 days oldRe-read the company; the note waits for it.POST /{namespace}/monitors/{monitor}/check
fix-gatea row with no fix anyone can reproduce, or a gap under the smallest real changeLeave it in the index; it gets no note.GET /{namespace}/decisions
named-scorepublic text that names a company outside the top 10, or one with no yes on fileShow the aggregate only, or ask the top 10 for their yes.POST /{namespace}/messages/{message}/schedule
cell-floora published group of fewer than 10 companiesMerge it into a larger group, or cut it.PATCH /{namespace}/pages/{id}
self-exclusionan index that includes you, your other Startups or a named rivalDrop them from the census and re-run it.POST /{namespace}/monitors/{monitor}/check
steward-linea page, chart, file or note that omits that you run the index and sell in the categoryKeep the fixed steward line on every output.PATCH /{namespace}/pages/{id}
methodany reading or note under a method that fails a method checkFix the method page; nothing reads until it passes.POST /{namespace}/sites/{site}/publish
movement-limita 2nd movement note in 30 days, a downward one, or one after 3 unansweredWait for the window; downward moves never send.POST /{namespace}/messages/{message}/schedule
late-notea movement note more than 24 h after its re-readIt drops; the next re-read starts a new one.POST /{namespace}/monitors/{monitor}/check
Stop (pauses the Play)Pauses whenThen
collection-fencea request outside public pages or the rate Limitcollection halts until you review it
unreadableover 10 % of companies cannot be readthe index and every row hold
disputeupheld disputes pass 2 % of rows in 30 days, after 100row notes pause and the method returns to you
removalremoval asks pass 3 % of rows delivered, after 100row notes pause
row-action-floorunder 3 acting per 100 after 300 deliveredrow notes stop; the index keeps publishing
sending-stop-lossbounces, complaints, spam placement or a blocklist hit pass their linesthat Mailbox pauses; POST /{namespace}/mailboxes/{mailbox}/rest
kill-switchyou press itevery Tactic pauses; POST /{namespace}/processes/{process}/enable after review

The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the note that sent instead is the second thread in Example.

422RefusedThe row note to Oak Hill Management did not send: it states a median the readings do not hold.
CheckFixThen
number-match failUse the stored reading, or re-read the page first.POST /{namespace}/monitors/{monitor}/check
fresh-reading pass—POST /{namespace}/monitors/{monitor}/check
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "The row note to Oak Hill Management did not send: it states a median the readings do not hold.",
  "checks": [
    {
      "check": "number-match",
      "status": "fail",
      "observed": "the note said 60; the stored median is 58",
      "doc": "/plays/benchmark-rows#check-number-match",
      "fix": "Use the stored reading, or re-read the page first.",
      "then": "Monitor.check"
    },
    {
      "check": "fresh-reading",
      "status": "pass"
    }
  ]
}

It says no, says why, and names the fix.

The Stops that fired, as Campaign.paused reasons · sample
[
  {
    "reason": {
      "limit": "sending-stop-loss",
      "observed": "2.3 % bounces on rows@leaseline.app",
      "bound": "2 %",
      "window": "1 day"
    },
    "doc": "/plays/benchmark-rows#stop-sending-stop-loss",
    "mailbox": "rows@leaseline.app"
  }
]

Did it work

Both halves come from the same random draw: 191 companies sent their row and 21 held back (rules m–o); a company counts once 30 days have passed since its row. Each figure’s call is POST /{namespace}/metrics/query by node and by arm; every node above the leaf is Not live yet (gaps #4).

+7.9 acting per 100 rows · ■□□□ Too early to tell · n 169 matured · path → arr

Chose
send-the-row
Why
Brookstone Rentals scores 41 against the median 58; its renewals page names no notice date, a fix it can copy from the method page, and its operations lead has a verified address
From
send-the-row · send-as-you · ask-to-be-named · send-the-movement · re-read-it · not-now
Expects
Brookstone ships the fix, replies or claims its row within 30d
Reopens when
no row action at organization_144 within 30d
By
worker_2
JSON
{
  "$id": "decisions/decision_495",
  "$type": "Decision",
  "choice": "send-the-row",
  "reason": "Brookstone Rentals scores 41 against the median 58; its renewals page names no notice date, a fix it can copy from the method page, and its operations lead has a verified address",
  "stakes": "low",
  "options": [
    "send-the-row",
    "send-as-you",
    "ask-to-be-named",
    "send-the-movement",
    "re-read-it",
    "not-now"
  ],
  "by": "worker_2",
  "on": "organization_144",
  "expected": "Brookstone ships the fix, replies or claims its row within 30d",
  "reopensWhen": "no row action at organization_144 within 30d"
}
NodeAgent halfYour halfAddedConfidenceBasis
row-action-rate13.8 acting per 100 rows (21 of 152)5.9 hand-raises per 100 held back (1 of 17)+7.9 [−4.6, +20.4]■□□□ Too early to tellheld back at random · n 169 matured · 43 still maturing · Other Startups’ results +9.2, ■■□□ Early sign, n 2,870
new-leads5.9 per 100 (9 of 152)0 (0 of 17)+5.9 [−1.4, +13.2]■□□□ Too early to tellthe same assignment
new-arr ↑$945, 1 Customer on Team · Booked: credited, not all caused by this Play$0+$622 per 100 rows [−$600, +$1,840] · Worth about +$250 a month■□□□ Too early to tell (1 vs 0 Customers)the same · 2 Deals still deciding
net-new-arr · arr+$945$0+$622 per 100 rows, carried: it moves no other bridge term■□□□ Too early to tellcarried from new-arr

The leaf counts companies that, within 30 days of their row, ship a change that moves their score, reply with anything but stop, or claim their row, each once, per 100 rows delivered; a held-back company counts if it writes in first.

How it moves it: each company got its own score, its gap to the median of 58 and one fix it could copy from the method page, and 14 of the first 152 shipped that fix within 30 days.

Guardrails: treated against held back: positive-reply-rate on the row Mailboxes, 6.1 %, and removal asks, 2 of 188 delivered, under the 3 % Stop.

The Campaign card · sample
{
  "$id": "https://api.sb/leaseline.app/campaigns/benchmark-rows",
  "$type": "Campaign",
  "play": "play:benchmark-rows@1",
  "path": [
    "row-action-rate",
    "new-leads",
    "new-arr",
    "net-new-arr",
    "arr"
  ],
  "experiment": {
    "metric": "row-action-rate",
    "unit": "per-100",
    "heldBack": 21,
    "decision": null
  },
  "readout": {
    "value": 7.9,
    "n": 169,
    "maturing": 43,
    "interval": [
      -4.6,
      20.4
    ],
    "readability": "inadmissible",
    "basis": "held-back",
    "pooled": false
  },
  "ledger": {
    "spend": 9,
    "workerCost": 8,
    "hours": 3.1,
    "wonArr": 945,
    "projectedArr": 250,
    "paybackDays": 7
  }
}

Outside benchmark: self-ranked “best of” lists leave out their own publisher in 1 of 4 cases, and readers trust those that do (a 2026 search-quality study).

Before it · After it. Before it: programmatic-seo and aeo make the index page findable. After it: proof-of-work-outreach, which it runs inside, writes the next note once a company engages, and instant-response answers anyone who writes first.

Example

Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days). 640 property managers were read; 26 could not be (4.1 %, under the hold), leaving 614 scored, median 58. After the top 10, 31 Customers, no fix, no address and holds, 212 were eligible: 191 got their row and 21 were held back at random. Read every captured thread at ?threads=all; three follow the tables.

What happened, by optionDecisionsDoneActing companies (what happened)
Send their row · Send it as you185 · 6185 sent, 3 bounced · 6 sent20 · 1
Ask to be named · Send the movement10 · 96 said yes · 9 sent— · 4 replied
Re-read it · Not now4 · 3891 score changed · held—
Sent · held back191 · 21188 delivered21 of 152 matured · 1 of 17
At 300 companies (the Use it when volume)about 90 rowsheld back at random; pools at 30 daysOther Startups’ results: +9.2 per 100, ■■□□ Early sign, n 2,870
DayEventWhat happenedYour time
0event_1121 Campaign.createdthe method from 7 parts; the dry run fails approved-pages and mailbox-warm35 min
1event_1127 Site.publishedthe method page, the median and the top 10’s empty slots25 min
3event_1139 Message.created, first of 10the top-10 asks; 6 said yes by day 910 min
14event_1191 Mailbox.warmedthe first rows sent, 25 a day across 2 Mailboxes—
19event_1218 Role.updatedpromoted after 25 rows approved unedited: rows send after a 2-minute hold—
20event_1222 Monitor.checkedthe first fix live: Northgate added its notice date—
29event_1297 Campaign.pausedsending-stop-loss on rows@: 2.3 % bounces; rested a day, resumed5 min
1–56event_1140 Task.created, first of 20approvals, re-reads and the weekly memo, from the POST /{namespace}/tasks/next log1.8 h · total 3.1 h measured, 3.5 h asked

Leaseline → Mei Tanaka, Northgate Lettings, Sep 12, 08:40 · Subject: Northgate’s renewal readiness: 49 · We read 614 property managers’ public renewal pages; the median is 58.¹ Northgate’s renewals page names no notice date, which is 9 of the 51 points between you and the leader. Adding one line, “we send renewal notices 60 days out”, closes it.² Your private row: leaseline.app/rows/northgate. We run this index and sell renewal software. *Signed with the Role’s disclosure line.*³

Sep 18 · the re-read found the line live: 61, up 21 percentiles; the movement note went the next morning. Sep 25 · “Fixed the notice date. What else would move us?” The Brief went to Priya, and Northgate took Team on Oct 9 (+$945 ARR).

Oak Hill Management, 2026-09-16 · number-match refused the note, then the one that sent
- The median property manager scores 60; Oak Hill scores 47.
+ The median property manager scores 58; Oak Hill scores 47.

Harlow Lettings, 2026-10-01 11:05 · “Your reading of our fees page is wrong.” · Leaseline, 11:06 · *Thanks. Dana re-reads every disputed row and replies by tomorrow, 17:00.*⁴ Two reads 24 h apart scored 52, up from 44 after their Sep 29 change; Dana approved the new score at 15:30 (approval_86).

¹ Every number matches a stored reading under 7 days old. ² One fix the company can make for free. ³ The fixed signature and steward lines, compiled from the Role’s Settings. ⁴ The routed line, compiled from the Role’s Settings.

Your settings

plays/benchmark-rows.mdx
---
holdout: 0.1      # 1 in 10 eligible companies gets no row note, chosen at random
---
Score renewal readiness, 0 to 100, from public pages only; one free fix per row.
Name only the top 10, and only with their yes.
Over 500 units, send the row as Dana, after her OK.
Text
$ npx startup-builder show plays/benchmark-rows
holdout 0.1 · the index and fix rule · the top-10 rule · the 500-unit line    your file  plays/benchmark-rows.mdx:2,4,5,6 (Ask 2026-08-24)
family demand · process outbound · runs inside proof-of-work-outreach · worker role:prospector, owns never · chooses 6 (4 rule, 2 read) · sequences row-first-touch, row-first-touch-founder, row-movement, row-watch, top-ten-ask · approval every-send · checks owned-by-a-person, number-match, fresh-reading, fix-gate, named-score, cell-floor, self-exclusion, steward-line, method, movement-limit, late-note · stops 7    catalog  play:benchmark-rows@1 (Not live yet, gaps #5)

Every key from the catalog

Key Id What it is
Tactic index-method Index method picks one metric a logged-out visitor can read, tests its stability and fixability, and freezes it before any census reading. Starts at You approve each one.
Tactic niche-census Niche census turns the ICP query into 200 to 3,000 Organizations, each with a verified address for the role that owns the measured surface. Starts at Sends nothing.
Tactic public-reading Public reading measures every Organization in the census each week from its public Pages, under a collection fence, and keeps every reading. Starts at Sends nothing.
Tactic fix-finder Fix finder picks the one-day change that most moves an Organization’s value, proves it on a copy, or returns no fix. Starts at Sends nothing.
Tactic index-publish Index publish posts the method, the aggregate and an opt-in top 10 on a cited index Page, and hands the quarterly release to Data stories. Starts at It does it, you can stop it.
Tactic top-ten-consent Top ten consent asks the 10 top-ranked Organizations to be named before each quarterly release, and names only those that say yes. Starts at You approve each one.
Tactic row-send Private row send delivers each Organization its private row, its gap and one free fix, under the day’s Mailbox capacity, with a 10 percent holdout. Starts at You approve each one.
Tactic change-watch Change watch re-reads an Organization within 24 hours of a change to its measured public Pages and sends the movement with the next fix. Starts at It does it, you can stop it.
Tactic row-desk Claims desk answers every claim on a row: re-reads, watches, disputes, removals, read-me requests and badges, each by its own rule. Starts at Sends nothing.
Tactic row-readout Action readout counts the Organizations that act on their row within 30 days against a holdout, and never counts a view. Starts at Sends nothing.
Tactic send-gate-check Send gate check: Checks Suppression, a live reason, the Market, the basis stamp, the Person-month grant, the facts and the labels before any cold Message exists. Starts at Sends nothing.
Tactic cold-email-send Cold email send: Sends a passed draft as plain text from an outbound Mailbox with tracking off, records it with its reason and stamp, and handles bounces. Starts at It does it, you can stop it.
Tactic reply-matrix Reply matrix: Labels every outreach reply with one of 11 labels, maps it to one of seven reply kinds, and runs that kind’s move by its deadline. Starts at You approve each one.
Tactic sending-stop-loss Sending stop loss: Reads the Play’s own bounces, replies and seed tests on every send, and rests, pauses or retires a Mailbox, Domain, cell or the Play. Starts at Sends nothing.
Trigger index-due Index due: at on Monitor.checked, window 7d.
Trigger row-ready Ready row: state on Monitor.checked, window 7d.
Trigger public-change Public change: event on Monitor.checked, window 24h.
Trigger rank-move Rank move: threshold on Monitor.checked, window 3d.
Trigger fix-live Fix live: event on Monitor.checked, window 30d.
Trigger regrade-request Regrade request: event on Form.submitted, window 24h.
Trigger row-dispute Reading dispute: event on Form.submitted, window 2d.
Trigger read-me-request Read-me request: event on Form.submitted, window 24h.
Sequence row-first-touch First touch with the row: 1 steps; it ends on Any reply; A stop or removal; A bounce; Suppression at any scope; An open Deal or Conversation; The Organization becomes a Customer.
Sequence row-first-touch-founder First touch with the row for the founder: 1 steps; it ends on Any reply; A stop or removal; A bounce; Suppression at any scope; An open Deal or Conversation; The Organization becomes a Customer.
Sequence row-movement Movement note: 2 steps; it ends on Any reply; A stop or removal; An open Deal; The Organization becomes a Customer; The 180-day park.
Sequence row-watch Watched movement notes: 2 steps; it ends on Unwatch; A stop or removal.
Sequence top-ten-ask Top ten ask: 2 steps; it ends on A yes; A no; A stop; A bounce; The publication date.
Benchmark self-ranked-list-owner-left-out Self-promotional ranked lists cited in Google AI Overviews without their owner recommended.: 69 % (A search consultant’s analysis of B2B best-software prompts in Google AI Overviews., 2026-06-18).

Compiled, not written: edit the Play record benchmark-rows and its Leaseline run, then regenerate. Every step runs from a sentence or a line of code. In your words: the CRM words you know, and where each lives here.