URL: /plays/aeo · Id: `play:aeo`

# Answer engine optimization

> Keeps the facts AI answers repeat about you true and dated, at home and at each cited source, and counts how often they name you.

Keeps the facts AI answers repeat about you true and dated, at home and at each cited source, and counts how often they name you.

```text title="Set it up · Ask"
Be our Content Lead for AI answers: find the 40 questions property managers ask ChatGPT, Perplexity, Gemini, Claude and Google about tools like ours, make sure every fact they repeat about Leaseline is true and dated, and ask any page that gets us wrong to fix it, after my OK. Show me what’s missing; don’t publish.
```

```text title="Run one · Ask"
Hand the latest wrong answer about us to the Content Lead 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", "Change.merged", "Keyword.measured", "Page.fetched")', 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_462",
    "$type": "Decision",
    "choice": "ask-the-source",
    "reason": "a roundup page by someone else, cited on 5 of the 40 questions, lists Pro at $39 a month; your Pricing Page says $29",
    "stakes": "low",
    "options": [
      "publish-the-answer",
      "fix-your-page",
      "ask-the-source",
      "update-the-comparison",
      "not-now",
      "let-it-go"
    ],
    "by": "worker_7",
    "on": "source_17",
    "expected": "answers on those 5 questions quote $29 within 2 weekly runs",
    "reopensWhen": "source_17 still states $39 at the run after next"
  },
  "actions": [
    {
      "$id": "https://api.sb/leaseline.app/actions/action_1",
      "$type": "Action",
      "status": "done",
      "mode": "try",
      "by": "worker_7",
      "verb": "Monitor.check",
      "checks": []
    },
    {
      "$id": "https://api.sb/leaseline.app/actions/action_2",
      "$type": "Action",
      "status": "done",
      "mode": "try",
      "by": "worker_7",
      "verb": "Contact.enrich",
      "checks": [
        {
          "check": "customer-collision",
          "status": "pass"
        }
      ]
    },
    {
      "$id": "https://api.sb/leaseline.app/actions/action_3",
      "$type": "Action",
      "status": "pending",
      "reason": "awaitingApproval",
      "mode": "try",
      "by": "worker_7",
      "verb": "Message.schedule",
      "checks": [
        {
          "check": "owned-by-a-person",
          "status": "pass"
        },
        {
          "check": "correction-cap",
          "status": "pass"
        },
        {
          "check": "contact-lease",
          "status": "pass"
        },
        {
          "check": "fact-check",
          "status": "pass"
        }
      ]
    }
  ]
}
```

`action_3` is the correction to the roundup’s editor, which waits for your OK (You approve each one); it cites your Pricing Page and the date its Price changed.

`+8.2 per 100 answers · ■■□□ Early sign · n 900 runs · path → arr`

| Try another: the answer | Choice | Reason |
| --- | --- | --- |
| Perplexity: a roundup page says Leaseline Pro is $39 a month | `ask-the-source` | someone else’s page, cited on 5 questions |
| ChatGPT: “Leaseline has no owner statements” on 3 questions | `fix-your-page` | your setup page says it, but only inside a tab |
| Google: no source names a tool for 60-day renewal notices | `publish-the-answer` | a buyer question no page answers |
| Gemini: the whole panel shifted on Oct 2 | `not-now` | a model release froze the series |

| Worth | Your time | Spend | First signal | Use it when | Instead |
| --- | --- | --- | --- | --- | --- |
| ≈ +$90 ARR a month at 40 questions | 45 min week 1, then 20 a week | $0.02 per panel run, ~$50 a month | Week 3: an answer cites your own page | a Pricing Page, 20+ buyer questions | No Pricing Page: publish it (<Op verb="Site.publish" />) · under 20 questions: `signup-interviews` |

**Where it sits:** **Stranger** → Lead → Trialing → Activated → At risk → Churned → Won back · Answer share → People reached → New Customers ↑ → ARR added each week → ARR

Worth’s formula: about +8.2 per 100 answers × 15 AI-sent visits a month per point × 1.9 % visits to Leads × 0.30 Leads to opens × 0.29 opens to paid × $420 first order ARR ≈ +$85. Under First signal: About 6 weeks to tell a +6 point lift at 15 questions a half and 450 runs a week; a model release adds 2 weeks to rebuild the baseline.

`sample · api.sb/leaseline.app · 41 Customers at 2026-10-19 · on Monitor.checked · first answer citing your page in week 3 · 4 keys Not live yet`

## Start it this week
```bash
npx startup-builder add play aeo   # 1 · writes plays/aeo.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":"aeo"}'

# 3 · keep it: pages publish from your records, corrections wait for you
curl -X POST https://api.sb/leaseline.app/campaigns \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"play":"aeo"}'

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

# off: pages stay up, queued corrections cancel
curl -X POST https://api.sb/leaseline.app/processes/content-marketing/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": "aeo can’t start yet: 1 check fails and 1 warns.",
  "checks": [
    {
      "check": "owned-by-a-person",
      "status": "pass",
      "observed": "0 source editors are Contacts a person owns",
      "doc": "/plays/aeo#check-owned-by-a-person",
      "then": "Task.assign"
    },
    {
      "check": "use-when",
      "status": "pass",
      "observed": "a Pricing Page and 40 questions from 12 signup interviews",
      "doc": "/plays/aeo#check-use-when",
      "then": "Metric.query"
    },
    {
      "check": "baseline",
      "status": "warn",
      "observed": "no panel history: week 1 is the baseline",
      "doc": "/plays/aeo#check-baseline",
      "fix": "Run the panel once; the first week fills Before.",
      "then": "Metric.query"
    },
    {
      "check": "approved-pages",
      "status": "fail",
      "doc": "/plays/aeo#check-approved-pages",
      "fix": "Put every Price and Limit in your Pricing Page’s text, not inside a tab.",
      "then": "Site.publish"
    },
    {
      "check": "domain-authenticated",
      "status": "pass",
      "observed": "leaseline.app: 3 of 3 records resolve",
      "doc": "/plays/aeo#check-domain-authenticated",
      "then": "Domain.authenticate"
    },
    {
      "check": "role-unstaffed",
      "status": "pass",
      "observed": "Content Lead and Marketing Lead are your agents; comparisons and corrections come to you",
      "doc": "/plays/aeo#check-role-unstaffed",
      "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` · pass: 0 owned; 40 questions (gaps #8) | <Op verb="Metric.query" /> on `answer-share` | 1 min | none |
| <a id="check-baseline"></a>`baseline` · warn: no history | <Op verb="Monitor.check" /> runs the panel; week 1 fills Before in Your number | 0 min | 7 days |
| <a id="check-approved-pages"></a>`approved-pages` · fail: the Team Limit sits inside a tab (Not live yet) | <Op verb="Site.publish" /> the Pricing Page with the table in its text | 20 min | none |
| <a id="check-domain-authenticated"></a>`domain-authenticated` · <a id="check-role-unstaffed"></a>`role-unstaffed` · pass · pass (gaps #8) | — | 0 min | none |

`Your number · Before 6.1 per 100 answers · Now 14.2 on the 15 changed · Target 20 by Dec 31 · ■■□□ Early sign · n 900 runs · held back at random`

Each panel run costs $0.02 (600 a week: 40 questions × 5 Venues × 3 samples), and each drafted page or correction costs $0.05 from your Domain (Worker cost). Contact data for a source editor costs $0.06 (<Op verb="Contact.enrich" />). That comes to about $50 a month at 40 questions, and a Limit cuts samples from 3 to 2 at $60.

## When it starts
| When | Trigger id | Starts on | Window | How it gets in |
| --- | --- | --- | --- | --- |
| The weekly panel run is due | `panel-week` | `at` on `Monitor.checked` where 7 days after the panel's last check | 7 d after the last check | <Op verb="Monitor.check" /> on the locked panel |
| An answer contradicts one of your facts | `misstatement-found` | `event` on `Monitor.checked` where an answer contradicts a fact record | queued the same run; ignored after 28 d | the panel run itself |
| A Price, Offer, Limit or integration changes | `fact-changed` | `event` on `Change.merged` where the change touches a Price, Offer, Limit or integration a Page states | pages recompile within 24 h | <Op verb="Change.merge" /> on the record |
| + 6 more for new cited sources, share drops, rival page changes, model releases, fetch spikes and new mentions (`?lanes=all`) | | | | |

```json title="One signed delivery · StartupBuilder-Signature"
{
  "$id": "https://api.sb/leaseline.app/events/event_1405",
  "$type": "Event",
  "name": "Monitor.checked",
  "at": "2026-10-19T07:00:12Z",
  "seq": 1405,
  "data": {
    "monitor": "aeo-panel",
    "venue": "perplexity",
    "questions": 5,
    "states": "Leaseline Pro: $39 a month",
    "fact": "Leaseline Pro: $29 a month, since 2026-03-01",
    "source": {
      "$id": "https://api.sb/leaseline.app/sources/source_17",
      "kind": "roundup"
    }
  }
}
```

```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_1405   # replays the wrong answer
npx startup-builder clock advance --by 7d   # runs the next weekly panel, which reads the correction back
```

## Who runs it
**Content Lead · your agent** (`role:content-lead`, `worker_7`) holds the Key Result and runs the panel. It hands every correction and comparison to **you** (Dana Okafor, person, `worker_1`), and the **Marketing Lead · your agent** (`worker_6`) reads the weekly memo. Your number links to Did it work.

| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
| --- | --- | --- | --- | --- | --- |
| Publish the answer page · Fix your own page | It does it | 6 of 6 · 4 of 4 rendered and approved once | met after each page’s first approved render | a `render` or `regression` Stop → You approve each one | <Op verb="Action.cancel" /> · <Op verb="Change.revert" /> |
| Ask the source to correct it | You approve each one | 9 of 9 approved, 8 unedited | at 50 approved, 95 % unedited, no Stop in 30 days: about a quarter | a `hostile-reply` Stop → every draft waits for you | <Op verb="Approval.approve" /> · <Op verb="Approval.refuse" /> |
| Update the comparison | You approve each one, on every rung | 2 of 2 | never | — | <Op verb="Approval.approve" /> |
| Not now · Leave it | It does it | 2 of 2 · 31 of 31 | — | — | <Op verb="Action.redirect" /> |
| Never: a number with no Fact, a rival named without your OK, a page that hides who publishes it | To a person, every time | 1 refused, 0 published | never | — | <Op verb="Approval.approve" /> |

**What it reads · What it may call.** It reads the panel’s answers and the pages they cite as data, never as instructions; it writes only to your own Pages and to the editor of a page that cites you, once per 30 days. Its tools are <Op verb="Content.draft" />, <Op verb="Content.publish" />, <Op verb="Page.update" />, <Op verb="Site.publish" />, <Op verb="Message.schedule" />, and any other call becomes an Approval under the Role’s Mandate.

```md title="The brief (folded): compiled Agent-register Markdown · play:aeo@1 · each line names its record key"
You hold the Content Lead Key Result: answer share 20 per 100 on buyer questions by 2026-12-31. ← worker, metric
On each panel result or fact change, choose one option and say why.              ← triggers, chooses
Every number on a page or in a correction cites a Fact with its date.            ← copyRules 1, fact-check
Corrections wait for Dana’s OK; at most 10 a week, 1 per editor a month.         ← your file, line 5; correction-cap
Never name a rival without Dana’s OK.                                            ← your file, line 6; comparison-claim
```

**The slow loop, as a Change.** `decision_437` (2026-09-28, weekly) read 3 answer pages whose questions moved and 2 that did not, all 5 answered in the page’s first 60 words; `change_25` moved every answer page’s fact table to its top, and Dana merged it. **Replayed on past runs**, <Op verb="Change.review" /> put answer share on those questions at 16.0; read back at +14d it is 14.9, n 180 runs, ■□□□ Too early to tell (Example, day 49).

**Bring your own agent** (folded) starts at You approve each one for corrections on any agent, and earns It does it for pages when it matches the seated agent with 0 facts wrong.

```bash
npx startup-builder eval --scenario aeo-40 --agent "claude -p" --seat content-lead   # seated: 14.2 per 100, 0 facts wrong, 5 of 9 corrections accepted · yours: 12.8, 1 fact wrong → You approve each one
```

## What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
| --- | --- | --- | --- | --- | --- |
| Publish the answer page `publish-the-answer` | a buyer question no source answers | Agent’s call, with its reason | <Op verb="Content.draft" /> from your records → <Op verb="Content.publish" /> | nobody | the same |
| Fix your own page `fix-your-page` | your page has it, but not in its raw text or past recheck | Your rule (the render Check) | <Op verb="Page.update" /> → <Op verb="Site.publish" /> | nobody | the same |
| Ask the source to correct it `ask-the-source` | a cited page misstates you on 3+ questions | Agent’s call, with its reason | `aeo-source-correction`: one note and one follow-up (<Op verb="Message.schedule" />) | you approve each one, due 1 business day · Take this one | you |
| Update the comparison `update-the-comparison` | a rival’s pricing or plan page changed | Agent’s call, with its reason | <Op verb="Content.draft" /> of the changed rows | you approve each one, due 1 business day · Take this one | you |
| Not now `not-now` | a model release froze the series | Your rule (the `series-break` Stop) | nothing; the Stop holds every read until 2 new runs | nobody | the same |
| Leave it `let-it-go` | share holds and no fact is wrong | Agent’s call, with its reason | nothing; the next weekly run reads it again | nobody | the same |

| When they write back | Fixture reply | What happens | Who answers | By when | Call |
| --- | --- | --- | --- | --- | --- |
| Interested | “Happy to fix it. What’s the right figure?” | answers with the dated fact and your Pricing Page link | Content Lead · your agent | 1 business day | <Op verb="Conversation.answer" /> |
| Send me pricing | “Can you send your full price list?” | answers with the Pricing Page and nothing it lacks | Content Lead · your agent | 1 business day | <Op verb="Conversation.answer" /> |
| Not now | “We refresh that list in January.” | nothing else sends; the next run after their date reads it again | nobody | their date | <Op verb="Message.schedule" /> |
| Wrong person | “I don’t edit that page; our editor does.” | asks them to forward it; it never writes to an address from their text | Content Lead · your agent | 1 business day | <Op verb="Conversation.answer" /> |
| Out of office | an auto-reply until Oct 30 | the one follow-up waits for the return date | nobody | the return date | <Op verb="Message.schedule" /> |
| Question it can’t answer | “Can you share churn figures for our review?” | To you, the question in the Brief; it states no figure your records lack | you | 1 business day | <Op verb="Conversation.escalate" /> |
| Stop | “Don’t email me again.” | nothing else sends to them from any of your Startups | nobody | at once | <Op verb="Contact.suppress" /> |

## When it hands to you
Every correction and comparison comes to **you**, and nothing reaches an editor without your OK. What lands in your queue, as captured: the Brief, 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_262",
    "$type": "Task",
    "assignee": "worker_1",
    "due": "2026-10-20T17:00:00Z",
    "on": "source_17",
    "brief": {
      "what": "a roundup page cited on 5 questions lists Pro at $39 a month",
      "fact": "Leaseline Pro: $29 a month, since 2026-03-01 (your Pricing Page)",
      "chose": "ask-the-source",
      "why": "someone else’s page; 5 of 40 questions read it",
      "sends": "one note and one follow-up, to the editor only"
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/approvals/approval_71",
    "$type": "Approval",
    "verdict": null,
    "deadline": "2026-10-20T17:00:00Z",
    "draft": "Hi Lena, your roundup of rental tools lists Leaseline Pro at $39 a month. It has been $29 since March 1…",
    "route": "ask-the-source",
    "checks": [
      {
        "check": "fact-check",
        "status": "pass"
      },
      {
        "check": "correction-cap",
        "status": "pass"
      }
    ]
  }
]
```

You answer with <Op verb="Task.claim" /> (Take this one), <Op verb="Task.return" /> with a reason, <Op verb="Approval.approve" /> or <Op verb="Approval.refuse" />, each a one-call window, and an Approval unanswered by its deadline expires and the note never sends. Once you claim a correction, the agent stops writing to that editor, and every reply comes to your queue.

**On time:** you, 11 of 12 approvals by their deadline, median 3 h 10 min, ■■□□ Early sign, n 12 (the 12th expired, and that note never sent). **Your queue:** counted by kind: in week 1, 1 panel lock and 1 Pricing Page fix; since, about 2 corrections a week and 1 comparison a month.

**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 correction to an editor 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-fact-check"></a>`fact-check` | a page or correction with a number or claim no Fact backs | Cut the claim, or name the record that backs it. | <Op verb="Content.draft" /> |
| <a id="check-stale-fact"></a>`stale-fact` | a Fact past its recheck date, on every page that states it | Recheck the Fact; the page returns once it passes. | <Op verb="Page.update" /> |
| <a id="check-correction-cap"></a>`correction-cap` | an 11th correction in a week, or a 2nd to one editor in 30 days | Wait for the window; the queue keeps its order. | <Op verb="Message.schedule" /> |
| <a id="check-contact-lease"></a>`contact-lease` | a note to an editor another of your Startups wrote to in 30 days | Leave it; the lease ends after 30 days. | <Op verb="Decision.list" /> |
| <a id="check-comparison-claim"></a>`comparison-claim` | a changed claim about a named rival without your OK | Approve the changed rows, or cut them. | <Op verb="Approval.approve" /> |
| <a id="check-ownership-stated"></a>`ownership-stated` | a comparison page that omits that you publish it and are one of the compared | Keep the fixed ownership line at the top. | <Op verb="Page.update" /> |

| Stop (pauses the Play) | Pauses when | Then |
| --- | --- | --- |
| <a id="stop-render"></a>`render` | a page’s raw text lacks a Price, Limit or Fact it shows | publishing holds; <Op verb="Site.publish" /> once it passes |
| <a id="stop-crawler"></a>`crawler` | an answer engine’s crawler is blocked on one of your pages | <Op verb="Issue.create" />; that page’s panel results read suspect |
| <a id="stop-hostile-reply"></a>`hostile-reply` | 2 hostile replies or block asks in 30 days | corrections pause; each sender is suppressed |
| <a id="stop-series-break"></a>`series-break` | a model release, or the whole panel moving past 3 intervals in a week | reads and tests freeze until 2 new runs |
| <a id="stop-regression"></a>`regression` | a page change followed by a fall past the interval for 3 weeks | <Op verb="Change.revert" /> on that change |
| <a id="stop-spend-limit"></a>`spend-limit` (the panel budget) | panel spend reaches its $60 Limit | samples drop from 3 to 2; <Op verb="Limit.raise" /> with your OK |
| <a id="stop-kill-switch"></a>`kill-switch` | you press it | every Tactic pauses, pages stay up, queued corrections cancel; <Op verb="Process.enable" /> after review |

The captured refusal, then the Stops that fired as `Campaign.paused` reasons (Not live yet, gaps #2); the rewrite that sent is the second thread in Example.

```json title="The captured refusal · sample"
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "The correction to the roundup editor did not send: it states a figure no Fact backs.",
  "checks": [
    {
      "check": "fact-check",
      "status": "fail",
      "doc": "/plays/aeo#check-fact-check",
      "fix": "Cut the claim, or name the record that backs it.",
      "then": "Content.draft"
    },
    {
      "check": "correction-cap",
      "status": "pass"
    }
  ]
}
```


```json title="The Stops that fired, as Campaign.paused reasons · sample"
[
  {
    "reason": {
      "limit": "render",
      "observed": "the Team Limit missing from the raw text of /pricing",
      "bound": "0 missing",
      "window": "1 publish"
    },
    "doc": "/plays/aeo#stop-render"
  },
  {
    "reason": {
      "limit": "series-break",
      "observed": "the whole panel moved 3.4 intervals after a Gemini model release",
      "bound": "3 intervals",
      "window": "1 week"
    },
    "doc": "/plays/aeo#stop-series-break"
  }
]
```

## Did it work
The 30 buyer questions were split at random, 15 whose pages changed and 15 held back, and both halves read from the same weekly runs (rules m–o); each figure’s call is <Op verb="Metric.query" /> by node and by arm. `answer-share` and every node above it are Not live yet (gaps #4, #6).

`+8.2 per 100 answers · ■■□□ Early sign · n 900 runs · path → arr`

| Node | Agent half | Your half | Added | Confidence | Basis |
| --- | --- | --- | --- | --- | --- |
| `answer-share` | 14.2 per 100 answers (64 of 450 runs) | 6.0 held back (27 of 450) | +8.2 [+2.6, +13.8] | ■■□□ Early sign | held back at random by question · n 900 runs, the last 2 weeks · 15 questions a half |
| `icp-reached` | 118 AI-sent visits | 71 | +47 [−8, +102] · Not carrying up yet | ■□□□ Too early to tell | the same split, visits landing on each half’s pages |
| `new-arr` ↑ | $347, 1 Customer on Pro · Booked: credited, not all caused by this Play | $0 | +$347 [−$340, +$1,030] · Worth about +$90 a month | ■□□□ Too early to tell (1 vs 0 Customers) | the same · 2 trials still deciding |
| `net-new-arr` · `arr` | +$347 | $0 | +$347, carried: it moves no other bridge term | ■□□□ Too early to tell | carried from `new-arr` |

The leaf counts panel runs whose answer cites or names Leaseline, per 100 runs, per Venue, buyer questions and branded questions apart; the 10 branded questions read accuracy, not share. The series froze for 2 weeks after the Oct 2 model release (`series-break`).

**How it moves it:** branded answers that quote $29 for Pro rose from 109 of 150 runs in week 1 to 147 of 150 in week 8, and 5 of 9 corrected pages now state the dated fact.

**Guardrails:** treated against held back: `organic-share` of visits, 31 % against 30 %, and `earned-mentions`, 4 against 3.

```json title="The Campaign card · sample"
{
  "$id": "https://api.sb/leaseline.app/campaigns/aeo",
  "$type": "Campaign",
  "play": "play:aeo@1",
  "path": [
    "answer-share",
    "icp-reached",
    "new-arr",
    "net-new-arr",
    "arr"
  ],
  "experiment": {
    "metric": "answer-share",
    "unit": "per-100",
    "heldBack": 15,
    "decision": null
  },
  "readout": {
    "value": 8.2,
    "n": 900,
    "maturing": 0,
    "interval": [
      2.6,
      13.8
    ],
    "readability": "C",
    "basis": "held-back",
    "pooled": false
  },
  "ledger": {
    "spend": 92,
    "workerCost": 6,
    "hours": 3.4,
    "wonArr": 347,
    "projectedArr": 85,
    "paybackDays": 270
  }
}
```

Outside benchmark: a brand list repeats in under 1 in 100 runs of the same question across answer engines (a 2026 study of 2,961 runs).

**Before it · After it.** Before it: `signup-interviews` gives it the questions buyers ask, and `editorial-seo` writes the long pages it cites. After it: `directory-listings` takes a wrong review profile, `community-answers` takes a cited forum thread, and `instant-response` answers anyone the answers send.

## Example
Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days). The panel held 40 questions: 30 a property manager asks and 10 with Leaseline’s name, each run weekly on 5 Venues, 3 samples apiece, 4,800 runs in all. Week 1 read 6.1 answers per 100 naming Leaseline on buyer questions, and 41 of 150 branded runs quoted $39 for Pro. Read every captured run at `?threads=all`; three follow the tables.

| What happened, by option | Decisions | Done | Read back (what happened) |
| --- | --- | --- | --- |
| Publish the answer page · Fix your own page | 6 · 4 | 6 published · 4 fixed | 7 of the 10 cited within 3 runs |
| Ask the source to correct it | 9 | 9 approved, 5 corrected | 5 pages state $29 now |
| Update the comparison · Not now · Leave it | 2 · 2 weeks · 31 | 2 approved · 2 runs frozen · — | — |
| **Changed questions** · held back | **15** · 15 | **14.2** per 100 answers · 6.0 | **$347** · $0 (credited, not all caused by this Play) |
| At 20 questions (the Use it when volume) | about 10 a half | held back at random, about 10 weeks to read | Other Startups’ results: +5.1 per 100, ■■□□ Early sign, n 31 panels |

| Day | Event | What happened | Your time |
| --- | --- | --- | --- |
| 0 | `event_1106` Campaign.created | 40 questions locked; the dry run fails `approved-pages` | 30 min |
| 2 | `event_1119` Site.published | the Team Limit moved into the Pricing Page’s text; `render` passes | 20 min |
| 7 | `event_1150` Monitor.checked | week 1: 6.1 per 100 on buyer questions; 41 of 150 branded runs quote $39 | — |
| 14 | `event_1187` Content.published | 3 answer pages, among them 60-day renewal notices per owner | — |
| 16 | `event_1201` Approval.created, first of 12 | the first correction, to the roundup editor | 4 min |
| 21 | `event_1233` Monitor.checked | first answer citing a Leaseline page, on Perplexity | — |
| 35 | `event_1309` Change.merged | fact tables to the top: replayed at 16.0, read back at +14d at 14.9 | 5 min |
| 39 · 53 | `event_1318` Campaign.paused | `series-break` after a Gemini model release; reads resumed after 2 runs | — |
| 1–56 | `event_1124` Task.created, first of 14 | corrections, comparisons and the weekly memo, from the <Op verb="Task.next" /> log | 2.4 h · **total 3.4 h measured, 3.5 h asked** |

> **Leaseline → Lena, editor of a rental-tools roundup, Sep 10** · Your roundup lists Leaseline Pro at $39 a month. It has been $29 since March 1, as our Pricing Page shows.¹ Could you update the row? *Signed with the Role’s disclosure line.*²
>
> **Lena, Sep 11** · “Fixed, thanks.” By the run of Sep 21, 4 of the 5 questions that read her page quoted $29.

```diff title="The roundup correction, 2026-09-10 · the draft fact-check refused, then the rewrite that sent"
- Property managers save about 6 hours a week with Leaseline Pro, which is $29 a month.
+ Leaseline Pro has been $29 a month since March 1, as our Pricing Page shows.
```

> **A rival’s plan page changed, 2026-10-07 07:00** · its renewal reminders moved to its top plan. Update the comparison drafted the 2 changed rows for Dana (`approval_69`, due 17:00 the next day); she approved them at 12:40, and the page kept its fixed ownership line.³ The Brief is `task_249`.

¹ Every number cites a Fact with its date. ² The fixed signature line, compiled from the Role’s disclosure Setting. ³ A comparison names who publishes it, every time.

## Your settings
```mdx title="plays/aeo.mdx"
---
holdout: 0.5      # half the buyer questions keep today’s pages, chosen at random
---
Lock these 40 questions for 6 weeks: 30 a buyer asks, 10 with our name.
Corrections wait for my OK.
Never name a rival without my OK.
```

```text
$ npx startup-builder show plays/aeo
holdout 0.5 · 40 questions · corrections wait · rivals wait    your file  plays/aeo.mdx:2,4,5,6 (Ask 2026-08-24)
family demand · process content-marketing · worker role:content-lead, owns never · chooses 6 (2 rule, 4 read) · sequence aeo-source-correction · approval every-send · checks owned-by-a-person, fact-check, stale-fact, correction-cap, contact-lease, comparison-claim, ownership-stated · stops 7    catalog  play:aeo@1
```

### Every key from the catalog
| Key | Id | What it is |
| --- | --- | --- |
| Tactic | <a id="tactic-prompt-panel-build"></a>`prompt-panel-build` | Prompt panel build: Builds and locks the fixed panel of Customer prompts, branded and non-branded, that the answer-citation Monitor samples each week. Starts at You approve the first wave. |
| Tactic | <a id="tactic-prompt-panel-run"></a>`prompt-panel-run` | Prompt panel run: Samples every panel prompt 3 times per answer engine each week, stores the retrieval set, and computes answer share with its interval. Starts at Sends nothing. |
| Tactic | <a id="tactic-retrieval-readiness-check"></a>`retrieval-readiness-check` | Retrieval readiness check: Fetches each Page as answer-engine crawlers do and fails any Page whose shown facts are missing from the raw HTML or blocked from retrieval. Starts at Sends nothing. |
| Tactic | <a id="tactic-vendor-truth-pages"></a>`vendor-truth-pages` | Vendor-truth pages: Compiles the server-rendered pricing, billing terms, Limits, integrations and dated changelog Pages from the Startup’s records within 24 hours of a change. Starts at You approve the first wave. |
| Tactic | <a id="tactic-honest-comparison"></a>`honest-comparison` | Honest comparison: Keeps one comparison Page per named rival, with method, sources, date checked and the rows the rival wins, updated within 24 hours of a change. Starts at You approve each one. |
| Tactic | <a id="tactic-cited-source-queue"></a>`cited-source-queue` | Cited-source queue: Ranks the third-party Pages answer engines cite for the panel, routes each to a fix, sends factual corrections, and records every earned mention. Starts at You approve each one. |
| Tactic | <a id="tactic-citation-cohort-test"></a>`citation-cohort-test` | Citation cohort test: Tests one Page variable a month on a treated cohort against a held-out cohort of matched prompts, and ships only winners into the template. Starts at It does it, you can stop it. |
| Trigger | <a id="trigger-panel-week"></a>`panel-week` | Panel week: `at` on `Monitor.checked`, window 7d. |
| Trigger | <a id="trigger-fact-changed"></a>`fact-changed` | Fact changed: `event` on `Change.merged`, window 24h. |
| Trigger | <a id="trigger-misstatement-found"></a>`misstatement-found` | Misstatement found: `event` on `Monitor.checked`, window 28d. |
| Trigger | <a id="trigger-cited-source-new"></a>`cited-source-new` | Cited source new: `threshold` on `Monitor.checked`, window 28d. |
| Trigger | <a id="trigger-answer-share-drop"></a>`answer-share-drop` | Answer share drop: `threshold` on `Keyword.measured`, window 14d. |
| Trigger | <a id="trigger-rival-page-change"></a>`rival-page-change` | Rival page change: `event` on `Monitor.checked`, window 72h. |
| Trigger | <a id="trigger-model-release"></a>`model-release` | Model release: `event` on `Monitor.checked`, window 7d. |
| Trigger | <a id="trigger-fetch-spike"></a>`fetch-spike` | Fetch spike: `threshold` on `Page.fetched`, window 72h. |
| Trigger | <a id="trigger-mention-earned"></a>`mention-earned` | Mention earned: `event` on `Monitor.checked`, window 28d. |
| Sequence | <a id="sequence-aeo-source-correction"></a>`aeo-source-correction` | Source correction: 4 steps; it ends on A reply; The fix observed in a panel run; An opt-out; A bounce; A hostile reply. |
| Benchmark | <a id="benchmark-aeo-brand-list-repeat"></a>`aeo-brand-list-repeat` | Share of repeated runs of one prompt that return the same brand list: 0–1 % (Brand-recommendation consistency study across 3 answer engines., 2026-01-28). |
| Benchmark | <a id="benchmark-aeo-in-summary-click"></a>`aeo-in-summary-click` | Share of visits that click a link inside an AI summary: 1 % (US search-behavior panel study., 2025-07-22). |
| Benchmark | <a id="benchmark-aeo-referral-share"></a>`aeo-referral-share` | Share of site traffic sent by answer engines: 0.62–0.73 % (100-site traffic study over 12 months, relayed secondhand., 2026-10-22). |
| Benchmark | <a id="benchmark-aeo-own-pricing-cited-first"></a>`aeo-own-pricing-cited-first` | Share of pricing answers that cite the company’s own pricing Page first: 12 % (Pricing-answer study across 6 answer engines., 2026-08-10). |
| Benchmark | <a id="benchmark-aeo-own-pricing-appears"></a>`aeo-own-pricing-appears` | Share of pricing answers where the company’s own pricing Page appears among sources: 46 % (Pricing-answer study across 6 answer engines., 2026-08-10). |
| Benchmark | <a id="benchmark-aeo-pricing-bot-readable"></a>`aeo-pricing-bot-readable` | Share of public pricing Pages fully readable by bots: 74 % (Pricing-answer study across 6 answer engines., 2026-08-10). |
| Benchmark | <a id="benchmark-aeo-mention-correlation"></a>`aeo-mention-correlation` | Spearman correlation of branded web mentions with brand visibility in Google AI Overviews; page count correlates at 0.17: 0.664 ratio (75,000-brand correlation study., 2025-05-26). |
| Benchmark | <a id="benchmark-aeo-self-list-unpicked"></a>`aeo-self-list-unpicked` | Share of self-ranking list citations where Google AI Overviews omit the list owner from its pick: 69 % (Best-software query study in Google AI Overviews., 2026-06-18). |
| Benchmark | <a id="benchmark-aeo-sources-per-answer"></a>`aeo-sources-per-answer` | Sources cited per answer, from ChatGPT (low) to Perplexity (high): 6.88–16.35 count (Citation-selection preprint across 3 answer engines., 2026-04-28). |