Launch week
Turns a quarter’s shipped Changes into five dated launch days, each with its own Page and posts, and leaves no claim on your Site false.
- Step
- Get found
- Channel
- Launches
- Summary
- startupbuilder.dev
Be our Marketing Lead for launch week: once a quarter, group what we shipped into five dated days, each with a Page and posts, plus a recap to the people who signed up to hear from us. Only things on for every Customer. Fix any Site claim a Change makes false. Show me what’s missing; don’t publish.
# 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":"launch-week"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'launch-week' }, { 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":"launch-week"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'launch-week' }, { 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": "launch-week can’t start: 1 check fails and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "warn",
"observed": "Q3: 8 visible Changes flag-on; 74 of 100 People who said yes",
"doc": "/plays/ launch-week#check-use-when",
"fix": "Grow the list to 100 by planning day; the recap waits for it.",
"then": "Contact.subscribe"
},
…
Hand the latest shipped Change to the Marketing Lead agent and show me what it chose and why. Don’t publish.
curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Change.merged%22%2C%20%22Flag.evaluated%22%2C%20%22Change.reverted%22%2C%20%22Period.opened%22%2C%20%22Organization.announced%22%2C%20%22Version.deployed%22%2C%20%22Visitor.identified%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_1209"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22change_41%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%22change_41%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Change.merged", "Flag.evaluated", "Change.reverted", "Period.opened", "Organization.announced", "Version.deployed", "Visitor.identified")', 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 (\"Change.merged\", \"Flag.evaluated\", \"Change.reverted\", \"Period.opened\", \"Organization.announced\", \"Version.deployed\", \"Visitor.identified\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1209"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"change_41\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"change_41\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Change.merged\", \"Flag.evaluated\", \"Change.reverted\", \"Period.opened\", \"Organization.announced\", \"Version.deployed\", \"Visitor.identified\")', 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_434",
"$type": "Decision",
"choice": "fix-the-claim",
"reason": "`change_41` ships the owner portal; your comparison Page still says “owners get PDF reports only”, and a comparison row is yours to rewrite",
"stakes": "medium",
"options": [
"write-the-feed-line",
"fix-the-claim",
"plan-the-week",
"run-the-day",
"swap-in-the-reserve",
"tell-who-asked",
…
sample · 4 Not live yetPreviewOn PATCH /{namespace}/campaigns/{id}Off PATCH /{namespace}/campaigns/{id}Take this one POST /{namespace}/tasks/{task}/claim
action_1 is the feed line, held until the portal is on for every Customer for 7 days. action_2 sends the comparison row to you; record-copied facts it fixes itself, a comparison row it never does.
462 ICP Visitors in the week’s window against 320 before · before-after,
| Try another: the Change | Choice | Reason |
|---|---|---|
| Owner portal shipped Oct 18; the comparison Page says “PDF reports only” | fix-the-claim | a live claim is now false |
| Sep 1: Q3 holds 8 flag-on units, 90 days since no week | plan-the-week | the quarter’s third month, 6+ units |
Sep 30, day 3: move-out templates, Incident open on POST /{namespace}/messages/{message}/schedule | swap-in-the-reserve | an open Incident on a Verb the day names |
| SMS reminders at 40 % rollout | not-now | not on for every Customer for 7 days |
- 3.5 h per week, then 15 min a week
- Your time
- Day 1 of the week: first week-sourced signup
- First signal
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Launch week ICP visits → People reached → New Customers ↑ → ARR added each week → ARR
Worth’s formula: about +150 ICP Visitors per launch week (Other Startups’ results; no lift of your own to read) × 1 week a quarter ÷ 3 months × 0.008 Visitors to paid × $590 first order ARR ≈ +$236. Under First signal: Each week reads at day 5 plus 14; at 1 a quarter it reads before-after against your 12-week baseline, beside Other Startups’ results.
sample · api.sb/
Start it this week
npx startup-builder add play launch-week # 1 · writes plays/launch-week.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":"launch-week"}'
# 3 · keep it: you accept every plan and every comparison row
curl -X POST https://api.sb/leaseline.app/campaigns \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"launch-week"}'
# on
curl -X PATCH https://api.sb/leaseline.app/campaigns/launch-week \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":null}'
# off: the week stops; the drift sweep keeps running
curl -X PATCH https://api.sb/leaseline.app/campaigns/launch-week \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":"now"}' | Check | Fix | Then |
|---|---|---|
use-when warn · Not live yet, gaps #8 | Grow the list to 100 by planning day; the recap waits for it. | POST /{namespace}/contacts/{contact}/subscribe |
baseline pass · Not live yet, gaps #8 | 118 ICP Visitors a week, 12-week baseline | POST /{namespace}/metrics/query |
change-feed fail | Connect your code host so the feed reads each merged Change. | POST /{namespace}/integrations/connect |
domain-authenticated pass | — | POST /{namespace}/domains/{domain}/authenticate |
mailbox-warm pass · Not live yet, gaps #1 | the Startup’s Mailbox, warm since July | POST /{namespace}/mailboxes/{mailbox}/warm |
role-unstaffed pass · Not live yet, gaps #8 | plans and comparison rows go to the founder, Dana | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "launch-week can’t start: 1 check fails and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "warn",
"observed": "Q3: 8 visible Changes flag-on; 74 of 100 People who said yes",
"doc": "/plays/launch-week#check-use-when",
"fix": "Grow the list to 100 by planning day; the recap waits for it.",
"then": "Contact.subscribe"
},
{
"check": "baseline",
"status": "pass",
"observed": "118 ICP Visitors a week, 12-week baseline",
"doc": "/plays/launch-week#check-baseline",
"then": "Metric.query"
},
{
"check": "change-feed",
"status": "fail",
"doc": "/plays/launch-week#check-change-feed",
"fix": "Connect your code host so the feed reads each merged Change.",
"then": "Integration.connect"
},
{
"check": "domain-authenticated",
"status": "pass",
"doc": "/plays/launch-week#check-domain-authenticated",
"then": "Domain.authenticate"
},
{
"check": "mailbox-warm",
"status": "pass",
"observed": "the Startup’s Mailbox, warm since July",
"doc": "/plays/launch-week#check-mailbox-warm",
"then": "Mailbox.warm"
},
{
"check": "role-unstaffed",
"status": "pass",
"observed": "plans and comparison rows go to the founder, Dana",
"doc": "/plays/launch-week#check-role-unstaffed",
"then": "Role.staff"
}
]
}It says no, says why, and names the fix.
| Check | Fix (one call) | Your time | Wait |
|---|---|---|---|
use-when · baseline · warn: 8 Changes, 74 of 100 who said yes; pass: 118 a week (gaps #8) | POST /{namespace}/contacts/{contact}/subscribe from the waitlist form; POST /{namespace}/metrics/query on launch-week-icp-visits fills Before | 5 min | about a week at 4 a day |
change-feed · fail (gaps #8) | POST /{namespace}/integrations/connect with your code host | 5 min | the first feed run, about 10 min |
domain-authenticated · mailbox-warm · role-unstaffed · pass | nothing to do | 0 min | none |
Your number · Before 320 ICP Visitors per 19 days · Now 462 in the week’s window · Target 500 by Dec 31 · before-after,
A launch week costs no cash: day Pages publish on your own Site and posts go from your own Handles. The feed, the drift sweep and the kit cost about $3 a week (Worker cost). Your time is about 3.5 hours per week, plus 15 minutes a week on the feed digest.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| A Change merges with a diff Customers can see | change-merged | event on Change.merged where tier is set and the diff touches a Verb, Noun, Offer, Entitlement, Interface, Page or Product | 7d | POST /{namespace}/integrations/connect with your code host |
| A merged or reverted Change makes a live claim false | claim-drift | event on Change.merged where alters a value a live Page, listing, Ad, fact, Template or Handle bio states | 1d; found within 1 h | the sweep reads your Site, listings, Ads and bios |
| The quarter’s third month opens, 90 days after the last week | launch-week-due | at on Period.opened where the first weekday of the quarter’s third month, 90 days after the last launch week | 30d | set by your file’s quarter line |
+ 5 more for flag-on Changes, reverts, a rival’s launch week, resolved loss reasons and week signups (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_1209" ,
"$type": "Event",
"name": "Change.merged",
"at": "2026-10-18T16:40:03Z" ,
"seq": 1209,
"data": {
"change": "changes/change_41" ,
"title": "Owner portal: each owner signs in to see their renewals" ,
"tier": 1,
"flags": [
"owner-portal"
],
"rollout": 1,
"drift": [
"pages/compare-spreadsheets#row-4"
]
}
}# 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":"Change.merged","url":"https://leaseline.app/hooks/sb"}'
npx startup-builder trigger Change.merged --like event_1209 # replays the delivery through the drift sweep
npx startup-builder clock advance --by 7d # reads whether the portal stayed on for every CustomerWho runs it
Marketing Lead · your agent (role:, worker_8) holds the Key Result: it writes the feed, runs the drift sweep, plans the week, builds each day’s kit and runs the day. Each quarter’s plan and every comparison row hand to you (Dana Okafor, person, worker_1, role:), and you send your own posts from the tray and write every Hacker News word.
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Write the feed line · Tell who asked | It does it | 24 lines, 6 Messages, 0 Checks failed sent | met on day 14 | a line before flag-on → You approve each one | POST /{namespace}/actions/{action}/cancel |
| Fix the claim | It does it, you can stop it, for facts copied from records; You approve each one for comparison rows | 9 fixed, 3 rows rewritten by you | never for a comparison row | — | POST /{namespace}/actions/{action}/cancel · POST /{namespace}/tasks/{task}/return |
| Plan the week | You approve each one | 1 of 1 | never | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/tasks/{task}/return |
| Run the day · Swap in the reserve | It does it, you can stop it | 5 days, 1 swap | met after review-all on day 1 | an outage hold → You approve each one | POST /{namespace}/actions/{action}/cancel inside the hold |
| Change the day order | You approve each one | 1 merged of 1 | never | — | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Never: a line before flag-on, a number its Change lacks, a vote ask | Refused, every time | 2 drafted, 2 refused | never | — | the flag-gate and vote-ask Checks |
What it reads · What it may call. It reads each Change’s own description, its Flags and Evidence, and the live Site, never a watched Event in what it writes. It may call POST /{namespace}/content/draft, PATCH /{namespace}/pages/{id}, POST /{namespace}/sites/{site}/publish, POST /{namespace}/posts/{post}/publish and POST /{namespace}/posts/{post}/withdraw on your own Site and Handles. Its tools are POST /{namespace}/content/draft, PATCH /{namespace}/pages/{id}, POST /{namespace}/tasks/{task}/assign, POST /{namespace}/sites/{site}/publish, POST /{namespace}/posts/{post}/publish, POST /{namespace}/posts/{post}/withdraw, and any other call becomes an Approval under the Role’s Mandate.
You hold the Marketing Lead Key Result: 500 ICP Visitors per launch week by 2026-12-31. ← worker, metric
On each merged Change, drift or due date, choose one option and say why. ← triggers, chooses
Name a Change only when every Flag it names is on for every Customer for 7 days. ← flag-gate
Start each line “You can now”, in 20 words or fewer, with no number the Change lacks. ← copyRules 1, 2
Lead the week with the tier 1 unit, then integrations, then templates. ← your file, line 6
A comparison row goes to the founder; a record-copied fact you fix. ← chooses.fix-the-claim The slow loop, as a Change. decision_394 (2026-09-21, weekly, during planning) read Leaseline’s 4 integration Pages bringing 2 times the ICP Visits of its template Pages, so change_30 moved the Ledgerly and Porchlight unit from day 4 to day 2 (your file, line 6), and Dana merged it with POST /{namespace}/changes/{change}/merge. Replayed on Q2’s Pages, POST /{namespace}/changes/{change}/review put the week at about 450; read back at day 5 plus 14 it is 462, n 1 week, ■□□□ Too early to tell (Example, day 53).
Bring your own agent (folded) plans and runs the week at the same rung when it matches or beats the seated agent on the eval suite; plans and comparison rows wait on you either way, and POST /{namespace}/roles/{role}/staff seats it.
npx startup-builder eval --scenario launch-week-38 --agent "claude -p" --seat marketing-lead # seated: 0 false claims left, 0 unflagged lines sent · yours: 1 claim left on a listing, 1 line at 40 % rollout → You approve each one What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Write the feed line write-the-feed-line | a merged Change with a diff Customers can see | Your rule (the feed) | POST /{namespace}/content/draft the line, held until flag-on | nobody | the same |
Fix the claim fix-the-claim | a merged or reverted Change made a live claim false | Agent’s call, with its reason | PATCH /{namespace}/pages/{id} for a fact copied from a record; POST /{namespace}/tasks/{task}/assign for a comparison row | you rewrite the row, due 1 business day · Take this one | you |
Plan the week plan-the-week | the quarter’s third month, 6+ flag-on units, 90 days since the last week | Your rule (line 3) | POST /{namespace}/content/draft the plan: five days and a reserve → POST /{namespace}/tasks/{task}/assign | you accept it, due 1 business day · Take this one | you |
Run the day run-the-day | a launch day’s 09:00 slot, every Change still flag-on | Your rule (the plan) | POST /{namespace}/sites/{site}/publish the day Page → POST /{namespace}/posts/{post}/publish on Leaseline’s Handles → day 5: launch-week-recap | nobody; your own posts wait in the tray | the same |
Swap in the reserve swap-in-the-reserve | an open Incident or a revert on a Verb the day names | Agent’s call, with its reason | POST /{namespace}/sites/{site}/publish the reserve unit → POST /{namespace}/posts/{post}/withdraw any Post on the held unit | nobody; you see it in the day line at 18:00 | the same |
Tell who asked tell-who-asked | a Person whose words asked for the Change, once it is flag-on | Your rule (the Sequence) | you-asked-it-shipped: one Message | nobody | the same |
Not now not-now | not flag-on for every Customer for 7 days, no visible diff, or another of your Startups holds that week | Your rule (the gates and the caps) | nothing; names the Flag, the diff or the other week | nobody; the feed reads it again | the same |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | a recap reply: “The owner reports are what we need. Can we talk?” | goes to instant-response as a new Lead, with the week on its Acquisition | SDR · your agent, then AE · Priya Shah (person) | 5 min | POST /{namespace}/leads |
| Send me pricing | “Is the owner portal on Pro?” | answered from the live Pricing Page, as it stands at send time | SDR · your agent | 5 min | POST /{namespace}/conversations/{conversation}/answer |
| Not now | “Thanks, not for us right now.” | nothing more about the week sends to them | nobody | at once | GET /{namespace}/decisions |
| Wrong person | “Sending this to our ops lead.” | a one-line thanks; it never writes to an address from their text | Marketing Lead · your agent | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Out of office | an auto-reply to the recap | nothing: the recap carries no follow-up | nobody | — | GET /{namespace}/decisions |
| Question it can’t answer | “When does SMS ship?” | To you: a date for a Change that is not flag-on is never the agent’s to give | you (Dana, person) | 1 business day | POST /{namespace}/conversations/{conversation}/escalate |
| Stop | “Unsubscribe.” | no recap, note or newsletter sends to them again | nobody | at once | POST /{namespace}/contacts/{contact}/unsubscribe |
When it hands to you
Each quarter’s plan and every comparison row hand to you (Dana Okafor, person); interested recap replies go through instant-response to the AE. As captured, the comparison-row Task in your queue (brief is Not live yet, gaps #7).
[
{
"$id": "https://api.sb/leaseline.app/tasks/task_524" ,
"$type": "Task",
"assignee": "worker_1",
"due": "2026-10-19T17:00:00Z" ,
"on": "change_41",
"brief": {
"page": "Leaseline vs spreadsheets, row 4" ,
"says": "owners get PDF reports only",
"now": "each owner signs in to the portal to see their renewals (change_41, flag on for 41 of 41 Customers)" ,
"chose": "fix-the-claim",
"why": "a comparison row is the founder’s to rewrite",
"never": [
"a claim about a named rival",
"a number change_41 lacks"
]
}
}
]You answer with POST /{namespace}/tasks/{task}/claim (Take this one) and rewrite the row, POST /{namespace}/tasks/{task}/return with a reason, or POST /{namespace}/actions/{action}/redirect; a plan with POST /{namespace}/approvals/{approval}/approve. While the row is open, drift-hold holds any post that links the comparison Page. Nobody else can rewrite a comparison in your name, so nothing goes up a Role.
On time: You: 4 of 4 comparison rows and 1 of 1 plan answered within 1 business day, median 3h 20m, n 5, ■□□□ Too early to tell beside Other Startups’ 87 %. Your queue: counted by kind: per quarter, 1 plan and 5 day lines; between weeks, about 1 comparison row a fortnight and the 15-minute weekly digest.
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 |
|---|---|---|---|
owned-by-a-person (rule j; Not live yet, gaps #8) | a recap or Message 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. | POST /{namespace}/tasks/{task}/assign |
fact-check (copy rule 2) | a line with a number the Change’s description, its Evidence or a measured Metric lacks | Cut the number, or add it to the Change’s description. | POST /{namespace}/content/draft |
flag-gate | a Post, Page, recap or listing naming a Change not on for every Customer for 7 days | Wait for full rollout; it joins the next day or the next week. | GET /{namespace}/decisions |
visible-only | a line, Post or Page for a Change with no diff Customers can see | None: it stays in the internal changelog. | GET /{namespace}/decisions |
drift-hold | a day’s sends while a linked surface holds a false claim; the week’s, for the Pricing or a comparison Page | Fix the claim; the sends release once it is true. | PATCH /{namespace}/pages/{id} |
deploy-freeze | a deploy or a named Flag change from day 1 00:00 to day 5 23:59 | Ship it after day 5, or ship an approved fix in steps; reverts always run. | POST /{namespace}/approvals/{approval}/approve |
incident-hold | a day that names a Verb with an open Incident | The reserve unit runs instead. | POST /{namespace}/incidents/{incident}/resolve |
authorship | an agent sentence for Hacker News | Write it yourself from the fragments. | POST /{namespace}/tasks/{task}/assign |
vote-ask | any Page, Post or Message that asks anyone to vote, upvote or rank anything | Cut the ask; say what they can now do. | POST /{namespace}/content/draft |
portfolio-caps | a second launch week for one audience in a calendar week, or your Startups launching together | Take the next open week. | POST /{namespace}/tasks/next |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the rewrite that published is the day 1 thread in Example.
| Check | Fix | Then |
|---|---|---|
fact-check fail · Not live yet, gaps #1 | Cut the number, or add it to the Change’s description. | POST /{namespace}/content/draft |
flag-gate pass | — | GET /{namespace}/decisions |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "The day 1 Post did not publish: it states a number `change_33` does not hold.",
"checks": [
{
"check": "fact-check",
"status": "fail",
"doc": "/plays/launch-week#check-fact-check",
"fix": "Cut the number, or add it to the Change’s description.",
"then": "Content.draft"
},
{
"check": "flag-gate",
"status": "pass"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "revert-withdraw",
"observed": "`change_37` reverted at 11:12" ,
"bound": "0 announced reverts",
"window": "day 4"
},
"doc": "/plays/launch-week#stop-revert-withdraw" ,
"task": "task_441"
}
]Did it work
At 1 week a quarter, no held-back half of weeks reads, so the basis is before-after against your 12-week baseline (rule o): the columns read Now and Before, and nothing prints as Added. Each figure’s call is POST /{namespace}/metrics/query by node, and every node above the leaf is Not live yet (gaps #4).
462 ICP Visitors in the week’s window against 320 before · before-after,
- Chose
- fix-the-claim
- Why
- `change_41` ships the owner portal; your comparison Page still says “owners get PDF reports only”, and a comparison row is yours to rewrite
- From
- write-the-feed-line · fix-the-claim · plan-the-week · run-the-day · swap-in-the-reserve · tell-who-asked · not-now
- Expects
- the comparison row true within 1 business day
- Reopens when
- no Page.updated on the comparison Page within 1d
- By
- worker_8
JSON
{
"$id": "decisions/decision_434",
"$type": "Decision",
"choice": "fix-the-claim",
"reason": "`change_41` ships the owner portal; your comparison Page still says “owners get PDF reports only”, and a comparison row is yours to rewrite",
"stakes": "medium",
"options": [
"write-the-feed-line",
"fix-the-claim",
"plan-the-week",
"run-the-day",
"swap-in-the-reserve",
"tell-who-asked",
"not-now"
],
"by": "worker_8",
"on": "change_41",
"expected": "the comparison row true within 1 business day",
"reopensWhen": "no Page.updated on the comparison Page within 1d"
}| Node | Now (the week, day 1 to day 5 plus 14) | Before (12-week baseline, per 19 days) | Added | Confidence | Basis |
|---|---|---|---|---|---|
launch-week-icp-visits | 462 ICP Visitors whose first Visit came from a day Page, a week Post, the recap or the short link | 320, from every Source | — · Worth about +$240 a month | — | before-after, not proof · Other Startups’ results +150 per week, ■■■□ Likely, n 380 weeks, 10 % recap holdout |
icp-reached | 1,104 ICP Visitors in the 19 days, every Source | 320 | — | — | before-after |
new-arr ↑ | $2,329, 5 week-sourced Customers (4 on Pro, 1 on Team) · Booked: credited, not all caused by this Play | $694 per 19 days | — · 23 signups activated by day 5 plus 14; 6 trials still deciding | — | before-after, not proof |
net-new-arr · arr | carried from new-arr | carried | — | — | carried |
Before against after reads ICP Visitors from the week’s outputs, day 1 to day 5 plus 14, against your 12-week baseline scaled to 19 days. It is not proof; Other Startups’ results, read against a 10 % recap holdout, print beside it.
How it moves it: eight small Q3 releases landed as five dated days, each with its own Page and two posts, and the recap reached 187 People who said yes.
Guardrails: before against after: play-sourced-customers, 5 against 2, and false claims left on the Site at day 5, 0 against 3 found by the first sweep.
{
"$id": "https://api.sb/leaseline.app/campaigns/launch-week" ,
"$type": "Campaign",
"play": "play:launch-week@1" ,
"path": [
"launch-week-icp-visits",
"icp-reached",
"new-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "launch-week-icp-visits",
"unit": "count",
"heldBack": 0,
"decision": null
},
"readout": {
"value": null,
"n": 1,
"maturing": 0,
"interval": null,
"readability": "inadmissible",
"basis": "before-after",
"pooled": true
},
"ledger": {
"spend": 0,
"workerCost": 24,
"hours": 5.5,
"pipelineArr": 2082,
"wonArr": 2329,
"projectedArr": 236,
"paybackDays": 0
}
}Outside benchmark: none measures a startup launch week against its own baseline; Other Startups’ results, +150 ICP Visitors per week, ■■■□ Likely, n 380 weeks, stand in for one.
Before it · After it. Before it: shipped Changes and the drift sweep run every week. After it: a tier 1 Change on a rested site goes to launch-sites, refreshed listings to marketplace-listings, and a resolved loss reason to lead-reactivation.
Example
Leaseline ran its first launch week from 2026-09-28 to 2026-10-02 on Q3’s 38 merged Changes: 14 internal, 16 changelog lines, 7 tier 2 and 1 tier 1, grouped into 5 days and 1 reserve. The drift sweep ran all 56 days. Read every captured thread at ?threads=; three follow the tables.
| What happened, by option | Decisions | Published or sent | ICP Visitors | Won (credited, not all caused by this Play) |
|---|---|---|---|---|
| Write the feed line · Tell who asked | 24 · 6 | 24 lines · 6 Messages | — | 1 Customer from a “you asked” Message |
| Fix the claim | 12 | 9 facts fixed, 3 rows rewritten by you | — | — |
| Plan the week · Run the day · Swap in the reserve | 1 · 5 · 1 | 5 day Pages, 10 Handle Posts, 187 recaps | 462 | 4 Customers |
| Not now | 8 | 0 | — | — |
| All · 12-week baseline, per 19 days | 57 | — | 462 · 320 | $2,329 · $694 |
| At 1 week a quarter (the Use it when volume) | about 60 a quarter | 1 week | before-after, not proof | Other Startups’ results: +150 per week, ■■■□ Likely, n 380 |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_130 Campaign.created | the three steps; dry run fails change-feed | 20 min |
| 1 | event_141 Change.merged | the first drift sweep: 3 false claims, all fixed by day 4 | 15 min |
| 8 | event_270 Approval.approved | you accepted the plan: 5 days, 1 reserve, freeze Sep 28 to Oct 2 | 30 min |
| 28 · 53 | event_538 Change.merged · event_890 Readout.created | integrations on day 2: replayed at about 450, read back at day 5 plus 14 at 462, n 1 | 5 min |
| 35 | event_610 Site.published | day 1: per-owner renewal batches; the first week-sourced signup at 09:40 | 20 min |
| 38 | event_655 Campaign.paused | revert-withdraw: change_37 reverted at 11:12; its Post withdrew at 11:31 and the reserve ran | — |
| 1–56 | event_145 Task.assigned, first of 18 | you accepted 1 plan, rewrote 3 rows and sent 10 of your own posts, from the POST /{namespace}/tasks/next log | 4.3 h · total 5.5 h measured, 5 h asked |
Day 2, Sep 29, 09:00, Leaseline’s LinkedIn · You can now post each signed renewal to Ledgerly or Porchlight the day it signs.¹ The day Page shows both, live.²
Sep 29, 10:12 · a 140-unit manager read the day Page, signed up (first Source: the week’s short link) and activated on Oct 3; paid for Team on Oct 9, +$941 ARR.
- Renewals now go out 3x faster with per-owner batches.
+ You can now send each owner their own renewal batch, 60 days out. Oct 18, 16:41 ·
change_41shipped the owner portal, and the sweep found row 4 of the spreadsheets comparison still saying “PDF reports only”. The agent fixed nothing there and sent the row to Dana, due Oct 19, 17:00. · Dana, Oct 19, 09:20 · claimed it and rewrote the row; the hold on posts linking the Page released at 09:21.
¹ “You can now”, 20 words or fewer, from the Change’s own description. ² A screen the live Site serves.
Your settings
---
recapHoldout: 0.1 # 1 in 10 who said yes gets no recap
quarter: third-month
freeze: day-1-to-day-5
---
Lead with the tier 1 unit, then integrations, then templates. Comparison rows are mine. $ npx startup-builder show plays/launch-week
recap holdout 0.1 · third month · freeze day 1 to day 5 · day order your file plays/launch-week.mdx:2,3,4,6 (Ask 2026-08-24; line 6 by change_30, 2026-09-21)
family demand · worker role:marketing-lead, owns never · chooses 7 (5 rule, 2 read) · sequences launch-week-recap, you-asked-it-shipped, week-signup-follow-up · checks owned-by-a-person, fact-check + 8 · stops 5 + 1 on ads · placements site, google-search, x, linkedin, hacker-news, gmail, outlook, yahoo-mail catalog play:launch-week@1 (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record launch-week 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.