Sibling audiences
Shows your cold Ads to Contacts your other Startup collected, after each daily build removes every opt-out, and holds a share back to price it.
- Step
- Earn referrals
- Channel
- Ads and sponsorships
Be our paid media lead: show Leaseline’s best cold Ad, unchanged, to the people our other Startup collected, rebuilt daily with every opt-out removed first. Hold 30 % of them back so we see what it adds, and watch that the other Startup loses no one. $200 a month. Show me what’s missing; don’t spend.
# Not live yet (gaps #2)
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":"sibling-audiences"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'sibling-audiences' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-08-24 · Not live yet, gaps #2
npx startup-builder do Campaign.create --json '{"play":"sibling-audiences"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'sibling-audiences' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-08-24 · Not live yet, gaps #2",
"mode": "try"
}
}application/json{
"type": "https: //startupbuilder.dev/ errors/ refused",
"title": "Refused",
"status": 422,
"detail": "sibling-audiences can’t start yet: 1 check fails and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "your other Startup: 4, 200 Contacts it collected; Lists overlap on small landlords",
"doc": "/plays/ sibling-audiences#check-use-when",
"fix": "Pair with a Startup of yours holding 2, 000 or more Contacts, or run retargeting.",
"then": "Metric.query"
},
…
Hand today’s sister Audience build to the paid media agent and show me what it chose and why. Don’t upload.
curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Schedule.fired%22%2C%20%22Consent.withdrawn%22%2C%20%22Contact.created%22%2C%20%22Order.paid%22%2C%20%22Subscription.canceled%22%2C%20%22Offer.published%22%2C%20%22Startup.graduated%22%2C%20%22Complaint.filed%22%2C%20%22Audience.resized%22%2C%20%22Experiment.matured%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_9701"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22audience_12%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%22audience_12%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Schedule.fired", "Consent.withdrawn", "Contact.created", "Order.paid", "Subscription.canceled", "Offer.published", "Startup.graduated", "Complaint.filed", "Audience.resized", "Experiment.matured")', 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 (\"Schedule.fired\", \"Consent.withdrawn\", \"Contact.created\", \"Order.paid\", \"Subscription.canceled\", \"Offer.published\", \"Startup.graduated\", \"Complaint.filed\", \"Audience.resized\", \"Experiment.matured\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_9701"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"audience_12\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"audience_12\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Schedule.fired\", \"Consent.withdrawn\", \"Contact.created\", \"Order.paid\", \"Subscription.canceled\", \"Offer.published\", \"Startup.graduated\", \"Complaint.filed\", \"Audience.resized\", \"Experiment.matured\")', 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"
}
}application/json{
"decision": {
"$id": "https: //api.sb/ leaseline.app/ decisions/ decision_903",
"$type": "Decision",
"choice": "add-to-audience",
"reason": "38 new host Contacts passed fresh reads; 11 removals were uploaded and acknowledged first; 16 drawn into the held-out 30 % stay out",
"stakes": "low",
"options": [
"add-to-audience",
"hold-out",
"leave-out",
"pair-two-startups",
"answer-a-report",
"run-a-lookalike"
…
sample · 4 Not live yetPreviewOn PATCH /{namespace}/campaigns/{id}Off PATCH /{namespace}/campaigns/{id}Take this one POST /{namespace}/tasks/{task}/claim
action_2 uploads today’s 11 removals. action_3 adds the 38 new members only once the Venue acknowledges every removal; no file leaves your account, and the Audience name carries no Startup or Market.
+2.6 added first orders per $100 · ■□□□ Too early to tell · n 4,
| Try another: the daily build | Choice | Reason |
|---|---|---|
| Today’s build: 38 new host Contacts, 11 removals acknowledged first | add-to-audience | fresh reads, collected by the host, outside the holdout |
| A host Contact drawn into the held-out 30 % on Aug 24 | hold-out | out of every sister ad set for the block |
| A host Contact who unsubscribed from the sister product an hour ago | leave-out | an opt-out at any of your Startups removes them |
| “How did this ad know me?” | answer-a-report | the fixed answer: the privacy notice, the entity and a one-step opt-out |
- 30 min week 1, then 10 a week
- Your time
- Day 4: the first signup from the sister Audience
- First signal
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Sibling audience lift → Sent by your other Startups → New Customers ↑ → ARR added each week → ARR
Worth’s formula: about +1.4 first paid Orders per $100 (Other Startups’ results; your own read is too early) × $200 a month × $347 Pro ARR ≈ +$972. Under First signal: One 90-day block per read: about 13 weeks to tell +1.4 per $100 at 4,200 Contacts with 30 % held out; under 2,000, 90 days can tell only +3.5 or more.
sample · api.sb/
Start it this week
npx startup-builder add play sibling-audiences # 1 · writes plays/sibling-audiences.mdx (Not live yet, gaps #5)
# 2 · dry run; below, its 422 on 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":"sibling-audiences"}'
# 3 · keep it, at You approve each one
curl -X POST https://api.sb/leaseline.app/campaigns \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"sibling-audiences"}'
# on
curl -X PATCH https://api.sb/leaseline.app/campaigns/sibling-audiences \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":null}'
# off: every sister ad set pauses and uploads stop
curl -X PATCH https://api.sb/leaseline.app/campaigns/sibling-audiences \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":"now"}' | Check | Fix | Then |
|---|---|---|
use-when pass · Not live yet, gaps #8 | Pair with a Startup of yours holding 2,000 or more Contacts, or run retargeting. | POST /{namespace}/metrics/query |
baseline pass · Not live yet, gaps #8 | Read it once; it fills Before in Your number. | POST /{namespace}/metrics/query |
removals-first fail | Reconnect with the Audience scope that acknowledges removals. | POST /{namespace}/integrations/{integration}/reconnect |
role-unstaffed warn · Not live yet, gaps #8 | Staff the Marketing Lead, or leave it: pairings and reports come to you. | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "sibling-audiences can’t start yet: 1 check fails and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "your other Startup: 4,200 Contacts it collected; Lists overlap on small landlords",
"doc": "/plays/sibling-audiences#check-use-when",
"fix": "Pair with a Startup of yours holding 2,000 or more Contacts, or run retargeting.",
"then": "Metric.query"
},
{
"check": "baseline",
"status": "pass",
"observed": "0.16 first paid Orders per 100 host Contacts with no Ads, n 4,200",
"doc": "/plays/sibling-audiences#check-baseline",
"fix": "Read it once; it fills Before in Your number.",
"then": "Metric.query"
},
{
"check": "removals-first",
"status": "fail",
"observed": "the Facebook connection returns no removal acknowledgments",
"doc": "/plays/sibling-audiences#check-removals-first",
"fix": "Reconnect with the Audience scope that acknowledges removals.",
"then": "Integration.reconnect"
},
{
"check": "role-unstaffed",
"status": "warn",
"roles": [
"marketing-lead"
],
"owned": 0,
"doc": "/plays/sibling-audiences#check-role-unstaffed",
"fix": "Staff the Marketing Lead, or leave it: pairings and reports come to you.",
"then": "Role.staff"
}
]
}It says no, says why, and names the fix.
| Check | Fix (one call) | Your time | Wait |
|---|---|---|---|
use-when · baseline · pass: 4,200 host Contacts; 0.16 per 100, n 4,200 (gaps #8) | POST /{namespace}/metrics/query on sibling-audience-lift, which fills Before in Your number | 1 min | none |
removals-first · fail: no removal acknowledgments | POST /{namespace}/integrations/{integration}/reconnect with the Audience scope | 5 min | none |
role-unstaffed · warn (gaps #8): no Marketing Lead | POST /{namespace}/roles/{role}/staff, or leave it: pairings and reports come to you | 0 min | none |
Your number · Before 0.16 · Now 2.6 added first orders per $100 · Target 2.0 by Jan 21 · ■□□□ Too early to tell · n 4,
The Ads cost what the Venues bill, capped at $200 a month by your Limit; the daily build, the removal audit and the canaries cost about $0.15 a day (Worker cost). That comes to about $14 for each added first order at Other Startups’ rate.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| The daily build time | sibling-build-due | at on Schedule.fired where the daily build time in your file, for every exposed pair | removals acknowledged before any addition | the host’s Contacts, read in your account; nothing leaves as a file |
| Someone opts out or is suppressed at any of your Startups | pool-opt-out | event on Consent.withdrawn where an opt-out, withdrawal or Suppression a Person records at any of your Startups | out of every Audience at the next build, within 24 h | POST /{namespace}/contacts/{contact}/unsubscribe and POST /{namespace}/contacts/{contact}/suppress at either Startup |
| A sister Audience member pays Leaseline for the first time | receiver-first-order | event on Order.paid where a receiver's first paid Order from a Person in a randomized pair | 90d | POST /{namespace}/integrations/connect (Stripe) |
+ 5 more for signups, host cancels, a Startup leaving, knowledge reports and the block start (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_9701" ,
"$type": "Event",
"name": "Schedule.fired",
"at": "2026-10-19T05:00:00Z" ,
"seq": 9701,
"data": {
"audience": "audience_12",
"trigger": "sibling-build-due",
"added": 38,
"removed": 11,
"heldOut": 16,
"readsAgeMinutes": 12
}
}npx startup-builder trigger Schedule.fired --like event_9701 # replays the daily build
npx startup-builder clock advance --by 1d # runs the removal audit and the next build
npx startup-builder listen Consent.withdrawn --forward-to http://localhost:3000/hook Who runs it
Paid media · your agent (role:, worker_7) holds the Key Result. Pairing two Startups, any lookalike and every knowledge report come to you (Dana Okafor, person, worker_1), because the Marketing Lead Role has no person. It writes to no one; it builds Audiences. Your number links to Did it work.
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Add to the sister Audience · Hold out · Leave them out | It does it | 2,940 · 1,260 · 214 | — | a removal unacknowledged at 24 h → every sister ad set pauses | POST /{namespace}/actions/{action}/redirect |
| Answer a knowledge report | You approve each one | 1 of 1 | never: it answers in your name | — | POST /{namespace}/approvals/{approval}/approve |
| Pair two Startups · Run a lookalike | You approve each one | 1 of 1 · 0 | never | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| Change the held-out share or the block length | You approve each one; next block only | 0 merged | never | — | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Never: an Ad written for them, an Ad that names the other Startup, a bought or matched member | Refused, every time | 1 concept refused | never | — | nothing; the Checks hold it |
What it reads · What it may call. It reads the host’s own Contacts with Suppression, Consent and opt-out reads under 1 hour old, and Leaseline’s approved cold concepts. No Ad names, mimics or borrows the other Startup, or implies anything a Person did there. Its tools are PATCH /{namespace}/audiences/{id}, POST /{namespace}/flags/{flag}/evaluate, POST /{namespace}/audiences, POST /{namespace}/conversations/{conversation}/answer, POST /{namespace}/contacts/{contact}/suppress, POST /{namespace}/ads, and any other call becomes an Approval under the Role’s Mandate.
You hold the paid media Key Result: 2.0 added first orders per $100 by 2027-01-21. ← worker, metric
Each day, upload removals, wait for every acknowledgment, then add. ← removals-first
Only Contacts the host collected, read fresh within the hour. ← first-party, fresh-reads
Hold 30 % out for each 90-day block. ← your file, line 2
Run Leaseline’s approved cold concepts unchanged; never write one for them. ← copyRules 1, 2
Watch the host: its cancellations among the exposed never rise past held out. ← host-churn The slow loop. The block runs to Nov 21 and no Change can touch its held-out share inside it, so there is no replay or read-back to print.
Bring your own agent (folded) starts at It does it for builds only when it matches the seated agent’s removals-first order on the eval suite; spend and pairing stay with you. POST /{namespace}/roles/{role}/staff seats it.
npx startup-builder eval --scenario sibling-audiences-4200 --agent "claude -p" --seat paid-media-manager # seated: every removal acknowledged before additions, 0 Checks failed served · yours: 1 addition before an acknowledgment, refused What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Add to the sister Audience add-to-audience | a Contact the host collected, fresh reads, no opt-out, outside the holdout | Your rule (line 4) | PATCH /{namespace}/audiences/{id}, after the day’s removals are acknowledged | nobody | the same |
Hold out hold-out | drawn into the 30 % at the block’s start | Your rule (line 2) | POST /{namespace}/flags/{flag}/evaluate: out of every sister ad set for 90 days | nobody | the same |
Leave them out leave-out | an opt-out, a Suppression, no Consent your file asks for, or not collected by the host | Your rule (the Guard) | nothing; the Guard holds them and logs a private reason | nobody | the same |
Pair two Startups pair-two-startups | Lists overlap and Offers complement each other | Agent’s call, with its reason | POST /{namespace}/audiences for the pair, after your approval | you approve the pair · Take this one | you |
Answer a knowledge report answer-a-report | someone says an Ad seemed to know them | Your rule (copy rule 10) | POST /{namespace}/conversations/{conversation}/answer with the privacy notice → on request POST /{namespace}/contacts/{contact}/suppress | you approve it, due 1 business day · Take this one | you |
Run a lookalike run-a-lookalike | the list arm already won its read | Agent’s call, with its reason | POST /{namespace}/audiences seeded from paying host Customers → POST /{namespace}/ads, read by region | you approve it · Take this one | you |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | a click to Leaseline’s trial Page from the cold concept | Leaseline’s standard Offer Page; nothing changes for a sister Audience | nobody | — | PATCH /{namespace}/audiences/{id} |
| Send me pricing | a comment: “What does Leaseline cost?” | the Pricing Page’s list Price, as it stands | Paid media · your agent | 1 h | POST /{namespace}/conversations/{conversation}/answer |
| Not now | a hide on the Ad | that ad set stops for them | nobody | at once | PATCH /{namespace}/audiences/{id} |
| Wrong person | a comment: “I don’t manage property.” | a plain answer; they leave the sister Audience | Paid media · your agent | 1 h | POST /{namespace}/conversations/{conversation}/answer |
| Out of office | an auto-reply to a trial email | the trial’s own notices wait for the return date | nobody | the return date | POST /{namespace}/messages/{message}/schedule |
| Question it can’t answer | “How did this ad know me?” | the fixed answer: the privacy notice, the entity it names, and the one-step opt-out | you approve it | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Stop | “Stop showing me ads.” | out of every Audience at every one of your Startups within 24 h | nobody | at once | POST /{namespace}/contacts/{contact}/suppress |
When it hands to you
This Play hands no buyer to a person. What lands in your queue is the pairing, any lookalike and each knowledge report, because the Marketing Lead Role has no person. As captured (draft and checks are Not live yet, gaps #7).
[
{
"$id": "https://api.sb/leaseline.app/approvals/approval_151" ,
"$type": "Approval",
"verdict": "approved",
"deadline": "2026-08-25T17:00:00Z" ,
"draft": "Pair: your other Startup hosts, Leaseline receives; Lists overlap on small landlords; 30 % held out; $200 a month" ,
"route": "pair-two-startups",
"checks": [
{
"check": "first-party",
"status": "pass"
},
{
"check": "removals-first",
"status": "pass"
}
]
},
{
"$id": "https://api.sb/leaseline.app/tasks/task_914" ,
"$type": "Task",
"assignee": "worker_1",
"due": "2026-10-02T17:00:00Z" ,
"on": "contact_388",
"brief": {
"who": "a commenter on the cold concept",
"said": "How did this ad know me?" ,
"chose": "answer-a-report",
"why": "a knowledge report gets the fixed answer, in your name" ,
"never": [
"arguing",
"naming what they did anywhere"
]
}
}
]You answer with POST /{namespace}/approvals/{approval}/approve or POST /{namespace}/approvals/{approval}/refuse, POST /{namespace}/tasks/{task}/claim (Take this one) or POST /{namespace}/tasks/{task}/return with a reason, each a one-call window. A suppression request never waits on you: it leaves every Audience at the next build. A Task nobody claims by its due time goes up a Role through POST /{namespace}/tasks/{task}/escalate, and person-promise fires.
On time: you, 2 of 2 within 1 business day, n 2, ■□□□ Too early to tell beside Other Startups’ 95 % on time. Your queue: in week 1, the pairing and 2 concepts to approve; then about 1 report a month and the weekly review.
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) | Refuses | Fix | Then |
|---|---|---|---|
fresh-reads (the record’s Fresh reads only) | an upload whose Suppression, Consent or opt-out read is over 1 h old | Read again; the upload runs on reads under 1 h old. | POST /{namespace}/collections/query |
removals-first (the record’s Removals first) | an addition before the Venue acknowledges every removal in the build | Wait for the acknowledgments; additions follow. | PATCH /{namespace}/audiences/{id} |
first-party (the record’s First-party only) | a member whose identifier the host did not collect from the Person | Use only Contacts the host collected itself. | PATCH /{namespace}/audiences/{id} |
knowledge-hold (the record’s Knowledge hold) | a concept that names, mimics or borrows the host, or implies what a Person did there | Run Leaseline’s approved cold concept unchanged. | PATCH /{namespace}/ads/{id} |
consent-stop (gaps #3) | a member with no advertising Consent in a Market your file marks consent-first | Leave them out until a Consent is recorded. | POST /{namespace}/messages/{message}/schedule |
claims-resolve (hub) | an Ad sentence no approved Page backs | Cut the sentence, or publish the Page that says it. | POST /{namespace}/content/draft |
price (gaps #1) | a Price in an Ad that differs from the Offer’s live Price | Quote the Pricing Page’s live Price. | POST /{namespace}/approvals/{approval}/approve |
| Stop (pauses the Play) | Pauses when | Then |
|---|---|---|
removal-lag | a removal unacknowledged 24 h after it was written | every sister ad set on that Venue pauses |
membership-leak | an uploaded member the Guard refuses today | every sister ad set on that Venue pauses |
canary | a canary still in an Audience after its next removal batch | the Play pauses on every Venue and drops to You approve each one |
market-consent | a member in a consent-first Market with no advertising Consent | the Play pauses on every Venue |
pool-exit | a Startup leaves the pool | its pairs end; its Contacts leave every Audience within 24 h |
knowledge-report | 2 knowledge reports on one pair in 30 days; 5 across the Play | the pair pauses; 5 pause the Play |
withdrawal | sister-product opt-outs among the exposed above held out by 2 per 1,000 in a block, over 5,000 | the receiver pauses |
host-churn | at 90 days, host cancellations among the exposed above held out by 1 per 100 | every pair of the receiver pauses |
audience-floor | an Audience under its Venue’s minimum | its ad set holds; it never widens to keep spending |
frequency | an ad set’s 7-day frequency above 10 | that ad set pauses |
yield-floor | a loser Readout | the receiver’s sister ad sets end; a Decision opens |
spend-limit | month-to-date spend reaches the Limit | the Play pauses until the month turns (POST /{namespace}/limits/{limit}/raise) |
kill-switch | you press it | every sister ad set and lookalike pauses through the proxy; uploads stop |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the concept that ran instead is in Example.
| Check | Fix | Then |
|---|---|---|
knowledge-hold fail | Run Leaseline’s approved cold concept unchanged. | PATCH /{namespace}/ads/{id} |
price pass · Not live yet, gaps #1 | — | POST /{namespace}/approvals/{approval}/approve |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "The concept did not run in the sister ad set: it addresses the other Startup’s users by name.",
"checks": [
{
"check": "knowledge-hold",
"status": "fail",
"doc": "/plays/sibling-audiences#check-knowledge-hold",
"fix": "Run Leaseline’s approved cold concept unchanged.",
"then": "Ad.update"
},
{
"check": "price",
"status": "pass"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "removal-lag",
"observed": "3 removals unacknowledged at 26h",
"bound": "24h",
"window": "Facebook, Sep 15 build"
},
"doc": "/plays/sibling-audiences#stop-removal-lag" ,
"task": "task_902"
}
]Did it work
The host’s Contacts were held out at random, 30 % for the block that ends Nov 21 (rules m–o); each figure’s call is POST /{namespace}/metrics/query by node and by arm, and every node above the leaf is Not live yet (gaps #4).
+2.6 added first orders per $100 · ■□□□ Too early to tell · n 4,
- Chose
- add-to-audience
- Why
- 38 new host Contacts passed fresh reads; 11 removals were uploaded and acknowledged first; 16 drawn into the held-out 30 % stay out
- From
- add-to-audience · hold-out · leave-out · pair-two-startups · answer-a-report · run-a-lookalike
- Expects
- removals acknowledged within 24h; first paid Orders per $100 above the held-out rate by the block’s end
- Reopens when
- a removal unacknowledged at 24h, or a canary still in the Audience
- By
- worker_7
JSON
{
"$id": "decisions/decision_903",
"$type": "Decision",
"choice": "add-to-audience",
"reason": "38 new host Contacts passed fresh reads; 11 removals were uploaded and acknowledged first; 16 drawn into the held-out 30 % stay out",
"stakes": "low",
"options": [
"add-to-audience",
"hold-out",
"leave-out",
"pair-two-startups",
"answer-a-report",
"run-a-lookalike"
],
"by": "worker_7",
"on": "audience_12",
"expected": "removals acknowledged within 24h; first paid Orders per $100 above the held-out rate by the block’s end",
"reopensWhen": "a removal unacknowledged at 24h, or a canary still in the Audience"
}| Node | Agent half (exposed, 70 %) | Your half (held out, 30 %) | Added | Confidence | Basis |
|---|---|---|---|---|---|
sibling-audience-lift | 14 first paid Orders of 2,940 (0.48 per 100) on $360, 0 more host cancels than held out | 2 of 1,260 (0.16 per 100) | +2.6 per $100 [−0.1, 4.8] | ■□□□ Too early to tell | held back at random · n 4,200 · 34 days left in the block · Other Startups’ results +1.4, ■■■□ Likely, n 61,000 |
sibling-sourced-share | 14 new Customers sent by your other Startup | 2 | +9.3 [−0.3, 18.5] | ■□□□ Too early to tell | the same assignment |
new-arr ↑ | $4,858, 14 Customers on Pro · Booked: credited, not all caused by this Play (kind sibling) | $694, 2 Customers | +$3,239 [−$149, +$6,626] · Worth about +$970 a month | ■□□□ Too early to tell (14 vs 2 Customers) | the same · 6 trials still deciding |
net-new-arr · arr | +$4,858 | +$694 | +$3,239, carried: it moves no other bridge term | ■□□□ Too early to tell | carried from new-arr |
The leaf counts Leaseline first paid Orders from the host’s Contacts, exposed against held out, less any rise in the host’s cancellations, per $100 of sister spend over the 90-day block; the block reads on Nov 21.
How it moves it: people who already pay your other Startup saw Leaseline’s best cold concept, unchanged, at a 7-day frequency of 3.2.
Guardrails: exposed against held out, the pair under sibling-sourced-share: host cancellations, 1.9 against 2.3 per 100 host Customers, and sister-product opt-outs, 1.0 against 0.8 per 1,000.
{
"$id": "https://api.sb/leaseline.app/campaigns/sibling-audiences" ,
"$type": "Campaign",
"play": "play:sibling-audiences@1" ,
"path": [
"sibling-audience-lift",
"sibling-sourced-share",
"new-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "sibling-audience-lift",
"unit": "ratio",
"heldBack": 1260,
"decision": null
},
"readout": {
"value": 2.6,
"n": 4200,
"maturing": 4200,
"interval": [
-0.1,
4.8
],
"readability": "inadmissible",
"basis": "held-back",
"pooled": false
},
"ledger": {
"spend": 360,
"workerCost": 8,
"hours": 1.4,
"pipelineArr": 0,
"wonArr": 4858,
"projectedArr": 972,
"paybackDays": 27
}
}Outside benchmark: this Play’s catalog record carries no sourced range yet, so Other Startups’ results stand in: +1.4 added first orders per $100, ■■■□ Likely, n 61,000 Contacts.
Before it · After it. Before it: family-opt-in and your other Startup’s own Plays collect the Contacts it hosts. After it: product-led and instant-response take the trials and forms it brings, and cross-sell holds the sister-product Offers inside each product.
Example
Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days) as the receiver, with Unitledger, Dana’s other Startup, as the host: 4,414 host Contacts, 214 left out by the Guard, and 4,200 assigned, 2,940 exposed and 1,260 held out, on Facebook and Instagram at about $6.40 a day. Read every captured Ad and comment at ?threads=; three follow the tables.
| What happened, by option | Decisions | People | First paid Orders (counts) |
|---|---|---|---|
| Add to the sister Audience | 56 daily builds | 2,940 exposed | 14 |
| Hold out · Leave them out | 1 draw · 214 | 1,260 · 214 | 2 · — |
| Pair two Startups · Answer a knowledge report · Run a lookalike | 1 · 1 · 0 | 1 pair · 1 answer · — | — |
| Exposed · held out | 2,940 · 1,260 | $360 · $0 | 14 · 2 |
| At 2,000 host Contacts (the Use it when volume) | about 1,400 exposed | held back at random, 30 % | Other Startups’ results: +1.4 per $100, ■■■□ Likely, n 61,000 |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_9602 Campaign.created | the three steps; the dry run fails removals-first | 15 min |
| 0 | event_9605 Integration.reconnected | the Audience scope that acknowledges removals | 5 min |
| 1 | event_9611 Approval.approved | you approved the pair and 2 cold concepts | 10 min |
| 4 | event_9630 Contact.created | the first Leaseline signup from the sister Audience | — |
| 22 | event_9655 Campaign.paused | removal-lag on Facebook: 3 removals at 26 h; resumed when acknowledged | 6 min |
| 39 | event_9672 Task.claimed | you answered the knowledge report with the fixed answer | 8 min |
| 1–56 | event_9610 Approval.created, first of 4 | you approved the pair, 2 concepts and 1 answer; knowledge-hold refused 1 concept; weekly reviews | 56 min · total 1.4 h measured, 1.5 h asked |
Leaseline’s cold concept, Instagram, Sep 9 · Every renewal notice, 60 days out, for every owner you manage. Try Leaseline free for 14 days.¹
A small landlord who keeps her books in Unitledger, exposed, Sep 10 · started a trial; paid for Pro on Sep 24: +$347 ARR, an Acquisition of kind
sibling.²
- Already on Unitledger? Add Leaseline and your renewals sync with your books.
+ Every renewal notice, 60 days out, for every owner you manage. Try Leaseline free for 14 days. A commenter, 2026-10-01 18:20 · “How did this ad know me?” · The agent, 18:21 · drafted the fixed answer and assigned it to you (
task_914), due tomorrow 17:00 · Dana, Oct 2 09:05 · posted it: the privacy notice, the entity it names and a one-step opt-out.³ They opted out; they left every Audience at the next build.
¹ Leaseline’s approved cold concept, unchanged: nothing written for the sister Audience. ² Credit through noun: with kind sibling; the sister product’s own cancellations read beside it. ³ The answer copy rule 10 fixes: never an argument.
Your settings
---
holdout: 0.3 # 30 % of the host’s Contacts held out for each 90-day block
budget: $200/month
---
Rebuild daily: removals first, then additions, on reads under 1 hour old.
Run Leaseline’s approved cold concepts only, unchanged. $ npx startup-builder show plays/sibling-audiences
holdout 0.3 · budget $200/month · daily build, removals first · cold concepts unchanged your file plays/sibling-audiences.mdx:2,3,5,6 (Ask 2026-08-24)
worker role:paid-media-manager, owns never · chooses 6 (4 rule, 2 read) · approval first-send, every-send · checks fresh-reads, removals-first, first-party, knowledge-hold, consent-stop, claims-resolve, price · stops 13 · placements facebook, instagram, linkedin, google-display catalog play:sibling-audiences@1 (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record sibling-audiences 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.