URL: /plays/benchmark-rows · Id: `play:benchmark-rows`

# 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.

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.

```text title="Set it up · Ask"
Be our SDR for a renewal readiness index: read every property manager’s public pages on how they handle renewals, score them 0 to 100, publish the method and the median, and email each one its own row with one fix it can make for free. Never name anyone outside the top 10, and only with their yes. Show me what’s missing; don’t send.
```

```text title="Run one · Ask"
Hand our latest ready row to the SDR agent and show me what it chose and why. Don’t send.
```

```ts title="Run one · SDK"
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 }
```

```json title="Run one · Response · sample"
{
  "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"
    ],
    "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"
  },
  "actions": [
    {
      "$id": "https://api.sb/leaseline.app/actions/action_1",
      "$type": "Action",
      "status": "done",
      "mode": "try",
      "by": "worker_2",
      "verb": "Monitor.check",
      "checks": [
        {
          "check": "fresh-reading",
          "status": "pass"
        }
      ]
    },
    {
      "$id": "https://api.sb/leaseline.app/actions/action_2",
      "$type": "Action",
      "status": "done",
      "mode": "try",
      "by": "worker_2",
      "verb": "Contact.enrich",
      "checks": [
        {
          "check": "customer-collision",
          "status": "pass"
        }
      ]
    },
    {
      "$id": "https://api.sb/leaseline.app/actions/action_3",
      "$type": "Action",
      "status": "pending",
      "reason": "awaitingTime",
      "mode": "try",
      "by": "worker_2",
      "verb": "Message.schedule",
      "checks": [
        {
          "check": "owned-by-a-person",
          "status": "pass"
        },
        {
          "check": "number-match",
          "status": "pass"
        },
        {
          "check": "fix-gate",
          "status": "pass"
        },
        {
          "check": "steward-line",
          "status": "pass"
        }
      ]
    }
  ]
}
```

`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 company | Choice | Reason |
| --- | --- | --- |
| Brookstone Rentals: 41 against a median of 58, no notice date on its renewals page | `send-the-row` | a gap, a free fix, and a verified address |
| Calloway Residential: 72, ranked 4th | `ask-to-be-named` | in the top 10: it asks for a yes to name them |
| Northgate Lettings: 49 to 61 after adding online renewal | `send-the-movement` | up 12 points and 21 percentiles |
| Harlow Lettings: “Your reading of our fees page is wrong” | `re-read-it` | a disputed reading |
| Wrenfield Rentals: a Customer | `not-now` | Customers get no row note |

| Worth | Your time | Spend | First signal | Use it when | Instead |
| --- | --- | --- | --- | --- | --- |
| ≈ +$250 ARR a month at 95 rows | 1 h week 1, then 20 min a week | $0.06 per row sent, ~$6 a month | Day 5: first company ships its fix | 300+ companies with public pages, a free fix to show | Under 300: `proof-of-work-outreach` · no free fix: `cold-email` |

**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](/plays/proof-of-work-outreach), as one of its options; this page keeps its own record and URL.

## Start it this week
```bash
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"
```


```json title="The dry run’s 422 · 2026-08-24 · sample"
{
  "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"
    }
  ]
}
```

| Check | Fix (one call) | Your time | Wait |
| --- | --- | --- | --- |
| <a id="check-owned-by-a-person"></a>`owned-by-a-person` · <a id="check-use-when"></a>`use-when` · <a id="check-baseline"></a>`baseline` · pass · pass: 640 companies · warn: 0.8 per 100 (gaps #8) | <Op verb="Metric.query" /> on `row-action-rate` | 1 min | none |
| <a id="check-approved-pages"></a>`approved-pages` · fail: no method page (Not live yet) | <Op verb="Site.publish" /> the method, the aggregate and the top 10 | 25 min | none |
| <a id="check-domain-authenticated"></a>`domain-authenticated` · <a id="check-mailbox-warm"></a>`mailbox-warm` · pass · fail: sdr@ and rows@ warmed 0 of 14 days | <Op verb="Mailbox.warm" /> | 2 min | 14 days |
| <a id="check-role-unstaffed"></a>`role-unstaffed` · warn (gaps #8): no AE, so replies come to you | <Op verb="Role.staff" />, or leave it | 0 min | none |

`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 (<Op verb="Contact.enrich" />). That comes to about $6 a month at 95 rows and a weekly re-read.

## When it starts
| When | Trigger id | Starts on | Window | How it gets in |
| --- | --- | --- | --- | --- |
| A row passes the gap floor and the fix test, with a verified address | `row-ready` | `state` on `Monitor.checked` where gap over the floor, a reproducible fix, and a verified address for the owning role | the note within 1 d; dropped after 7 d | the weekly <Op verb="Monitor.check" /> |
| A re-read moves a company up by a real change | `rank-move` | `threshold` on `Monitor.checked` where value moved by the smallest real change, and percentile by 5 points or more | the note within 24 h, or dropped | the same |
| A company asks for a re-read | `regrade-request` | `event` on `Form.submitted` where form = 'regrade', from the row Page or a reply | within 24 h | the row page’s Form, through <Op verb="Form.create" /> |
| + 5 more for index dates, public changes, live fixes, disputes and read-me requests (`?lanes=all`) | | | | |

```json title="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"
  }
}
```

```bash title="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.

| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
| --- | --- | --- | --- | --- | --- |
| Send their row · Send the movement | It does it, you can stop it | 25 of 25 approved unedited, then 166 of 166 | met on day 19 (the first 25 rows); capped here | a `dispute` or `removal` Stop → You approve each one | <Op verb="Action.cancel" /> inside the hold |
| Send it as you · Ask to be named | You approve each one, on every rung | 6 of 6 · 10 of 10 | never | — | <Op verb="Approval.approve" /> · <Op verb="Approval.refuse" /> |
| Re-read it | It does it; a changed score waits for you | 4 re-read, 1 changed and approved | — | — | <Op verb="Approval.approve" /> |
| Not now | It does it | 389 held | — | — | <Op verb="Action.redirect" /> |
| Never: a low scorer named in public, a number no reading holds, the index without you named as its steward | To a person, every time | 1 refused, 0 sent | never | — | <Op verb="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 <Op verb="Message.schedule" />, <Op verb="Monitor.check" />, and any other call becomes an Approval under the Role’s Mandate.

```md title="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.

```bash
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
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
| --- | --- | --- | --- | --- | --- |
| Send their row `send-the-row` | a gap, a free fix and a verified address | Agent’s call, with its reason | `row-first-touch` → `row-watch` for those who claim the row | on reply, <Op verb="Task.assign" /> → AE · Priya Shah, due 60 min · Take this one | you, within 60 min |
| Send it as you `send-as-you` | over 500 units | Your rule (line 6) | `row-first-touch-founder` from dana@, after your OK | you approve each one · Take this one | you |
| Ask to be named `ask-to-be-named` | in the top 10 | Your rule (line 5) | `top-ten-ask`: one ask for a yes to be named | nobody | the same |
| Send the movement `send-the-movement` | up by a real change and 5+ percentiles | Your rule (the movement Limit) | `row-movement`: one note per 30 days, upward only | nobody | the same |
| Re-read it `re-read-it` | a re-read request or a dispute | Agent’s call, with its reason | <Op verb="Monitor.check" /> twice, 24 h apart; a changed score waits for you | you, due 2 business days · Take this one | you |
| Not now `not-now` | no fix, under the floor, a Customer or open Deal, or no address | Your rule (the send list) | nothing; the company stays in the index and its aggregate | nobody | the same |

| When they write back | Fixture reply | What happens | Who answers | By when | Call |
| --- | --- | --- | --- | --- | --- |
| 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 min | <Op verb="Meeting.book" /> |
| Send me pricing | “What does Leaseline cost for 180 units?” | answers with the Pricing Page’s list Price and one next step | SDR · your agent | 5 min | <Op verb="Conversation.answer" /> |
| Not now | “Interesting. Maybe after year-end.” | no further note but one upward movement; the row page stays theirs | SDR · your agent | at once | <Op verb="Lead.nurture" /> |
| Wrong person | “Our web team owns that page.” | asks them to forward the row; it never writes to a name from their text | SDR · your agent | 1 business day | <Op verb="Conversation.answer" /> |
| Out of office | an auto-reply until Nov 4 | any movement note waits for the return date, and drops if 24 h pass after a re-read | nobody | the return date | <Op verb="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 can | you | 1 business day | <Op verb="Conversation.escalate" /> |
| Stop | “Remove us from your index.” | no note sends, and their row leaves every output; the aggregate re-runs without them | nobody | at once | <Op verb="Suppression.create" /> |

## 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).

```json title="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 <Op verb="Task.claim" /> (Take this one), <Op verb="Task.return" /> with a reason, <Op verb="Action.redirect" />, <Op verb="Approval.approve" /> or <Op verb="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 <Op verb="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:** <Op verb="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) | Refuses | Fix | Then |
| --- | --- | --- | --- |
| `owned-by-a-person` (rule j; Not live yet, gaps #8) | a row note to a Contact whose Lead or open Deal a person owns | Leave it to the person who owns it: the draft waits in their queue. | <Op verb="Task.assign" /> |
| <a id="check-number-match"></a>`number-match` | a number in a row, note or post that matches no stored reading | Use the stored reading, or re-read the page first. | <Op verb="Monitor.check" /> |
| <a id="check-fresh-reading"></a>`fresh-reading` | a note that states a reading over 7 days old | Re-read the company; the note waits for it. | <Op verb="Monitor.check" /> |
| <a id="check-fix-gate"></a>`fix-gate` | a row with no fix anyone can reproduce, or a gap under the smallest real change | Leave it in the index; it gets no note. | <Op verb="Decision.list" /> |
| <a id="check-named-score"></a>`named-score` | public text that names a company outside the top 10, or one with no yes on file | Show the aggregate only, or ask the top 10 for their yes. | <Op verb="Message.schedule" /> |
| <a id="check-cell-floor"></a>`cell-floor` | a published group of fewer than 10 companies | Merge it into a larger group, or cut it. | <Op verb="Page.update" /> |
| <a id="check-self-exclusion"></a>`self-exclusion` | an index that includes you, your other Startups or a named rival | Drop them from the census and re-run it. | <Op verb="Monitor.check" /> |
| <a id="check-steward-line"></a>`steward-line` | a page, chart, file or note that omits that you run the index and sell in the category | Keep the fixed steward line on every output. | <Op verb="Page.update" /> |
| <a id="check-method"></a>`method` | any reading or note under a method that fails a method check | Fix the method page; nothing reads until it passes. | <Op verb="Site.publish" /> |
| <a id="check-movement-limit"></a>`movement-limit` | a 2nd movement note in 30 days, a downward one, or one after 3 unanswered | Wait for the window; downward moves never send. | <Op verb="Message.schedule" /> |
| <a id="check-late-note"></a>`late-note` | a movement note more than 24 h after its re-read | It drops; the next re-read starts a new one. | <Op verb="Monitor.check" /> |

| Stop (pauses the Play) | Pauses when | Then |
| --- | --- | --- |
| <a id="stop-collection-fence"></a>`collection-fence` | a request outside public pages or the rate Limit | collection halts until you review it |
| <a id="stop-unreadable"></a>`unreadable` | over 10 % of companies cannot be read | the index and every row hold |
| <a id="stop-dispute"></a>`dispute` | upheld disputes pass 2 % of rows in 30 days, after 100 | row notes pause and the method returns to you |
| <a id="stop-removal"></a>`removal` | removal asks pass 3 % of rows delivered, after 100 | row notes pause |
| <a id="stop-row-action-floor"></a>`row-action-floor` | under 3 acting per 100 after 300 delivered | row notes stop; the index keeps publishing |
| <a id="stop-sending-stop-loss"></a>`sending-stop-loss` | bounces, complaints, spam placement or a blocklist hit pass their lines | that Mailbox pauses; <Op verb="Mailbox.rest" /> |
| <a id="stop-kill-switch"></a>`kill-switch` | you press it | every Tactic pauses; <Op verb="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.

```json title="The captured refusal · sample"
{
  "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"
    }
  ]
}
```


```json title="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 <Op verb="Metric.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`

| Node | Agent half | Your half | Added | Confidence | Basis |
| --- | --- | --- | --- | --- | --- |
| `row-action-rate` | 13.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 tell | held back at random · n 169 matured · 43 still maturing · Other Startups’ results +9.2, ■■□□ Early sign, n 2,870 |
| `new-leads` | 5.9 per 100 (9 of 152) | 0 (0 of 17) | +5.9 [−1.4, +13.2] | ■□□□ Too early to tell | the 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 tell | carried 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.

```json title="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 option | Decisions | Done | Acting companies (what happened) |
| --- | --- | --- | --- |
| Send their row · Send it as you | 185 · 6 | 185 sent, 3 bounced · 6 sent | 20 · 1 |
| Ask to be named · Send the movement | 10 · 9 | 6 said yes · 9 sent | — · 4 replied |
| Re-read it · Not now | 4 · 389 | 1 score changed · held | — |
| **Sent** · held back | **191** · 21 | **188** delivered | **21** of 152 matured · 1 of 17 |
| At 300 companies (the Use it when volume) | about 90 rows | held back at random; pools at 30 days | Other Startups’ results: +9.2 per 100, ■■□□ Early sign, n 2,870 |

| Day | Event | What happened | Your time |
| --- | --- | --- | --- |
| 0 | `event_1121` Campaign.created | the method from 7 parts; the dry run fails `approved-pages` and `mailbox-warm` | 35 min |
| 1 | `event_1127` Site.published | the method page, the median and the top 10’s empty slots | 25 min |
| 3 | `event_1139` Message.created, first of 10 | the top-10 asks; 6 said yes by day 9 | 10 min |
| 14 | `event_1191` Mailbox.warmed | the first rows sent, 25 a day across 2 Mailboxes | — |
| 19 | `event_1218` Role.updated | promoted after 25 rows approved unedited: rows send after a 2-minute hold | — |
| 20 | `event_1222` Monitor.checked | the first fix live: Northgate added its notice date | — |
| 29 | `event_1297` Campaign.paused | `sending-stop-loss` on rows@: 2.3 % bounces; rested a day, resumed | 5 min |
| 1–56 | `event_1140` Task.created, first of 20 | approvals, re-reads and the weekly memo, from the <Op verb="Task.next" /> log | 1.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).

```diff title="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
```mdx title="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 | <a id="tactic-index-method"></a>`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 | <a id="tactic-niche-census"></a>`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 | <a id="tactic-public-reading"></a>`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 | <a id="tactic-fix-finder"></a>`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 | <a id="tactic-index-publish"></a>`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 | <a id="tactic-top-ten-consent"></a>`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 | <a id="tactic-row-send"></a>`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 | <a id="tactic-change-watch"></a>`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 | <a id="tactic-row-desk"></a>`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 | <a id="tactic-row-readout"></a>`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 | <a id="tactic-send-gate-check"></a>`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 | <a id="tactic-cold-email-send"></a>`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 | <a id="tactic-reply-matrix"></a>`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 | <a id="tactic-sending-stop-loss"></a>`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 | <a id="trigger-index-due"></a>`index-due` | Index due: `at` on `Monitor.checked`, window 7d. |
| Trigger | <a id="trigger-row-ready"></a>`row-ready` | Ready row: `state` on `Monitor.checked`, window 7d. |
| Trigger | <a id="trigger-public-change"></a>`public-change` | Public change: `event` on `Monitor.checked`, window 24h. |
| Trigger | <a id="trigger-rank-move"></a>`rank-move` | Rank move: `threshold` on `Monitor.checked`, window 3d. |
| Trigger | <a id="trigger-fix-live"></a>`fix-live` | Fix live: `event` on `Monitor.checked`, window 30d. |
| Trigger | <a id="trigger-regrade-request"></a>`regrade-request` | Regrade request: `event` on `Form.submitted`, window 24h. |
| Trigger | <a id="trigger-row-dispute"></a>`row-dispute` | Reading dispute: `event` on `Form.submitted`, window 2d. |
| Trigger | <a id="trigger-read-me-request"></a>`read-me-request` | Read-me request: `event` on `Form.submitted`, window 24h. |
| Sequence | <a id="sequence-row-first-touch"></a>`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 | <a id="sequence-row-first-touch-founder"></a>`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 | <a id="sequence-row-movement"></a>`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 | <a id="sequence-row-watch"></a>`row-watch` | Watched movement notes: 2 steps; it ends on Unwatch; A stop or removal. |
| Sequence | <a id="sequence-top-ten-ask"></a>`top-ten-ask` | Top ten ask: 2 steps; it ends on A yes; A no; A stop; A bounce; The publication date. |
| Benchmark | <a id="benchmark-self-ranked-list-owner-left-out"></a>`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). |