M3: The Static Camera Isn't
That clip up top: every serve the pipeline is confident about across the sixty point clips — server end and deuce/ad called on each, SERVE flashed at the detected toss.
Sixty clips are waiting to be charted, and charting each one starts with the players. SAM does that beautifully for about $0.15 a clip — $9 per full pass over the reel, forever, every rerun. But M1 left a free alternative lying around: the temporal median erases players, which means frame minus median IS a player detector. This session cashed that in, and the pursuit of free player tracking knocked over three assumptions on the way.
Finding 1: the static camera isn't
M1 measured the camera static across the 16-second M0 rally and concluded one homography serves all frames. Align every frame of a 60-second clip against its first frame (ECC, translation-only) and a different story appears:

point_29: the broadcast camera, measured. A 32-pixel pan in the middle of the point, plus slow drift throughout.
The camera operator follows the play. Of course they do — it's their job. The pan is invisible watching the footage and fatal to everything downstream: it smears the median plate, and at the far baseline 30 pixels is meters of court-coordinate error. M1's assumption survived only because the M0 clip was short. Every frame now gets stabilized to its clip's first frame before anything else — plate, subtraction, or homography — touches it.
Finding 2: the plate keeps a ghost
With stabilization in, the near player tracked at 100% coverage immediately. The far player: 35%. The plate had eaten him.
He's small, and between shots he barely moves — so the median over a short clip contains a faint standing copy of him, and wherever he stands still, frame-minus-plate reads zero. The near player never suffers this because he's big and restless.
The fix borrows the medicine that already worked twice: don't build the plate from one clip; build it from five. Each clip's plate is median-merged with its four neighbors' plates (ECC-aligned). Players stand in different spots from point to point, so their ghosts never line up, and the median votes them out. Far-player coverage: 35% → 96%, near stays 100%. Zero API calls.
Finding 3: everyone looks like a tennis player
First serve-detection run, several clips reported the far player standing at court x = 13.5 meters. The court is 10.97 meters wide.
Those blobs were the far-corner ballkids — crouched just outside the doubles lines, inside my generous tracking region, and moving just enough to out-diff a motionless pre-serve server. Third impostor of the project, after M0's spare-ball holders and the self-erasing line judge: to a difference image, everyone near a tennis court looks like a tennis player. The far half's region is now cut tight to the court; the near half stays generous.
Point anatomy: who serves, and when
With tracks in hand, the serve should be geometry. The server hugs the center mark; the receiver waits wide. The toss stretches the server's silhouette — arm and racket at full reach — so the blob's height peaks. Which side of the mark they stand on gives deuce or ad for free.
Version 1 asked only "who's closer to the center mark?" and the frame strips ate it alive: the reel's cold open starts mid-rally, zoom-tail fragments produced garbage blobs, and — the expensive lesson — returners often stand a meter off the center hash, where a return swing reads as a toss to a height detector.

When it's right, it's textbook: point_33, toss at full stretch on the detected frame.

When it's wrong, it's instructive: point_40's "server" is the returner, one meter off the hash, mid-return-swing. Four gates passed on the wrong man.
Version 2 stops guessing. Every candidate must clear four gates — early
track coverage, distance to the center mark, distance to their own
baseline, and a real height peak — or the clip gets an explicit
no_confident_serve with its reasons attached. The yield: 40 of 60
clips produce a confident serve call; the other 20 are reasoned
refusals, and reading the refusal log is diagnosis for free (the cold
open, mid-point rejoins, and the two long clips whose early far tracks
are too sparse — the 49-shot rally among them).
Frame-verifying a sample of the confident calls: six of eight server ends right, five of eight serve moments usable. Honest scorecard. Geometry-only anatomy tops out about here — the structural fix is the ball. A serve is the ball leaving the server's hand and crossing the net; when ball tracking runs over these clips, the ball adjudicates everything the silhouette can only suggest.
The verdict
Player tracking for all sixty points, serve anatomy on two-thirds of them, three assumptions corrected — for $0.00. Project total: still about seventy-five cents, all of it spent back in M0. SAM is now needed for exactly one thing: the ball.
Which is the next session: the charting loop. Ball tracking over point clips, M2's detector with fps finally a parameter, and the pieces — serve, hits, bounces, letters — assembling into per-point MCP strings. The string from cv-05 was one rally's middle. The next one should have a beginning.