LIVE Commerce Analytics / Builder session 7 of 8
Learn LIVE Commerce Analytics with Phoebe · Builder session 7 of 8

The live nowcast

Everything so far has been done to a recording. Tonight the stream is still running. A producer sits behind the host with an earpiece, and the only useful thing you can put in that earpiece is a number about the next five minutes that is better than her own guess, delivered with enough context that she knows what to do with it. That is a nowcast, and it is smaller than it sounds: a smoothed order rate times a projection of where the room is going, summed over five minutes. The work is not the arithmetic. The work is the backtest that proves it beats "the next five minutes will look like the last five", and the alert rule that stays quiet when the dip is noise.

🔴 Hardest Data scientists Anyone who wants a number in the producer's ear 45 min
0-3 · Welcome 3-20 · A five-minute forecast 20-40 · Build-along: backtest and alert 40-45 · Q&A
Part 0

Where session 7 sits

Session 6 ended with a playbook: say the ask, say the price, two minutes of urgency and stop, show the product, answer the room. Each line has a within-stream number. None of them says when. A CTA at minute 43 of a stream that is already converting is a CTA wasted; the same CTA at minute 43 of a stream that has been quietly sliding for three minutes is the one that pays. Tonight builds the thing that can tell those two minute-43s apart while they are happening, and session 8 puts it on the replay bench to find out what it was worth.

Live = presented in the 45 minutes Self-study = the full depth, after class 🔍 Every diagram zooms

★ What you walk out with tonight. A nowcaster for the next five minutes of orders that beats "next five equals last five" over 6,720 backtest windows: MAE 9.41 orders per window at alpha 0.1 against 11.97 for the naive rule. An alert rule with two conditions, orders under 70 percent of the nowcast for three minutes and no CTA in the last six, and the base-rate table that says how often it fires on a host's own plan. And a replay loop that prints the producer's line minute by minute for one real stream.

LiveWhy five minutes3 min▶

The horizon is chosen by the people, not the model. A host can act on a cue within a minute: pick up the serum, say the price, ask for the order. A cue takes about two minutes to land in the ledger, because the viewer who hears it has to tap the card, read the page and pay, and session 2 found the stream itself carries a delay before the words even arrive. So one minute is too short to see anything change, and two is the earliest a change shows. Five is the shortest horizon a producer can plan against: long enough that a cue given now is fully inside it, short enough that the room at the end of it is still recognisably the room at the start.

Go longer and the forecast gets easier to hit and useless to act on. A thirty-minute forecast is mostly the room's slow drift, which the producer can see with her own eyes. The five-minute number is the one she cannot see: whether the next five will be better or worse than the last five, and by roughly how much.

Real world

Lumen Glow's first producer dashboard showed the running GMV total and a line for the room. The producer's own words on it: "It tells me what already happened. I need to know if I should interrupt her." The nowcast replaced the running total with one line, orders expected in the next five minutes against orders in the last five, and an amber state when the second was falling short of the first. She stopped watching the room curve within a week.

Self-studyThe vocabulary tonight leans on4 min▶
  • Nowcast - a forecast of the immediate future from the immediate past, made while the thing is still happening. Distinguished from a forecast by the horizon (minutes, not weeks) and by the fact that the same model runs again every minute with one more row.
  • Horizon - how far ahead the number reaches. Five minutes here. The backtest scores the sum over the horizon, not each minute inside it.
  • EWMA - exponentially weighted moving average. rate = alpha * new + (1 - alpha) * rate. Small alpha means long memory; the newest minute barely moves the estimate. Large alpha means the estimate chases the newest minute.
  • Backtest window - one (stream, minute t) pair at which the nowcaster is run using only rows before t and scored against rows t to t+4. Every window is a fresh forecast; 6,720 of them tonight.
  • MAE - mean absolute error, in the unit of the thing forecast. Orders per five-minute window here. It is the average size of the miss, in either direction.
  • Base rate - how often a rule fires when nothing is done about it, and how often a firing is followed by the thing it was supposed to predict. An alert without one cannot be judged.
  • Alert - a rule that turns the nowcast into a yes or no. It is the only part of tonight a producer ever sees, so it carries the most design.
Part 1 · covers the nowcaster's arithmetic, the backtest and the alpha sweep

A small honest model

9 min live

The nowcaster is two estimates and a loop. An order rate per viewer, smoothed so one noisy minute does not swing it, and a room projection, the last five minutes' slope carried forward but damped so it cannot run away. Multiply, sum five times, and you have a number. The diagram is the whole model and the whole backtest on one canvas, because a model this small should fit.

The nowcaster, and what it scored left: the arithmetic at minute t · right: MAE over 6,720 five-minute windows, all 60 streams order rate per viewer rr = orders[t-1]/room[t-1] rate = a*rr + (1-a)*rate room projection slope = 5-min change / 5 next = room + 0.6*slope next five minutes for 5 steps: room = room + 0.6*slope orders += room * rate Two knobs. alpha is the rate's memory; 0.1 remembers about ten minutes, 0.6 remembers about two. 0.6 damping keeps a two-minute spike in arrivals from being projected as a room that doubles. The room is what moves inside five minutes. The rate barely does. Project the room, smooth the rate. Backtest: MAE, orders per 5-minute window every minute 3 to 115 of every stream; lower is better alpha 0.1 9.41 alpha 0.3 10.84 alpha 0.6 11.28 naive: last 5 11.97 naive = "next five equals last five", the bar to beat Slower memory wins. Per-minute order rates are noisy; chasing the last minute chases the noise. 6,720 windows = 60 streams x 112 minutes each. Without the naive bar, 9.41 is just a number. With it, the nowcast beats a producer's rule of thumb by 21 percent.
🔍 Click to zoom - the whole nowcaster as arithmetic, and the four-bar backtest that says whether it earned its place.
LiveThe arithmetic, and why the room matters more than the rate3 min▶

Orders in a minute are the room times the rate at which that room is ordering. Both move, but not equally. Across a five-minute window the per-viewer order rate of a given host in a given stream is nearly a constant with noise on it: one minute has three orders from a room of 800, the next has nine, the one after has four. Smoothing it is the right treatment. The room is different. It rises when the feed sends a burst of arrivals and falls when a segment goes stale, and those moves are real and they persist for minutes. A projection of the room is the right treatment for that.

So the nowcaster smooths the thing that is mostly noise and projects the thing that is mostly signal. The rate is an EWMA of orders[t-1] / room[t-1]. The room projection takes the change over the last five minutes, divides by five for a per-minute slope, and carries it forward five steps with a damping of 0.6 at each step, so a slope of plus twenty viewers a minute contributes twelve to the first projected minute and never compounds into a room that doubles. Each projected minute's room times the smoothed rate is that minute's expected orders; the five of them add up to the nowcast.

That is all of it. There is no seasonality, no exogenous regressor, no state vector. A model a producer can hold in her head is a model she will believe when it disagrees with her, and the backtest is what earns it the right to.

LiveThe backtest, and the bar that makes it mean something3 min▶

A backtest replays history as if it were live. For every stream and every minute t from 3 to 115, the nowcaster is given rows 1 to t-1 only, asked for the sum of orders in minutes t to t+4, and scored against what actually happened. Minute 3 is the first with enough history for a slope; minute 115 is the last whose five-minute horizon fits inside the 120. That is 112 windows a stream, 6,720 across the 60. The score is the mean absolute error over all of them, in orders per window.

The naive baseline is computed in the same loop, at the same windows: the sum of orders in minutes t-5 to t-1, offered as the forecast for t to t+4. "The next five minutes will look like the last five" is what a producer does in her head, and it is not stupid; it scores 11.97. Any nowcast that cannot beat it has no business in an earpiece. The rule is simple and it is not negotiable: the naive number goes in the same table as the model's number, every time, or the model's number means nothing.

ForecasterMAE, orders per 5-min windowAgainst naive
EWMA rate x room projection, alpha 0.19.4121 percent lower
Same, alpha 0.310.849 percent lower
Same, alpha 0.611.286 percent lower
Naive: next five equals last five11.97the bar

Score the sum, not the minutes. The producer acts on "about 40 orders in the next five", not on a per-minute path. Scoring each of the five minutes separately rewards a model for getting the shape right and the total wrong, which is the opposite of what she needs.

LiveAlpha: why the slow memory wins here3 min▶

Three alphas, three MAEs: 0.1 gives 9.41, 0.3 gives 10.84, 0.6 gives 11.28. The ordering is monotone and the gap is not small. With alpha 0.6 the rate estimate is mostly the last minute, and the last minute's rate in a room of 800 is a count of three or nine divided by 800, a number with enormous relative noise. The nowcaster then multiplies that noise by five projected rooms. With alpha 0.1 the newest minute gets a tenth of the weight and the estimate is effectively an average over the last ten or so, which is where the true rate lives.

This is a property of the data, not a law. A stream whose host changes what she is doing every two minutes has a rate that genuinely moves, and a slow alpha would lag it. The 60 Lumen Glow streams have segments of a few minutes each and a rate that mostly rides on the host, so the slow memory wins. The sweep in the build-along is there so you re-run it on your own streams rather than inheriting 0.1 as a constant.

Real world

On Priya's stream 16 (Monday 18:00, no giveaway, peak room 498) the per-minute order count is small enough that a single bundle order swings the rate visibly. The alpha 0.6 nowcast on that stream oscillates by tens of orders from one minute to the next while the actual five-minute totals barely move; the alpha 0.1 version tracks them. Small rooms are where the slow memory pays most, and small rooms are most streams.

Self-studyThe next rungs: statsforecast and a Kalman local level4 min▶

Tonight's nowcaster is the bottom rung of a ladder, and it is worth knowing the next two by name so you reach for them when the bottom rung stops beating naive.

  • statsforecast 2.1.1 (Apache-2.0): AutoETS, AutoTheta and MSTL on a frame of unique_id, ds, y with freq="min", then sf.forecast(df, h=5, level=[90]) for a prediction interval as well as a point. MSTL takes season_length=[60] or a list if a stream has a repeating segment cycle. One caution: the package has had no release since 2024-09. It is stable and it works; it is not being extended.
  • statsmodels 0.15.0 UnobservedComponents with level="local level": the textbook Kalman filter for a true room hidden under noisy per-minute reads. y_t = mu_t + e_t, mu_t = mu_{t-1} + eta_t; the filtered level is the room estimate and res.forecast(5) is the projection. It replaces the slope-and-damping rule with something that learns how noisy the room reads are and how fast the true room drifts.

Both need the same backtest loop and the same naive bar. A forecaster that is more sophisticated and scores 11.5 has lost to the arithmetic. The full method ladder, from naive through ETS and Theta to state space and beyond, with the backtesting discipline that goes with each rung, is a course on its own: learn time series forecasting with phoebe.

Part 2 · covers the alert rule, its base rate and the sentence the producer hears

An alert that does not fire on noise

8 min live

A nowcast is a number every minute. A producer cannot act on a number every minute; she can act on a handful of moments a night. The alert is the rule that picks them, and a rule that fires on every noisy minute is worse than no rule, because by the third false alarm the earpiece is muted. Two conditions and a base rate, drawn on one stream.

One stream, one night: where the alert fires and where it holds schematic of a two-hour stream · solid: orders per minute · dotted: the nowcast made five minutes earlier orders / min 0 30 60 90 120 min CTA CTA CTA FIRES 3 min under 70%, last CTA 8 min back HOLDS dip, but a CTA ran 3 min ago Condition 1: a real shortfall sum(orders[t-3:t]) < 0.7 * nowcast for those 3 three minutes, not one, so noise cannot trip it Condition 2: room to act minutes since last CTA >= 6 a CTA takes two minutes to land; firing during one asks for a second ask The base rate, on the history How many times a night does it fire on the host's own plan, and what share of firings precede a real five-minute dip? This rule is the "CTA on a dip" policy on session 8's bench: +14.6 percent GMV over 40 nights. Same code, simulated night.
🔍 Click to zoom - two dips on one stream; the rule fires on the first and holds on the second because a CTA was already running.
LiveThe rule as the bench uses it3 min▶

The alert has two conditions and both must hold. First, the last three minutes of orders sum to under 70 percent of what the nowcast expected for those three minutes. Three, not one, because one minute under forecast happens constantly in a room where the count is a handful; three in a row is a slide. Seventy percent, not ninety, because a five-order miss on a forty-order forecast is noise and a fifteen-order miss is a room that has stopped buying. Second, the host's last CTA was six or more minutes ago.

This rule, followed exactly, is the "CTA on a dip" policy on session 8's replay bench: when it fires, the host is cued to do a CTA, and over 40 seeded nights of tonight's stream (Jules, Friday 20:00) that policy takes 20,847 dollars against the host's own plan at 18,198, plus 14.6 percent. The bench computes those means live in the browser. The rule you write tonight and the rule the bench runs are the same code.

The second condition is the one people want to delete, and it is the one that makes the rule usable. Without it, the rule fires during CTAs that are already running. A CTA minute has its orders arriving one to two minutes later, so the minute of the ask itself often looks like a shortfall; the rule would then cue a CTA into a CTA, the host would be asked to ask again, and the third time it happened she would take the earpiece out. Six minutes is two for the CTA to land, then a few more of the room converting on it, before it is reasonable to ask a second time.

LiveThe base rate, or why an alert without one is a guess3 min▶

Before a rule goes in anyone's ear, run it over the 60 historical streams with nothing done about it and count two things. How many times a night it fires on the host's own plan, which is the number of interruptions the producer is signing up for. And of those firings, what share were followed by an actual five-minute shortfall against the nowcast, which is how often the interruption was warranted. The build-along computes both from the history and prints them as a table; they are properties of your streams and your thresholds and they are not the same for a small room as for a large one.

Then move the thresholds and watch both numbers move. Loosen 70 percent to 85 and the rule fires more often on less; tighten six minutes to ten and it fires less often and later. There is no right setting, there is a trade the producer should make with the two numbers in front of her, and a rule shipped without them is a rule whose trade was made by whoever wrote the first draft.

What to reportHow it is computed on the historyWhat it tells the producer
Firings per streamCount of minutes where both conditions hold, over 60 streamsInterruptions a night
Share of firings before a real dipOf the firings, the share where the next five minutes fall under 70 percent of the nowcastHow often the interruption was warranted
Dips caughtOf the real dips, the share with a firing in the three minutes beforeWhat it misses

A base rate measured on a different stream mix is a different base rate. If your streams are half the size of these, the counts are noisier and the 70 percent threshold trips more. Rerun the table on your own history before you quote a firing rate to anyone.

LiveThe human in the loop2 min▶

The producer does not hear "fire". She hears a sentence: "orders under forecast, last CTA 8 minutes ago". That is the two conditions read out, and it is deliberately not an instruction. She can see the host, the chat and the product table; the rule can see three columns. She decides whether the cue is a CTA, a price reminder or nothing, because the host is mid-story and the story is working. The rule's job is to make sure she looks, at the right moment, with the reason in her ear.

Two words of the sentence carry the design. "Under forecast" says the shortfall is against what the room was expected to do, not against a number from a different night. "8 minutes ago" says there is room for an ask. When the leader track's session 5 teaches producers to coach live, this is the sentence they practise reacting to.

Self-studyWhat the nowcast will never see3 min▶

The nowcaster reads two columns of the minute table, orders and room, and knows nothing else. A change in how the feed is routing traffic shows up in the room only after it has happened, so the projection is late by exactly the amount it matters. A competitor's flash sale at the same hour pulls viewers out of the room for reasons the room curve cannot explain and the rate cannot anticipate. A product going out of stock stops orders dead while the nowcast keeps forecasting them for five more minutes.

None of that is a reason to add columns. It is the reason the horizon stays at five minutes. Every one of those shocks is invisible before it arrives and obvious within two minutes of arriving, and a five-minute forecast re-run every minute is wrong about it for at most a few windows before the new rate and the new slope take over. A thirty-minute forecast would be wrong for thirty. Short horizons are not a limitation the ladder grows out of; they are how a model with two inputs stays honest about the things it cannot see.

Build-along

Backtest the nowcast, then write the alert

★ 20 min · everyone builds

Five steps, pandas and numpy only. The nowcast function, the backtest loop with the naive baseline in the same table, the alpha sweep, the alert rule with its base rate computed on the 60 streams, and a replay loop that prints the producer's sentence minute by minute for Priya's stream 16. The loop matches analyze.py's nowcast_backtest so your numbers are its numbers.

The nowcast function. Takes the order and room arrays of one stream and a minute t, uses only rows before t, returns the expected orders in t to t+4. The EWMA rate is carried between calls, so the function takes the previous rate and returns the new one.

★ Two estimates and a loop import pandas as pd import numpy as np m = pd.read_csv("data/streams.csv").sort_values(["stream_id", "t"]) def nowcast(orders, room, t, rate, alpha=0.1, horizon=5, damp=0.6): """Expected orders in minutes t..t+horizon-1, using rows before t only. Returns (forecast, rate).""" rr = orders[t - 1] / room[t - 1] if room[t - 1] else 0.0 rate = rr if rate is None else alpha * rr + (1 - alpha) * rate # EWMA of orders per viewer k = min(5, t - 1) slope = (room[t - 1] - room[t - 1 - k]) / k # last-5-minute slope pr, po = room[t - 1], 0.0 for _ in range(horizon): pr = max(0, pr + slope * damp) # damped room projection po += pr * rate return po, rate

The backtest loop, with the naive baseline in the same table. Every stream, every minute 3 to 115. The naive forecast is the last five minutes' orders. Both errors are collected at the same windows so the comparison is fair.

★ 6,720 windows, two error lists def nowcast_backtest(alpha=0.1, horizon=5): errs, naive_errs = [], [] for sid, g in m.groupby("stream_id"): orders, room = g.orders.to_numpy(), g.room.to_numpy() rate = None for t in range(3, len(g) - horizon): po, rate = nowcast(orders, room, t, rate, alpha=alpha, horizon=horizon) actual = orders[t:t + horizon].sum() errs.append(abs(po - actual)) naive_errs.append(abs(orders[t - horizon:t].sum() - actual)) # "next 5 = last 5" return {"alpha": alpha, "mae": round(float(np.mean(errs)), 2), "naive_last5_mae": round(float(np.mean(naive_errs)), 2), "n": len(errs)} print(nowcast_backtest(0.1)) # {'alpha': 0.1, 'mae': 9.41, 'naive_last5_mae': 11.97, 'n': 6720}

The alpha sweep. Three values, one table, the naive column repeated in every row so nobody reads the model column alone.

★ Slower memory wins on this data sweep = pd.DataFrame([nowcast_backtest(a) for a in (0.1, 0.3, 0.6)]) print(sweep) # alpha mae naive_last5_mae n # 0.1 9.41 11.97 6720 # 0.3 10.84 11.97 6720 # 0.6 11.28 11.97 6720 sweep.to_csv("data/derived/nowcast_backtest.csv", index=False)

The alert rule and its base rate on the history. At each minute, compare the last three minutes' orders with the nowcast that was made for them three minutes earlier, and check the minutes since the last CTA. Then count firings per stream and the share followed by a real five-minute shortfall.

★ Two conditions, then count how often they hold on the host's own plan def alert_table(alpha=0.1, short=0.7, gap=6): rows = [] for sid, g in m.groupby("stream_id"): orders, room, seg = g.orders.to_numpy(), g.room.to_numpy(), g.segment.to_numpy() rate, fc3, fc5 = None, {}, {} last_cta = -99 for t in range(3, len(g) - 5): po3, _ = nowcast(orders, room, t, rate, alpha=alpha, horizon=3) po5, rate = nowcast(orders, room, t, rate, alpha=alpha, horizon=5) fc3[t], fc5[t] = po3, po5 # forecasts made at t, for t..t+2 and t..t+4 if seg[t - 1] == "cta": last_cta = t - 1 if t - 3 in fc3: recent = orders[t - 3:t].sum() cond1 = recent < short * fc3[t - 3] # last 3 minutes under 70% of their nowcast cond2 = (t - last_cta) >= gap # last CTA 6+ minutes back real_dip = orders[t:t + 5].sum() < short * po5 rows.append({"stream_id": sid, "t": t, "fires": cond1 and cond2, "real_dip": real_dip}) a = pd.DataFrame(rows) fires = a[a.fires] return pd.Series({ "firings_per_stream": round(len(fires) / a.stream_id.nunique(), 2), "share_before_real_dip": round(fires.real_dip.mean(), 3), "real_dips_per_stream": round(a.real_dip.sum() / a.stream_id.nunique(), 2), "dips_with_a_firing": round(a[a.real_dip].fires.mean(), 3), }) base = alert_table() print(base) # the numbers the producer signs up for; rerun on your own streams

Replay one stream and print the producer's line. Priya's stream 16, minute by minute. The sentence is the two conditions read out; "fire" never appears.

★ What the earpiece would have said on stream 16 def replay(sid, alpha=0.1, short=0.7, gap=6): g = m[m.stream_id == sid] orders, room, seg = g.orders.to_numpy(), g.room.to_numpy(), g.segment.to_numpy() rate, fc3, last_cta = None, {}, -99 for t in range(3, len(g) - 5): po3, _ = nowcast(orders, room, t, rate, alpha=alpha, horizon=3) po5, rate = nowcast(orders, room, t, rate, alpha=alpha, horizon=5) fc3[t] = po3 if seg[t - 1] == "cta": last_cta = t - 1 line = f"min {t:3d} | room {room[t-1]:4.0f} | next 5 expected {po5:5.1f} | last 5 actual {orders[t-5:t].sum():3d}" if t - 3 in fc3 and orders[t-3:t].sum() < short * fc3[t - 3] and (t - last_cta) >= gap: line += f" -> orders under forecast, last CTA {t - last_cta} minutes ago" print(line) replay(16)

The forecast you compare against must be the one made before the minutes it covers. Comparing the last three minutes with a nowcast made at t, which already saw them, is a rule that fires on its own hindsight. Keep the forecast dictionary keyed by the minute it was made, and look three minutes back.

Homework

Before session 8

30 min
  1. Sweep the damping factor (0.4, 0.6, 0.8, 1.0) at alpha 0.1 and add the rows to the backtest table. Write one sentence on what a damping of 1.0 does to the error on streams with a giveaway opener, where the room moves fastest.
  2. Split the backtest error by room size: windows where the room is under 400 and windows where it is over 800. Report both MAEs and both naive MAEs. The nowcast's advantage over naive is not the same in both, and you should be able to say why before you look.
  3. Move the alert thresholds: 70 percent to 85 percent, and six minutes to ten. Produce the base-rate table for each of the four combinations and write two lines a producer could choose between, with the firings per stream and the share before a real dip on each.
  4. Fit a statsmodels 0.15.0 UnobservedComponents(room, level="local level") to one stream's room column and compare its five-step forecast with the slope-and-damping projection at ten minutes of your choosing. Do not add it to the nowcaster yet; just see whether the two disagree and where.
Check yourself

Three questions

The nowcast scores an MAE of 9.41 orders per five-minute window. Why does the backtest table also carry the naive "next five equals last five" rule at 11.97?

A forecast number without a baseline cannot be judged good or bad. Computed at the same 6,720 windows, the nowcast is 21 percent lower than naive. A more elaborate model that scored 11.5 would have lost to arithmetic.

Alpha 0.1 gives MAE 9.41, alpha 0.6 gives 11.28. Why does the slower memory win?

Alpha only touches the rate, not the room projection, and there is no training set. The per-viewer order rate of a host inside a stream is close to a constant with noise on it; the long memory averages the noise out.

The alert's second condition is "last CTA six or more minutes ago". What does it prevent?

Without the second condition the rule fires on its own remedy. The producer would be asked to cue a CTA while one is in progress, and after the third time the earpiece comes out. Six minutes is time for the ask to land and the room to convert on it.

Sources covered

What tonight maps to

✓ The nowcaster and its backtest EWMA order rate times a damped room projection over a five-minute horizon; 6,720 windows; alpha 0.1 MAE 9.41, 0.3 at 10.84, 0.6 at 11.28, naive last-five 11.97.
✓ The alert rule and its base rate Three minutes under 70 percent of nowcast and six or more minutes since the last CTA; firings per stream and share before a real dip computed on the 60-stream history; the producer's sentence.
✓ statsforecast 2.1.1 and statsmodels 0.15.0 UnobservedComponents, named with versions AutoETS, AutoTheta and MSTL with freq="min" (no release since 2024-09), and the local-level Kalman nowcaster of the true room. Homework fits the second on one stream.
◐ The forecasting method ladder Only the bottom rung is built tonight and the next two are named. The ladder, its backtesting discipline and prediction intervals live in the time series forecasting course.
◐ The replay bench Tonight's alert is the "CTA on a dip" policy the bench runs at plus 14.6 percent over 40 nights. Session 8 puts the rule on the bench and adds the switchback design that makes the result believable.
· Deep forecasters Not covered. With 120 minutes per stream and two input columns, a neural forecaster has nothing to learn that the arithmetic and a state-space model do not already capture, and it cannot be explained in an earpiece.

Builder session 7 cheat sheet

The horizonFive minutes. A host acts within one, a cue lands in two, five is the shortest a producer can plan against.
The nowcasterEWMA of orders per viewer (alpha) times a room projection from the last five minutes' slope, damped 0.6, summed over five steps.
Smooth the rate, project the roomThe rate is a constant with noise on it. The room is what actually moves inside five minutes.
The backtestEvery minute 3 to 115 of every stream, forecast t to t+4 from rows before t. 6,720 windows, MAE on the five-minute sum.
The naive bar"Next five equals last five" scores 11.97. Alpha 0.1 scores 9.41. Never quote the second without the first.
Alpha0.1 beats 0.3 beats 0.6 here because per-minute order rates are noisy. Re-run the sweep on your own streams.
The alertFire when the last 3 minutes are under 70 percent of their nowcast AND the last CTA is 6+ minutes back. The second condition stops it firing into a running CTA.
The base rateFirings per stream and share before a real dip, computed on the history before the rule goes in anyone's ear. The producer hears the conditions, not "fire".