From a3f306c388205e125bf8b5bbd104c3adff752c1e Mon Sep 17 00:00:00 2001 From: Erol Haagenrud Date: Fri, 21 Aug 2026 08:05:17 +0200 Subject: [PATCH] CHANGELOG: logg for cut-kaskade, sorterbare kolonner, Ny runde-fiksene og Score-fane-rettelsene Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc22853..b0bcf12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13667,3 +13667,255 @@ Neste steg: Ren frontend. `docker compose build teecup_frontend && up -d`, rene logger. Ekstra oppmerksomhet på akkurat denne (automatisk 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: `` 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}` på + 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 `` 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å.**