M2 · Shipped · Meet auto-seed workstream

Pick the kids. Pick the events. Hit Seed.

The wizard walks roster → events → policy → review → commit. The engine consumes the same PR data the Athlete page reads, applies serpentine lane assignment, and fans the result out to the iPad as a brand-new meet (or merges into one already running). Drag-to-tweak between lanes; cross-event drags are blocked; manual edits are sticky.

SETUP

A reproducible sample roster

This walkthrough drives against the same synthetic Sample Invitational meet that the W2 awards walkthrough uses, plus a 16-athlete roster the M-series fixture adds. The roster is identical across runs:

The DM Track Archive window just after launch with the fixture loaded.

The Mac archive just after launch. The fixture meet shows in the Pending Meets sidebar; the 16-athlete roster is wired into the analytics index.

STEP 1

Open the wizard

The wizard's window scene is registered with id seedMeetWizard and bound to ⌘⇧J. Reach it via the Window menu or the keyboard shortcut — either path opens the same window. Below, the Window menu is open with Seed Meet Wizard highlighted so you can see exactly which entry to click.

The Window menu open with Seed Meet Wizard highlighted in blue at the bottom, showing its Cmd+Shift+J shortcut.

Window menu open · Seed Meet Wizard highlighted · ⌘⇧J shown next to the entry.

Why J and not S: the original M2 scaffold tried ⌘⇧S but that key was already bound to the Stream Health window. SwiftUI silently awards the shortcut to whichever scene registers first, so the wizard's shortcut was being eaten. The M2.2 XCUITest caught it; we re-bound to ⌘⇧J (free in the Cmd+Shift namespace, "J" for "Jump-start the meet").
STEP 2

Step 1 — Pick the roster

The wizard opens on the Roster step. The picker reads from coordinator.athletes; chip filters narrow by team or group; the search field fuzzy-matches on name or team. The counter in the header — 0 selected · 16 shown · 16 total — gives you a running tally as you check rows.

Wizard step 1 showing the 16-athlete roster across 3 teams, no athletes selected yet.

Roster step on first open. SceneStorage round-trips the selection so closing + reopening the wizard preserves your pick.

STEP 3

Select every athlete

Click Select all visible. The counter ticks to 16 selected, every row gets a check, and the Next button at the bottom activates. (Without at least one athlete picked, Next stays disabled — same gate as step 2's events.)

Step 1 after Select all visible — every athlete row checked, counter shows 16 selected.

All 16 selected. Click Next to advance.

STEP 4

Step 2 — Pick events from four sources

Step 2 sources events from four places at once: the archive vocabulary (from the analytics index), the curated MacMeetTemplates.all presets, the iPad's currently-active MeetStructureSnapshot, and a free-form name+category entry row. All four push rows into the same selectedEventKeys set; the picker dedupes via Set semantics.

The fixture has no heat anchors, so the archive vocabulary is empty — but that's exactly the day-one case. The empty-state CTA points the operator at the template menu:

Step 2 with empty archive — empty state explaining the template path is shown.

Empty archive vocabulary. The "No events yet" empty state points to Add from template for day-one rosters.

STEP 5

Pick a template

Click Add from template to surface the curated presets. Each item shows its name + a one-line summary so you can pick by shape, not by reading every entry. Sprints & Relays is highlighted below — it's a 6-event preset (60 / 100 / 200 / 400 / 4×100 / 4×400) that fits a practice meet or a small invitational cleanly.

Add from template menu open with five presets listed; Sprints & Relays highlighted in blue at the bottom.

Template menu open · Sprints & Relays highlighted · click to insert all 6 events into selectedEventKeys.

All four sources compose: you can add a template's events, then type a custom event in the free-form row, then add another template if you want — Set semantics dedupe transparently. The picker shows the unioned result as one list.
STEP 6

Events appear in the picker

The Sprints & Relays template expanded into 6 EventKey rows. Because the archive has no prior data for these events, each row reads 0 races · 0 athletes — these are synthetic rows the picker added so you can see + uncheck them from the same list. Field-event entries would carry an orange "Field" pill on the right; track entries get blue category pills.

Step 2 after adding the Sprints & Relays template — 6 events checked off in the picker.

All 6 events selected. Counter at the top shows 6 selected · 6 shown · 6 in archive. Click Next.

STEP 7

Step 3 — Policy

Three sub-pickers control engine behavior:

The Summary block at the bottom computes the implied heat count live as you change pickers.

Step 3 policy step showing lane-count, distribution, and data-window pickers with their captions and live summary.

8-lane similar-skill, all-time. The summary at the bottom reads 16 athletes · 8-lane heats · 4 track events × 2 heats each = 8 heats total · 2 field events → 2 flights total · ≈ 80 lane assignments to commit.

STEP 8

Step 4 — Review

The wizard runs MeetSeedEngine.seed(...) once per selected event with the chosen policy and renders per-event sections with heat cards inside. Each heat card lists its athletes by lane number; track events get Heat N (slowest/fastest) titles, field events get a single Flight (best → unknown) card.

Without prior race data every lane shows the yellow seed: none capsule. The engine still places athletes in the slowest heat first per locked decision #6 (no-data routes to safety), with serpentine lane assignment within each heat. Drag a lane onto another lane in the same event to swap athletes — both swapped lanes pick up an edited pill that survives across step navigation. Cross-event drags are blocked at the drop site.

Step 4 review pane showing the 100m event split into Heat 1 (slowest) and Heat 2 (fastest), each with 8 lanes of athletes, all marked seed: none.

Review pane with per-event sections. seed: none capsules everywhere because the fixture has no prior race data — in a real archive you'd see seed times alongside athlete names.

Drag-to-tweak preserves edits: manually-edited lanes show an "edited" pill and survive step navigation. The Re-seed unmoved button (visible once you drag anything) reruns the engine over only the non-manual lanes — useful when new PR data arrives or when you want a partial refresh. Reset edits nukes everything back to the engine's default.
STEP 9

Step 5 — Commit

The commit step asks two questions: where to commit (new meet vs add to the iPad's current meet) and the new meet's metadata (name, date, optional location). The destination defaults to "add to current meet" when the iPad has a snapshot live, "create a new meet" otherwise.

The Will create summary tallies what the commit will fan out — distinguishing new event groups from reused ones when committing into an existing meet. Click Commit to iPad to confirm:

Step 5 commit step showing the destination picker, meet metadata form, will-create summary, and the prominent Commit to iPad button.

Commit pane with destination picker + meet form + will-create summary + the prominent Commit to iPad button.

Idempotent fan-out via deferOrSend: every wire op (createMeet → createEventGroup → createDivision → createHeat → submitLaneAssignment) queues through the same offline-aware path the existing Mac authoring flow uses. Commit works offline; the iPad picks up on reconnect. Re-committing the same draft is a no-op — lane assignments overwrite by (heatID, laneNumber).
UNDER THE HOOD

Why this is faster than 480 manual lane assignments

RELATED

The rest of the meet auto-seed workstream

M1 — single-event seeder: a wand button in the Heat Editor footer that opens a one-heat preview sheet. Same engine, scoped to one heat at a time — useful when you've already built the meet structure manually and want to fill lanes from PRs.

M3 — per-athlete event suggestion: the Athlete Detail page gains a "Suggested events" section ranking each event the athlete has 2+ appearances in against teammates who've also raced it. "Add to Seed Wizard" hands the (athlete, event) pair off to this wizard pre-populated on step 2.

M4 — stale-data filter: already integrated into step 3's Data window picker. PRs outside the window route as no-data; in-window-but-older-than-midpoint PRs get a purple "stale" pill in the review pane so you can spot aging data at a glance.

← All walkthroughs Home