CHANGELOG: logg for cut-kaskade, sorterbare kolonner, Ny runde-fiksene og Score-fane-rettelsene

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Erol Haagenrud 2026-08-21 08:05:17 +02:00
parent e940e932c1
commit a3f306c388

View file

@ -13667,3 +13667,255 @@ Neste steg:
Ren frontend. `docker compose build teecup_frontend && up -d`, rene Ren frontend. `docker compose build teecup_frontend && up -d`, rene
logger. Ekstra oppmerksomhet på akkurat denne (automatisk logger. Ekstra oppmerksomhet på akkurat denne (automatisk
hull-fremgang etter siste spiller) anbefalt i faktisk bruk. hull-fremgang etter siste spiller) anbefalt i faktisk bruk.
144. **Cut-overlevere kaskaderes automatisk til alle senere runder,
2026-08-20 (ADR-095).** Bruker: "I eksempelturneringen vår opererer
vi med cut etter runde 1. På et vis burde de som har klart cut'en
autoselekteres på runde 2?" Undersøkt (read-only, Explore-agent) før
bygging: `tournament_round_participant`-rader opprettes kun på
forespørsel, aldri på forhånd for alle runder -- ingen eksisterende
mekanisme for dette.
To designbeslutninger bekreftet av bruker etter at jeg foreslo en
snevrere variant: (1) kaskade til ALLE runder etter cut, ikke bare
den neste -- "Har du klart cut'en spiller du alle påfølgende
runder." (2) fjern kuttede spilleres rundedeltakelse i senere runder
(ikke bare la stå blokkert) -- "Jo, fjern de. Dette får vi heller
reversere om det viser seg å være en dårlig beslutning," etter at
jeg opplyste at sletting kaskaderer til `tournament_round_hole`
(migrasjon 040, `ON DELETE CASCADE`).
Ny `_sync_post_cut_round_participation`-funksjon
(`app/routers/individual_tournaments.py`), kalt fra `apply_cut` i
samme transaksjon: for hver runde etter cut -- overlevere som
mangler en rad får én auto-INSERT-et (tee kopiert fra cut-runden,
handicap regnet ut med samme funksjon `add_round_participant`
bruker); kuttede spilleres eksisterende rad SLETTES, MEN kun hvis
den ikke allerede har registrert score (beskytter ekte data mot
kaskade-sletting). Idempotent, som resten av `apply_cut`.
`CutResult` fikk nytt felt `added_to_later_rounds`, vist i "Anvend
cut"-bekreftelsen. `SetupTab` nullstiller nå hele
`roundParticipantsByRound` etter "Anvend cut" (flere runder kan
endres samtidig) i stedet for å refreshe kun én.
**Testet, ikke bare gjennomgått:** 5 nye tester lagt til
`tests/test_cut.py`, kjørt mot en isolert scratch-database
(`./scripts/run_backend_tests.sh`) -- auto-tillegg med riktig
kopiert tee, fjerning av kuttede spilleres rad, IKKE-fjerning når
scorer finnes (+ bekreftet at 403-sperren fortsatt fungerer der),
kaskade til runde 3 uten runde 2 i mellom. Én eksisterende test
fikk sin forventning riktig oppdatert fra 403 til 404 (raden
slettes nå, blokkeres ikke lenger). Alle 156 backend-tester grønne.
**Rullet ut 2026-08-20** -- bruker bekreftet ("Suprt! Da kjører vi
på!"), etter en presiseringsrunde om hva "fjernes" faktisk betyr
(deselekteres fra runden, IKKE fjernet fra deltakerlisten eller
spillerpoolen). `docker compose build teecup_api teecup_frontend &&
up -d`, begge containere friske, rene logger. Ingen migrasjon
nødvendig.
145. **Sorterbare kolonner i Spillere-tabellen (turneringsoppsett),
2026-08-20.** V0-prompt (`v0-prompt-players-table-sort.md`, sortering
ALENE -- en tidligere prompt som også inkluderte en bulk-
utslagssted-flyt ble uttrykkelig trukket av bruker: "Jeg glemmer at
sjekkboksene er for HVEM SOM SKAL SPILLE RUNDEN. Ikke gjør hva jeg
ba deg om (med unntak av sorteringsmuligheten)"). V0-mønsteret
(klikk header -> stigende -> synkende -> opprinnelig rekkefølge,
`aria-sort`, pil-indikator kun på aktiv kolonne, ekte fokuserbar
knapp) integrert i den ekte `tournament-players-table.tsx` for de syv
ikke-runde-kolonnene (Spiller/Hcp/Klasse/Statistikknivå/Status/
Kjønn/Alder) -- runde-kolonnene og handlingskolonnen forblir
usorterbare, urørt.
Klasse-sortering slår opp klassenavn via `classId` (`classNameById`,
utledet fra `classes`-proppen); statistikknivå/status sorteres etter
en meningsfull rangering (mengde sporing / alvorlighet), ikke
alfabetisk. Null-verdier sorteres alltid sist, uansett retning.
**Verifisert i scratch mot den EKTE komponenten** (ikke V0-mocken):
egen `tmp-preview`-rute som monterer `TournamentPlayersTable` direkte
med realistisk mock-data, `evaluate_script`-sjekker av faktisk
radrekkefølge OG `aria-sort`-verdi gjennom alle tre klikk-sykluser
(stigende/synkende/opprinnelig) for både numerisk (Hcp) og
oppslags-basert (Klasse) sortering -- begge korrekte, inkludert
null-sist-oppførsel. `tsc --noEmit` rent. Scratch-ruten slettet
etterpå, bekreftet med `git status --short`.
**Rullet ut 2026-08-20** -- samlet med #144. Ren frontend, samme
`docker compose build teecup_frontend && up -d`, rene logger.
146. **Flytende "Registrer score" forsvant helt ved mange hindringer,
2026-08-20.** Bruker viste skjermbilde: knappen manglet når hullet
hadde mange registrerte hindringer -- selv om banekartet ALDRI ble
utvidet.
Rot-årsak: den flytende knappens synlighet var styrt av `mapExpanded`
alene (#140-#142). Feil premiss -- ADR-083 gjorde at
"compact"-visningen (kartet IKKE utvidet) OGSÅ viser hele
hindringslisten, ikke bare nærmeste. På et hull med mange hindringer
(7 i brukerens tilfelle) blir denne listen alene høy nok til å dytte
den vanlige side-flyt-knappen utenfor synlig område -- akkurat den
situasjonen den flytende knappen skulle dekke, men trigget aldri
fordi `mapExpanded` fortsatt var `false`.
Rettet ved å bytte ut det indirekte signalet (`mapExpanded`) med et
direkte: er selve side-flyt-knappen faktisk synlig akkurat nå. Ny
`inFlowButtonRef` + `inFlowButtonVisible`-tilstand, målt med samme
`getBoundingClientRect()` + scroll/resize-lytter-mønster som
`playerListReached` (ikke IntersectionObserver, se begrunnelse i
kodekommentaren fra #141). Side-flyt-knappen fjernet fra sin
`{!mapExpanded && ...}`-betingelse -- ligger nå ALLTID i normal flyt,
uansett kart-tilstand. Den flytende knappen vises når
`!inFlowButtonVisible && !playerListReached` (før: `mapExpanded &&
!playerListReached`).
**Verifisert i scratch, ikke bare gjennomgått:** egen
`tmp-preview`-rute som monterer den EKTE `RoundDetail` (kun
`roundId`-prop, ingen egen mock-versjon), med `window.fetch`-mock for
runde/deltakere/hull-data og et hindringssett som gjenskaper
brukerens skjermdump nøyaktig (7 hindringer, samme typer/avstander).
`evaluate_script`-målt gjennom fire scenarioer: (1) mange hindringer,
kart ALDRI utvidet -- flytende knapp korrekt synlig
(`aria-hidden="false"`) siden side-flyt-knappen satt bak headeren;
(2) scroll til side-flyt-knappen faktisk er fri av headeren -- flytende
knapp korrekt skjult; (3) hull UTEN hindringer -- flytende knapp
forblir skjult hele veien, ingen regresjon; (4) kart utvidet (det
opprinnelige brukstilfellet) -- samme korrekte oppførsel som før,
pluss `playerListReached`-skjuling ved scroll til spillerlisten
fortsatt intakt. `tsc --noEmit` rent. Scratch-ruten slettet etterpå,
bekreftet med `git status --short`.
**Rullet ut 2026-08-20** -- bruker bekreftet ("Bygg og deploy").
`docker compose build teecup_frontend && up -d`, container frisk,
rene logger. Ingen migrasjon, ren frontend.
147. **Tre ting i "Ny runde"-veiviseren, 2026-08-20 (bruker, skjermdump av
Spillere-steget).**
1. **"Administrer runde"-overleggsmenyen lukket seg ikke selv etter
"Spillere og runde" ble trykket** -- måtte lukkes manuelt for å se
siden under. Rot-årsak: `<Link href={manageHref}>` i
`ManageRoundDialog` (round-header.tsx) navigerer ofte KUN til en
søkeparameter-endring (`?tab=manage`) på samme rute -- ingen
remount, så dialogens lokale `manageOpen`-state (eid av
`RoundHeader`) forble uendret. Rettet med `onClick={onClose}`
selve lenken, i tillegg til navigasjonen.
2. **Kunne ikke overstyre HCP for en nylig lagt til, kontokoblet
medspiller i selve veiviseren** -- feltet viste kun en read-only
"X · hentes fra profilen"-tekst. Fungerte allerede via "Runde og
runde" (PATCH .../participants/{id}) senere i runden, men ikke fra
start. To lag:
- **Backend** (`add_participant`, app/routers/rounds.py): POST-
endepunktet ignorerte `body.handicap_index` HELT for en
`user_id`-koblet deltaker (brukte alltid profilens verdi
direkte) -- ulikt PATCH-endepunktet (`update_participant`), som
allerede æret en eksplisitt overstyring for enhver deltaker,
ikke bare gjester (bekreftet i kode: `guest_only_fields`-sperren
ekskluderer bevisst `handicap_index`). Rettet til `body.
handicap_index if body.handicap_index is not None else target
["handicap_index"]`, i tråd med ADR-038 sin allerede dokumenterte
"MANUELT satt ... med mindre eksplisitt overstyrt"-modell.
- **Frontend** (`step3-players.tsx`): HCP-feltet for en
kontokoblet, ikke-eier-spiller gjort redigerbart (samme `Field`/
`TextInput`-mønster som allerede brukt for gjester i samme fil),
forhåndsutfylt med profilverdien, urørt betyr fortsatt "bruk
profilen". `wizard-context.tsx` sin `submit()` sender nå
`handicap_index: p.hcp ?? null` også for kontokoblede
deltakere (uendret verdi er en trygg no-op, siden backend
faller tilbake til profilen når feltet er urørt).
- Ny backend-test `test_add_participant_hcp_override.py` (2 tester
-- overstyring æres, OG regresjonsvern: uendret oppførsel når
ingen overstyring gis), kjørt mot scratch-database
(`./scripts/run_backend_tests.sh`), alle 158 tester grønne.
3. **Standard statistikknivå for en NY medspiller var "Alt", skal
være "Kun slag"** -- `defaultStat`-proppen til `AddPlayerPanel`
speilet feilaktig `state.statLevel` (scoreførerens EGET valgte
nivå fra "Spilleform"-steget), ikke et fast "Kun slag"-utgangs-
punkt for ANDRE spillere. Bekreftet ved kodegjennomgang: en
tilstøtende kommentar i wizard-context.tsx (fra en tidligere,
urelatert rettelse 2026-08-15) dokumenterer eksplisitt at
`defaultStat` alltid var MENT som "default for NYE medspillere",
atskilt fra eierens eget felt -- speilingen var en glipp, ikke et
bevisst valg. Rettet til en fast `"score"` i `step3-players.tsx`.
Organisatoren kan fortsatt sette et høyere nivå manuelt per
medspiller.
**Verifisert i scratch, ikke bare gjennomgått, for alle tre:**
(1) egen `tmp-preview`-rute som monterer den EKTE `RoundHeader`,
bekreftet via `evaluate_script` at dialogen (`[role="dialog"]`) er
borte fra DOM-en umiddelbart etter klikk+navigasjon, ingen manuell
lukking nødvendig. (2)+(3) egen `tmp-preview`-rute som monterer den
EKTE `WizardProvider` + `Step3Players` (med `window.fetch`-mock for
`/auth/me` og `/people/search`), drevet gjennom hele den ekte søk-og-
legg-til-flyten (søkte "Morten", la til kontoen, ekspanderte kortet)
-- bekreftet HCP-feltet er en ekte, redigerbar `<input>` forhånds-
utfylt med 11.1, aksepterer et desimaltall (satt direkte via
`dispatchEvent` for å utelukke en `fill`-verktøy-særegenhet som først
strippet punktumet), OG at "Kun slag" er forhåndsvalgt for den nylig
lagte-til spilleren. `tsc --noEmit` rent gjennom hele. Begge
scratch-rutene slettet etterpå, bekreftet med `git status --short`.
**Rullet ut 2026-08-20** -- bruker bekreftet ("Ja takk").
`docker compose build teecup_api teecup_frontend && up -d`, begge
containere friske, rene logger. Ingen migrasjon.
148. **Hindringslisten sortert feil vei + kartretning ved slagmåling nå
styrt av ekte utslag→green-geometri, 2026-08-21.** Bruker, med
skjermdump: holdes telefonen loddrett for avstandsmåling, bør det
som er lengst unna (greenen) stå øverst i lista og det nærmeste
(utslaget) nederst, med hindringene sortert i SAMME rekkefølge
imellom -- listen viste tidligere motsatt (nærmeste hindring øverst,
rett attmed greenen). Presisert: der en hindring har både forkant og
bakkant vist, er det BAKKANTEN (fjerneste kant) som skal styre
sorteringen.
To sorteringssteder i `hole-target-distance.tsx` rettet fra stigende
til synkende (lengst unna FØRST): `groupDiagramHazards()` sin
`entities.sort(...)` (den parrede forkant/bakkant-visningen, brukt av
`HoleDiagram` -- nøkkel endret fra alltid `below` til `above ?? below`,
altså bakkanten når en finnes), og den enklere flate listen (`hazards
.sort(...)`, brukt når banen mangler tee-koordinater -- ingen
forkant/bakkant-parring der, kun ett tall per punkt).
**Samme runde, andre delen av brukerønsket:** på baner med BÅDE
utslags- OG green-koordinater kjent, skal selve satellittkartet i
slagmåleren ("Mål et slag") vises med greenen opp/utslaget ned, ikke
nord opp. `initialBearing`-mekanismen fantes allerede (bygget
2026-08-10, roterte kartet etter spillerens EGEN forrige slag-
retning på hullet, `bearingDegrees(forrige slag start, slutt)`) --
denne er nå supplert med en NY, mer pålitelig kilde: `ShotMeasurement
Entry` (fellet-komponenten brukt fra alle tre stedene i filen
slagmåling kan åpnes fra: kompakt spillerkort, delt-ball-sidebadge,
og full-skjerm-veiviserens "Retning"-steg) henter nå selv hullets
`target-points`, regner ut `bearingDegrees(midtpunkt(utslag front/
bakkant), green senter)`, og lar DENNE vinne over forrige-slag-
gjetningen når den finnes -- ekte banegeometri er mer pålitelig enn
en tilfeldig sleng/hook på forrige slag. Egen, liten fetch per
spillerkort (i stedet for å prop-drille et tall gjennom RoundDetail/
PlayerHoleCards/ScoringWizard for å dele HoleTargetDistance sin
allerede-eksisterende henting) -- en akseptert kostnad for at ALLE
tre inngangene til kartet får riktig retning samtidig, ikke bare én.
**Verifisert i scratch, presist, ikke bare gjennomgått:** egen
`tmp-preview`-rute som monterer den EKTE `RoundDetail`, med
`window.fetch`-mock for `target-points` (utslag+green forskjøvet til
en bevisst IKKE-kardinal (ikke nord/øst/sør/vest) retning, for å
fange opp en feil som ved et uhell falt tilbake til "ingen
rotasjon"). Ekte `NEXT_PUBLIC_MAPBOX_TOKEN` lest fra `.env` inn i
scratch-serverens miljø (aldri skrevet i klartekst noe sted).
`mapboxgl.Map`-konstruktøren instrumentert (kun i scratch, aldri i
kildekoden) til å fange opp `bearing`-verdien den faktisk mottok.
Gikk gjennom hele den ekte flyten (ekspander spillerkort -> "Mål et
slag" -> "Velg punkt på kart") og bekreftet numerisk: forventet
`19.02°` (regnet uavhengig, samme formel, i selve scratch-siden) mot
faktisk mottatt `19.016306...°` -- match. Selve korttavlerenderingen
feilet med "Kunne ikke laste kartet" pga. manglende ekte nettverks-
tilgang til Mapbox sine tile-servere i dette sandkasse-miljøet
(urelatert til retting -- `bearing`-argumentet appliseres synkront
ved konstruksjon, uavhengig av om selve kart-flisene faktisk laster).
`tsc --noEmit` rent. Scratch-ruten slettet etterpå, bekreftet med
`git status --short`.
**Ikke rullet ut ennå.**