Weekly readout
Each week, each running Play’s numbers beside its benchmark, then keep, fix or switch, naming the row that fired.
- Kind
- Workflow
- Price
- Free
- Your time
- 7 minutes
- Approval
- Runs on its own
- Deepens
- Weekly review
Read this week’s numbers for every running Play and tell me what to keep, fix or switch. Spend nothing.
curl -X POST "https: //api.sb/ leaseline.app/ plays/ review? mode= try" \
-H "Authorization: Bearer $SB_TOKEN" \
-H "Content-Type: application/ json" \
-d '{"goal": "Read this week’s numbers for every running Play and tell me what to keep, fix or switch. Spend nothing.", "budget": {"amount": 0, "currency": "USD"}}'
npx startup-builder do Play.review --try --data '{"goal": "Read this week’s numbers for every running Play and tell me what to keep, fix or switch. Spend nothing.", "budget": {"amount": 0, "currency": "USD"}}'
{
"name": "do",
"arguments": {
"mode": "try",
"code": "return await $.Play.review({ goal: 'Read this week’s numbers for every running Play and tell me what to keep, fix or switch. Spend nothing.', budget: { amount: 0, currency: 'USD' } })"
}
}
import { $ } from 'startup-builder'
const result = await $.try.Play.review({ goal: 'Read this week’s numbers for every running Play and tell me what to keep, fix or switch. Spend nothing.', budget: { amount: 0, currency: 'USD' } })
{
"mode": "try",
"stored": false,
"estimate": "Free",
"sample": {
"play": "Cold email",
"metric": "reply rate",
"week": "1.6% of 250 (0.7% to 3.5%)",
"benchmark": "3% to 6%",
"verdict": "fix",
"fired": "replies < 2% at 200 sends: angle, not volume"
}
}
What you get
- 1 week · Each week, each running Play’s numbers beside its benchmark, then keep, fix or switch, naming the row that fired. · Play
plays[].numbers· The week’s numbers for the Play’s Metric and its funnel rows, each beside its benchmark and its source label.plays[].interval· The 90% interval on every rate: 2 replies from 60 sends reads “3.3%, 1.1% to 9.6%”, so one reply never decides a switch.plays[].verdict·keep(everygoodrow for this week holds),fix(abreaksrow fired and its fix is a change inside the Play) orswitch(twobreaksrows fired two weeks running).plays[].fired· The typed row that fired: its metric, the threshold, this week’s reading, the cause and the call that fixes it.
How long: Seconds.
Trigger
It runs weekly at 08:00 on the first weekday, after the week’s Search readout lands.
every('mon 08:00' , ($) => $.Play.review({ plays: 'running' }))Steps
Your agent does these steps, one row per step; each step’s check is part of its row and its price.
| Step | Verb | Returns | Price | Approval |
|---|---|---|---|---|
| 1. Read each running Play’s numbers for the week | Metric.query | The Metric and the funnel rows for each Play, with n | Free | Runs on its own |
| 2. Read the benchmarks and the typed rows | Collection.query | Each Play’s good row for this week and its breaks rows, with their thresholds and source labels | Free | Runs on its own |
| 3. Hold each reading against its rows | Metric.watch | Which breaks rows fired, which good rows held, and the 90% interval on every rate | Free | Runs on its own |
| 4. Write the verdict by the declared rule | Collection.query | Keep, fix or switch per Play, with the row that fired and the call that fixes it | Free | Runs on its own |
Calls: Metric.query, then Collection.query, then Metric.watch, then Collection.query.
Free, each time it runs, capped at 0¢.
Example: give it a goal
Read this week’s numbers for every running Play and tell me what to keep, fix or switch. Spend nothing.
The plan it shows runs 4 steps, priced before it spends anything; Run it above shows the result it returns.
When something fails
Each failure, and what happens next
| When | Then |
|---|---|
| A Play’s Metric has no reading this week | The Play reads no-data with the Event it waits on, never a zero; a missing feed is a fix, not a switch. |
n is under minN | The verdict can be keep or fix, never switch: at 60 sends a 3.3% reply rate could be anywhere from 1.1% to 9.6%. |
Two breaks rows fire for one Play | The verdict names both, the first by the order its page lists them, and the switch waits one more week unless both fired last week too. |
Each step retries three times, then falls through to the next route; one item's failure lands in skipped with its reason, never failing the call. Before a step would cross maxCost it stops and returns what it has, with a resume link. Each step's idempotency key is the call's key plus the step and the item: leaseline-play-review-1-<step>-<item>.
Change it
| Ask | Compiles to |
|---|---|
| Wait two weeks before any switch. | Play.review |
| Apply the fix the readout names for Cold email. | Play.apply |
| Rebuild next week’s mix from this readout. | PlayMix.compile |
import { $, workflow } from 'startup-builder'
export default workflow({
name: 'weekly-review',
verb: 'Play.review',
input: { plays: "'running' | string[]", minN: 'integer' },
trigger: { schedule: 'mon 08:00' },
maxCost: 0,
execute: async (ctx, { plays = 'running', minN = 100 }) => {
const numbers = await ctx.step('numbers', () => $.Metric.query({ plays, period: 'week', withN: true }))
const rows = await ctx.step('rows', () => $.Collection.query({ from: 'play', where: plays === 'running' ? "state = 'running'" : `$id in ${plays}`, fields: ['breaks', 'good'] }))
const held = await ctx.step('watch', () => $.Metric.watch({ readings: numbers, against: rows, interval: 0.9, minN }))
return verdicts(held) // keep: every good row holds · fix: a breaks row fired · switch: two rows, two weeks running
},
})Extend it with extends: and base(), or compose your own from these steps.
Works with
Plays that order it: Build in public, Commission partners, Creator partnership, Creator retainers, Made-with line, Sponsorships.
It serves Measure, and runs in Hands-on, Paid, Borrowed, Keep and grow. It deepens Weekly review.
For agents
For agents: the guide, its approvals, retries and lookups
| Fact | Value |
|---|---|
| Guide | Play.review |
| Guide approval | none |
| Goal | Read this week’s numbers for every running Play and tell me what to keep, fix or switch. Spend nothing. It may change counts, the order of steps, soft filters and the route a read takes, and it stops early when the goal is met. It never relaxes your words, raises its own budget, answers its own approval, calls a Play or acts outside your standing approval. |
| Trigger | every('mon 08: |
| Retry | Three times with backoff, then the next route; the same idempotency key never charges, sends or posts twice |
| Idempotency key | leaseline-play-review-1 |
| Lookups | A find: input asks unless exactly one record fits |
| Step |
|---|
| 1. Read each running Play’s numbers for the week |
| 2. Read the benchmarks and the typed rows |
| 3. Hold each reading against its rows |
| 4. Write the verdict by the declared rule |
The amounts live once, on the hub (approvals).
Who does each step, and how it is checked
| Step | Function | Doer | Checker | Assurance | Inputs |
|---|---|---|---|---|---|
| 1. Read each running Play’s numbers for the week | code | Code | Code checks each result against its declared type | measured | $0.plays, |
| 2. Read the benchmarks and the typed rows | code | Code | Code checks each result against its declared type | measured | $0.plays |
| 3. Hold each reading against its rows | code | Code | Code checks each result against its declared type | measured | $1, |
| 4. Write the verdict by the declared rule | code | Code | Code checks each result against its declared type | measured | $3 |
The doer is never the checker, and the weakest assurance on the path is the whole call’s.
Under the hood
Under the hood: the Systems, Nouns and Events it touches
| Kind | What it touches |
|---|---|
| Systems | Analytics and experiments |
| Nouns | Metric, Collection |
| Events | Metric.queried, Collection.queried, Metric.watched |
Reference
Inputs, outputs, its Event and its errors
| Name | Type | Default | Meaning |
|---|---|---|---|
plays | 'running' | PlayId[] | 'running' | The Plays to read: every Play running this week, or the ones you name. |
week | string | the last full ISO week | The week read. |
minN | integer | 100 | Below this many sends, visits or clicks, the verdict can fix but never switch: the interval is too wide to call. |
maxCost | number | 0.00 | The most this call spends each time it runs, in USD. It stops before a step would cross it and returns what it has, with a resume link. |
Emits Play.reviewed. Refuses with max-cost before it spends, and with the Data calls and Accounts groups (refusals).