Backend validation batch: ScheduleHeat guards, membership pruning, DQ standings symmetry (#335, #336, #339, #341)#346
Merged
Conversation
…ship pruning, DQ metrics, h2h points (#335 #336 #339 #341) Release-review hardening, each fix with tests: - ScheduleHeat validation (#335): reject a duplicate competitor in the lineup; a round tag must name one of the event's rounds; a class tag must be selected by the event and (when a round is also tagged) eligible for it; on a tagged heat, every lineup ref naming a directory pilot must be a member of the tagged round's eligible classes' membership (mirroring the FillRound field / console eligible-members picker). node-{i} timer seats and sim free-text refs still pass, so practice-style heats keep working. - ScheduleHeat duplicate id (#341, VERIFIED by probe): the fold re-seeds a repeated HeatScheduled back to Scheduled, so re-using an id silently reset a finished/Final heat and orphaned its result. Only genuinely-new ids are accepted now (re-runs go through Discard/Restart), on both the event-aware and bare command paths. - Stale membership on shrink (#336): the roster PUT (and the per-pilot DELETE, same hole) now prune classes_membership slots whose pilot left the roster; the classes PUT drops deselected classes' membership entries — so FillRound can no longer seat removed pilots past the #330 membership guard. Surviving members keep their channels; empty entries are dropped. - DQ standings-metric asymmetry (#339): a disqualified placement contributes NO best-lap and NO win-condition metric (lap count / consecutive window) to the standings row — the ranking already excluded it (#331), so the row no longer surfaces values the position ignored. The pilot's clean heats still count; class standings share the fixed best-lap fold. - head_to_head linear points (#341, VERIFIED): the no-table fallback priced a finish by heat.result.places.len(), so a no-show shrank every present pilot's points in that heat. It now prices by the round's group_size (an explicit points table was and is unaffected). Added the missing odd-field tests pinning the [2,2,1] one-pilot trailing heat and the [4,2] short trailing group under both scorings. - heats.contract.ts now builds a real class/roster/membership/round before scheduling a tagged heat (required by the #335 validation) and pins the new rejections over the wire. cargo test --workspace green; cargo fmt + clippy --all-targets -D warnings clean; frontend npm run contract green (9 files, 90 tests) against a rebuilt Director. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 3, 2026
Closed
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #335, #336, #339 and the two confirmed verify-first items from #341 (user-approved fix batch).
places.len(), so a no-show shrank everyone's points that heat; now priced by the round'sgroup_size. Explicit tables unaffected.16 new tests (4 engine, 12 server) + the heats contract rebuilt on a real fixture. Workspace green, clippy clean, contract 90/90.
🤖 Generated with Claude Code