Skip to content

Run the live match in halves, and make the mid-half line-up a plan - #84

Merged
JaspervdM80 merged 3 commits into
mainfrom
claude/games-lineup-labels-fixes-bfkamf
Aug 13, 2026
Merged

Run the live match in halves, and make the mid-half line-up a plan#84
JaspervdM80 merged 3 commits into
mainfrom
claude/games-lineup-labels-fixes-bfkamf

Conversation

@JaspervdM80

Copy link
Copy Markdown
Owner

Two commits that were pushed to this branch after PR #80 merged, so they had no pull request of their own. Opening one now.

The live match runs in halves. "Volgende opstelling" is gone — the button, the service call behind it and the line-up rewrite it did. It was the only thing that made a quarter boundary a moment the clock had to be told about, and what it did at the touchline was never clear. The clock now runs in halves however the line-ups were planned: NextHalf() skips the quarter left behind inside a half already played, so the second half opens at Q3 and Q2 is never kicked off. A period with no timings costs GameMinutesReport nothing, so the half is credited to the line-up that actually played it plus the substitutions made during it.

The model and the services now say "half" where they mean one — CurrentOrLastHalf, LiveHalf, NextHalf, MidHalfPlan, EndHalfAsync, StartNextHalfAsync — because a period row turned out to be what it always was in practice: a planned line-up. The row that opens a half is the one the match is played, timed and recorded with; the row planned for the middle of a half is a plan and nothing else.

The order of match events could be wrong across half time. The scoreboard clock stops at the end of a half, but the minute written down counted straight on, so a goal two minutes into first-half stoppage was stored as 37 and sorted after a goal in the 36th minute of the second half — which happened a minute later. Substitutions were worse: their minute came off the raw elapsed time and ignored the scoreboard clock entirely. A minute is now a MatchMinute pair, 35 or 35+2, compared on both parts so the comparison is chronological across the whole match. A goal stores both halves of the pair; a substitution derives its own from AtSeconds and the period it belongs to. The timeline, the result page's goal list and ScoreProgressionReport all sort on the pair.

The mid-half changes moved into a pop-up behind a "Changes (n)" button on the line-up card. Standing beside the live line-up, a plan reads as the state of play and invites being asked about before it has been carried out; behind a button it is looked up, worked through by tapping the pitch, and dismissed. Still admin-only, still stripped of the swaps play has overtaken, still readable before kick-off.

Migration20260813062317_AddGoalAdditionalMinute adds one nullable-free AdditionalMinute column to GameGoals, with no backfill: nothing left in an old row says whether a stored 37 was stoppage time or a minute typed in by hand, so existing goals keep reading and sorting exactly as they do today. The second commit changes no schema.

Anonymous visibility is unchanged. The live screen and the timeline stay public reads; the changes pop-up is behind the same admin check the card it replaced was.

Worth reading alongside #83, which was filed against this design: it argues the goal should carry GamePeriodId and AtSeconds like a substitution does, so the minute is derived rather than frozen and AdditionalMinute can go again. That is a follow-up to this, not a reason to hold it — the bug fixed here is visible today.

Checked: dotnet build -c Release clean, dotnet test 399/399 at the branch head. I also merged main into the branch locally to see whether PR #81's changes to MatchGoalService and GameGoal collide with the goal-minute work here — they merge clean and the suite stays green, but I did not push that merge, because this branch is still being written to. It is one commit behind main, so it needs the "Update branch" button before the merge button will light up.

🤖 Generated with Claude Code

https://claude.ai/code/session_013ys63zAujLcoaS7UP9F2wm


Generated by Claude Code

claude added 3 commits August 13, 2026 06:31
Two things, both on the live screen.

"Volgende opstelling" is gone: the button, the service call behind it and
the line-up rewrite it did. What it was for was never clear at the
touchline, and it was the only thing that made a quarter boundary a
moment the clock had to be told about. The clock now runs in halves
however the line-ups were planned — Game.NextPeriod() skips the quarter
left behind inside a half already played, so the second half opens at Q3
and Q2 is never kicked off. A period with no timings costs
GameMinutesReport nothing, so the half is credited to the line-up that
actually played it plus the substitutions made during it. The "Changes
at half-way" card stays, and is now purely a list to work through by
tapping the players on the pitch above it.

The order of match events could be wrong across half time. The
scoreboard clock stops at the end of a half, but the minute written down
counted straight on, so a goal two minutes into first-half stoppage was
stored as 37 and sorted after a goal in the 36th minute of the second
half — which happened a minute later. Substitutions were worse: their
minute came off the raw elapsed time and ignored the scoreboard clock
entirely. A minute is now a MatchMinute pair, 35 or 35+2, and comparing
the two parts is chronological across the whole match. A goal stores
both halves of it (new nullable-free AdditionalMinute column, no
backfill — nothing left in an old row says whether a 37 was stoppage
time or typed in by hand); a substitution derives its own from AtSeconds
and the period it belongs to. The timeline, the result page's goal list
and ScoreProgressionReport all sort on the pair.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AfrvWcNR8hMjw3ny6dMemX
The touchline screen dealt in periods: a quarters game's second line-up of
a half showed up as a card beside the pitch, and the clock, the services and
the model all still spoke of periods even though nothing stopped for one.

A period row is now what it always was in practice — a planned line-up. The
row that opens a half is the one the match is played, timed and recorded
with; the row planned for the middle of a half is a plan, and nothing else.
The model, the clock service and the live screen say so: CurrentOrLastHalf,
LiveHalf, NextHalf, MidHalfPlan, EndHalfAsync, StartNextHalfAsync, and
messages that talk about halves rather than periods.

The changes due partway through a half move out of the screen and into a
pop-up behind a "Changes (n)" button on the line-up card. Standing beside
the live line-up, a plan reads as the state of play and invites being asked
about before it is carried out; behind a button it is looked up, worked
through by tapping the pitch, and dismissed. It is still admin-only, still
stripped of the swaps play has overtaken, and still readable before kick-off.

No schema change: what is stored is what was stored, and the minutes a
season is built from are untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AfrvWcNR8hMjw3ny6dMemX
Only the two service summaries in architecture.md and patterns.md clashed:
main reworded them for the goal write that now commits with its scoreline,
this branch reworded them for halves. Both statements are true, so the
merged lines say both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AfrvWcNR8hMjw3ny6dMemX
@JaspervdM80
JaspervdM80 merged commit 6df4e58 into main Aug 13, 2026
4 checks passed
@JaspervdM80
JaspervdM80 deleted the claude/games-lineup-labels-fixes-bfkamf branch August 13, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants