docs/volleyball-rotations.html · 111 tests passingcard-confirmed. Base and
defense were correct in all six rotations.The doc's six rotations are internally consistent, and worth naming: the system is a
6-2. S and RS are the two setters — the back-row one sets, the
front-row one plays right side. That is why S is never front row and RS
never back row, and why R4–R6 repeat R1–R3's shapes with the other bodies in them. Your
Role.isRowLocked model reproduces it correctly.
| Phase | R1 | R2 | R3 | R4 | R5 | R6 | Verdict |
|---|---|---|---|---|---|---|---|
| Base | match | match | match | match | match | match | All six correct. Cycle closes both ways. |
| Receive | match | FAULT | FAULT | match | FAULT | FAULT | Four wrong. See below. |
| Defense | match | match | match | match | match | match | All six correct, including R1's as-drawn exception. |
| FL (4) | FM (3) | FR (2) | BL (5) | BM (6) | BR (1) | |
|---|---|---|---|---|---|---|
| was | RS | S | M | L | OH | OH |
| now | OH | RS | M | L | S | OH |
Two faults in one picture: the setter (zone 6) was standing in front of her partner RS (zone 3), and the outside (zone 4) had drifted to the right of the setter in the front row. Either is a free point for the other team. The app's Whiteboard was teaching as correct a formation its own Thread mode exists to flag as broken.
Whoever transcribed the handout read stretched locations as changed zones. R1 and R4 survived only because nobody in that shape stretches across a zone boundary. And the app's six-cell court could not have expressed it correctly even if the transcription had been right — there was no way to say "same zone, different spot".
That is now the model: zone is the legal truth and never changes between base and receive;
spot is a named place on the floor. Twenty spots cover all eighteen formations and every
rally beat — off-net-left, stack-behind-right,
pass-centre-left, deep-cross, and so on. Each is a name a coach would
actually say, which means the narrator has words and the answer line has something to read out.
The exporter refuses to write if any receive formation differs from its base, and names the exact zones. Verified by reverting R2 to the broken row: it stopped the build and printed all three disagreements.
Every pre-contact formation is checked at its resolved coordinates — row order plus front/back partner. Defense is exempt, deliberately: overlap expires at contact, which is why one defensive picture is legal in all six rotations.
Seven near_positions named the correct answer as a natural mistake.
Latent — no view reads the field yet — but it would have bitten the moment the diagnostic
feedback your guide calls "what is missing" got wired up. Now impossible.
Renaming the phase broke three Stories that cite formations by id. Caught by a Swift test, not by the export — so the export now checks it too.
Overlap in Swift · 15 new testsThe rule existed in three doc comments and no code. It is now a type, with the corpus held against it: receive must match base, every pre-contact formation must be legal at its spots, and no two spots may sit too close to read as two places.
The four rows were card-confirmed. Confidence notes now record what was wrong
and why. R1 defense stays flagged conflicted — the doc confirms it is drawn that
way, but not why it differs from R4.
The old screen offered three phases as peers — "we serve / they serve / ball's live" — which reads as three different rotations. It is one rotation with one base and a fork, and the fork is now drawn rather than described:
The two branches also pose different questions, because they are different kinds of thing. Base asks which zone — the part a referee judges. Receive and defense ask where you stand, because the zones do not change. The receive screen says so out loud in its prompt: "same six zones — now where does she stand". Without that, correcting the data would have made receive a pixel-identical duplicate of base, with nothing left to teach.
A point, narrated beat by beat, under a clock. Six rings appear on the floor — the six places you and your teammates could be — and you tap yours before the next contact. Six rallies, covering all three shapes and both branches.
A missed beat flashes the right spot and the rally plays on, because that is what a rally does. The misses come back at the end, where there is time to look at them.
The wrong rings are always a teammate's real spot, so a miss reads "that's Madison's spot" rather than a red circle. No distractor authoring exists or is needed.
A beat naming a phase cites the rotation's own base / receive / defense entry rather than restating it. Only genuinely rally-shaped moments — free ball, transition, coverage, dig — carry their own spots.
Points resolve with an explicit note: you rotate when you win the serve back — not when you win a point, and not when you keep serving. Rally 5 exists specifically to make that third case land.
Your Press Raven note on The Tag records that the mode's original question — who serves next? — had to be abandoned, because back-right across the six rotations reads S / OH / L / S / OH / L, "which is not a legal serving order, and the libero cannot serve twice".
The doc resolves it. The libero reaches zone 1 twice per cycle because the pairs repeat every three rotations, and she may serve in one of those slots — the other is served by the middle she replaced. R3 the middle serves; R6 is the libero's own turn. The order is six distinct people and entirely legal. The Tag can ask its original question. I have not changed that mode — flagging it as available.
near_positions is authored and still unread by any view. Wiring it into the
Whiteboard's check is the cheapest remaining quality win in the app.High on the correction and the model — those are rule-derived and machine-checked, and I would defend them against the handout. Lower on the rally content, which is the part I authored rather than validated: the shapes are conventional and the voice is modelled, and both want a human pass before you trust them in front of her.
PressRaven-Corpus/guides/stellar-backup-pre-rotation-fix