Fiks: eierens statistikknivå/utslag ble ikke lagret i Ny runde-veiviseren (ADR-073)
Eierens spillerobjekt i ny-runde-veiviseren hadde egne teeId/statLevel-felt, kun synkronisert fra state.teeId/state.statLevel ÉN gang da banen først ble valgt. For utslag var dette kosmetisk (submit() leser state.teeId direkte for eieren), men for statistikknivå en reell datafeil: "Statistikk for deg selv"-valget i steg 2 hadde ingen effekt på eierens faktiske innsending, som alltid endte på strokes_only uansett hva som ble valgt. Erstatter den punktvise engangs-synken med én kontinuerlig useEffect i wizard-context.tsx. Bruker-rapportert regresjon (video vedlagt) -- se ADR-073/CHANGELOG for full detalj og verifisering. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
bb087b4437
commit
bf6955bff6
4 changed files with 167 additions and 7 deletions
|
|
@ -7215,6 +7215,100 @@ bruker. Begge containere startet rent.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## ADR-073: Regresjon i "Ny runde"-veiviseren -- eierens statistikknivå (og utslag ved endring) ble ikke lagret (2026-08-15)
|
||||||
|
|
||||||
|
Foranledning: bruker rapporterte at de "til stadighet må gå tilbake å
|
||||||
|
sette utslagssted og statistikktype på nytt før runden begynner", og at
|
||||||
|
"det må ha blitt borte i prosessen, for det fungerte tidligere" --
|
||||||
|
vedla en skjermopptak-video (`Temp-uploads/Video_2026-08-15_070115.mp4`,
|
||||||
|
lest via `ffmpeg` hentet på farten som npm-pakke `ffmpeg-static`, siden
|
||||||
|
ingen video-verktøy fantes fra før og `apt`/`pip` krevde sudo).
|
||||||
|
|
||||||
|
**Videoen viste presist to symptomer for RUNDE-EIEREN** (frittstående
|
||||||
|
runde, `ny-runde/`-veiviseren): (1) endres utslag i "Bane & tid"-
|
||||||
|
bekreftelsesskjermen ETTER at banen først ble valgt, viser steg 3 sitt
|
||||||
|
spillerkort fortsatt det GAMLE utslaget -- (2) "Statistikk for deg
|
||||||
|
selv"-valget i steg 2 ("Spilleform") hadde INGEN effekt på den faktiske
|
||||||
|
innsendingen -- runden ble alltid opprettet med `strokes_only` ("Kun
|
||||||
|
slag") uansett hva som ble valgt der, bekreftet ved å åpne "Rediger" på
|
||||||
|
eget spillerkort i steg 3 rett før innsending.
|
||||||
|
|
||||||
|
**Rotårsak (`wizard-context.tsx`/`step1-course-time.tsx`/`step2-
|
||||||
|
format.tsx`):** eierens spillerobjekt i `state.players[]` har SINE EGNE
|
||||||
|
`teeId`/`statLevel`-felt, atskilt fra de øverste `state.teeId`/`state.
|
||||||
|
statLevel`-feltene steg 1/steg 2 faktisk redigerer. Disse ble tidligere
|
||||||
|
KUN synkronisert i ett øyeblikk -- da banen først velges (`pickCourse()`
|
||||||
|
i `step1-course-time.tsx`, som satte begge samtidig). Endres utslag
|
||||||
|
IGJEN i bekreftelsesskjermen (`Fields()`, linje 746, `onChange={(e) =>
|
||||||
|
patch({ teeId: ... })}`), oppdateres kun det øverste feltet -- for
|
||||||
|
utslag var dette rent KOSMETISK (selve `submit()` i `wizard-context.tsx`
|
||||||
|
leser `state.teeId` direkte for eieren ved selve rundeopprettelsen, se
|
||||||
|
linje 307/311), men for statistikknivå var det en REELL datafeil:
|
||||||
|
`submit()` sin `stat_level`-verdi for eieren leses fra `owner?.
|
||||||
|
statLevel` (spillerobjektet, linje 317) -- IKKE fra `state.statLevel`.
|
||||||
|
`owner.statLevel` settes KUN til `"score"` hardkodet i `loadMe()`
|
||||||
|
(linje 217) når `/auth/me` laster, og synkroniseres ALDRI fra `state.
|
||||||
|
statLevel` når brukeren faktisk gjør et valg i steg 2 -- "Statistikk for
|
||||||
|
deg selv"-seksjonen påvirket dermed KUN default-verdien for NYE
|
||||||
|
medspillere lagt til senere (`defaultStat`-proppen til `AddPlayerPanel`,
|
||||||
|
uendret/fortsatt riktig), aldri eierens eget valg.
|
||||||
|
|
||||||
|
**Ikke en ny mangel -- en bekreftet regresjon:** kommentaren over
|
||||||
|
`pickCourse()` sin manuelle engangs-synk siterte eksplisitt at den
|
||||||
|
"matcher eksakt" den opprinnelige (nå oppdelte) `new-round.tsx` sin
|
||||||
|
`chooseCourse()`-logikk for UTSLAG -- selve engang-synk-mønsteret er
|
||||||
|
altså gammelt og forsettlig replikert ved en tidligere refaktorering til
|
||||||
|
dagens `ny-runde/`-mappestruktur. Ingenting tilsvarende fantes noensinne
|
||||||
|
for STATISTIKKNIVÅ i denne koden -- det er uklart om en eldre
|
||||||
|
enkeltfil-versjon av veiviseren hadde `owner.statLevel` lest direkte fra
|
||||||
|
`state.statLevel` uten et eget spillerfelt (brukerens "det fungerte
|
||||||
|
tidligere" tyder på det), men konklusjonen er uansett den samme: i
|
||||||
|
DAGENS kode har "Statistikk for deg selv" vært virkningsløs for eieren
|
||||||
|
siden splittingen til separate steg-komponenter, sannsynligvis
|
||||||
|
usett fordi standardverdien (`strokes_only`) er nettopp det de fleste
|
||||||
|
runder uansett bruker.
|
||||||
|
|
||||||
|
**Fiks:** i stedet for punktvise manuelle synkroniseringer, en ENKELT
|
||||||
|
`useEffect` i `WizardProvider` (`wizard-context.tsx`) som holder
|
||||||
|
`players[owner].teeId`/`statLevel` KONTINUERLIG i synk med `state.teeId`/
|
||||||
|
`state.statLevel`, uansett hvor mange ganger disse endres eller fra
|
||||||
|
hvilket steg. Kjører kun en faktisk `patch()` når verdiene faktisk
|
||||||
|
avviker (unngår unødvendige re-renders/uendelig løkke). Den nå
|
||||||
|
overflødige manuelle engangs-synken i `pickCourse()` fjernet -- ett
|
||||||
|
sted for denne logikken fremfor to som lett driver fra hverandre igjen.
|
||||||
|
Endrer brukeren stat-nivået sitt EKSPLISITT i steg 3 sitt eget
|
||||||
|
spillerkort (i stedet for steg 2), respekteres det inntil de ev. går
|
||||||
|
TILBAKE til steg 2 og endrer det der igjen (samme presedens-rekkefølge
|
||||||
|
som "siste redigerte felt vinner", ingen ny brukerforvirring innført).
|
||||||
|
|
||||||
|
**Verifisert:** `tsc --noEmit` rent + 45/45 vitest (ingen eksisterende
|
||||||
|
test dekket denne regresjonen -- INGEN ny automatisert test lagt til
|
||||||
|
heller, siden `ny-runde/`-veiviseren ikke har noen eksisterende
|
||||||
|
test-infrastruktur i dette repoet; browserverifisering ansett
|
||||||
|
tilstrekkelig for en ren frontend-tilstandssynk-fiks). Egen
|
||||||
|
scratch-database + scratch `teecup_api`-container (port 18007,
|
||||||
|
live-montert kode) + lokal `next dev` (port 13007), MED en egen bane
|
||||||
|
opprettet med to utslag (for å kunne reprodusere "bytt utslag etter
|
||||||
|
førstevalg") -- gjenskapte videoens eksakte scenario (banevalg → bytt
|
||||||
|
utslag fra standard "32" til "50" i bekreftelsesskjermen → "All
|
||||||
|
statistikk" i steg 2 → steg 3 sitt spillerkort viste nå KORREKT "Utslag:
|
||||||
|
50" og "Alt" (uten regresjonens stale "32"/"Kun slag") → fullført runde
|
||||||
|
→ bekreftet direkte i databasen at BÅDE `round.tee_name_snapshot='50'`
|
||||||
|
OG `round_participant.stat_level='full'` faktisk ble lagret → åpnet
|
||||||
|
scoreregistrering for hull 1, bekreftet at veiviseren auto-hopper videre
|
||||||
|
til Putter-steget (kun mulig for `strokes_and_putts`/`full`, aldri for
|
||||||
|
`strokes_only`) -- beviser fiksen virker HELE VEIEN til faktisk lagret
|
||||||
|
data, ikke bare i visningen. Lys+mørk bekreftet for selve
|
||||||
|
"Ny runde"-veiviseren (steg 1-3). Scratch-stacken fullstendig revet ned
|
||||||
|
-- ekte `teecup_db`/`teecup_api`/`teecup_frontend` urørt.
|
||||||
|
|
||||||
|
**Ingen migrasjon** -- ren frontend-tilstandssynk-fiks.
|
||||||
|
|
||||||
|
**IKKE rullet ut ennå** -- venter på eksplisitt bekreftelse fra bruker
|
||||||
|
før `teecup_frontend` bygges/startes på nytt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Utviklingsplan (rekkefølge)
|
## Utviklingsplan (rekkefølge)
|
||||||
|
|
||||||
1. ✅ Land tenant-modell → **Organisasjon** (ADR-001/002/003)
|
1. ✅ Land tenant-modell → **Organisasjon** (ADR-001/002/003)
|
||||||
|
|
|
||||||
44
CHANGELOG.md
44
CHANGELOG.md
|
|
@ -11485,3 +11485,47 @@ Neste steg:
|
||||||
**Rullet ut 2026-08-15** -- ingen migrasjon, `docker compose build
|
**Rullet ut 2026-08-15** -- ingen migrasjon, `docker compose build
|
||||||
teecup_api teecup_frontend && up -d` etter eksplisitt bekreftelse fra
|
teecup_api teecup_frontend && up -d` etter eksplisitt bekreftelse fra
|
||||||
bruker. Begge containere startet rent.
|
bruker. Begge containere startet rent.
|
||||||
|
|
||||||
|
89. **Fiks: eierens statistikknivå (og utslag ved endring) ble ikke
|
||||||
|
lagret i "Ny runde"-veiviseren (ADR-073) — 2026-08-15.** Bruker
|
||||||
|
rapporterte at de "til stadighet må" sette utslag/statistikktype på
|
||||||
|
nytt, og at "det må ha blitt borte i prosessen, for det fungerte
|
||||||
|
tidligere" -- vedla en skjermopptak-video som viste to symptomer.
|
||||||
|
|
||||||
|
Rotårsak: eierens spillerobjekt i veiviserens `state.players[]` har
|
||||||
|
EGNE `teeId`/`statLevel`-felt, atskilt fra `state.teeId`/`state.
|
||||||
|
statLevel` (de faktiske feltene steg 1/steg 2 redigerer) -- kun
|
||||||
|
synkronisert ÉN gang, da banen først velges. For utslag var
|
||||||
|
konsekvensen rent kosmetisk (steg 3 viste et gammelt utslag, men
|
||||||
|
selve innsendingen leste `state.teeId` direkte for eieren) -- for
|
||||||
|
statistikknivå var det en REELL datafeil: `submit()` leser eierens
|
||||||
|
`stat_level` fra spillerobjektet (hardkodet `"score"` fra `/auth/me`-
|
||||||
|
lastingen), ALDRI fra `state.statLevel` -- "Statistikk for deg
|
||||||
|
selv"-valget i steg 2 var dermed virkningsløst for eieren, kun
|
||||||
|
default for NYE medspillere lagt til senere.
|
||||||
|
|
||||||
|
Fiks: én samlet `useEffect` i `wizard-context.tsx` som holder
|
||||||
|
eierens spillerobjekt kontinuerlig i synk med `state.teeId`/`state.
|
||||||
|
statLevel`, uansett hvor mange ganger de endres eller fra hvilket
|
||||||
|
steg -- erstatter den tidligere punktvise engangs-synken i
|
||||||
|
`pickCourse()` (fjernet, nå overflødig).
|
||||||
|
|
||||||
|
**Verifisert:** `tsc --noEmit` rent + 45/45 vitest (ingen eksisterende
|
||||||
|
testinfrastruktur for `ny-runde/`-veiviseren i dette repoet -- ingen
|
||||||
|
ny automatisert test lagt til, browserverifisering ansett
|
||||||
|
tilstrekkelig for en ren tilstandssynk-fiks). Scratch-database +
|
||||||
|
scratch `teecup_api` (port 18007, live-montert kode) + lokal `next
|
||||||
|
dev` (port 13007) med en egen bane med to utslag: gjenskapte
|
||||||
|
videoens eksakte scenario (bytt utslag etter førstevalg, velg "All
|
||||||
|
statistikk") -- steg 3 viste nå korrekt utslag+nivå, OG bekreftet
|
||||||
|
direkte i databasen at både `round.tee_name_snapshot` og
|
||||||
|
`round_participant.stat_level='full'` faktisk ble lagret (ikke bare
|
||||||
|
riktig i visningen) -- scoreregistreringen auto-hoppet deretter
|
||||||
|
videre til Putter-steget, kun mulig for `full`. Lys+mørk bekreftet.
|
||||||
|
Scratch-stacken fullstendig revet ned -- ekte `teecup_db`/
|
||||||
|
`teecup_api`/`teecup_frontend` urørt.
|
||||||
|
|
||||||
|
**Ingen migrasjon** -- ren frontend-tilstandssynk-fiks.
|
||||||
|
|
||||||
|
**IKKE rullet ut ennå** -- venter på eksplisitt bekreftelse fra
|
||||||
|
bruker før `teecup_frontend` bygges/startes på nytt.
|
||||||
|
|
|
||||||
|
|
@ -28,19 +28,16 @@ export function Step1CourseTime() {
|
||||||
}
|
}
|
||||||
const compatible = state.ownGender ? course.tees.filter((t) => t.genders.includes(state.ownGender!)) : course.tees
|
const compatible = state.ownGender ? course.tees.filter((t) => t.genders.includes(state.ownGender!)) : course.tees
|
||||||
const tee = compatible[0]
|
const tee = compatible[0]
|
||||||
|
// Eierens EGET spillerkort (steg 3) sitt teeId-felt synkroniseres nå
|
||||||
|
// løpende fra state.teeId av en egen effekt i wizard-context.tsx
|
||||||
|
// (fanger også senere endringer i "Bane & tid"-bekreftelsen, ikke bare
|
||||||
|
// dette førstevalget) -- ingen manuell synk nødvendig her lenger.
|
||||||
patch({
|
patch({
|
||||||
course,
|
course,
|
||||||
courseMeta: meta,
|
courseMeta: meta,
|
||||||
courseSource: meta.source === "teeoff" ? "official" : "own",
|
courseSource: meta.source === "teeoff" ? "official" : "own",
|
||||||
teeId: tee?.id,
|
teeId: tee?.id,
|
||||||
s1Sub: "fields",
|
s1Sub: "fields",
|
||||||
// Eierens EGET spillerkort (steg 3) har sitt eget teeId-felt, atskilt
|
|
||||||
// fra state.teeId over -- uten denne synkroniseringen viser kortet
|
|
||||||
// "Ikke valgt" selv om et utslag faktisk er valgt (kun kosmetisk, selve
|
|
||||||
// innsendingen leser state.teeId direkte for eieren -- men samme
|
|
||||||
// synkronisering som den opprinnelige new-round.tsx sin chooseCourse()
|
|
||||||
// gjorde, så oppførselen matcher eksakt).
|
|
||||||
players: state.players.map((p) => (p.kind === "owner" ? { ...p, teeId: tee?.id } : p)),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -228,6 +228,31 @@ export function WizardProvider({
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// Eierens EGET teeId/statLevel-felt i players[] (lest av steg 3 sitt
|
||||||
|
// spillerkort, OG -- for statLevel -- av submit() sin faktiske innsending,
|
||||||
|
// se linje ~317) er egne, atskilte felt fra state.teeId/state.statLevel
|
||||||
|
// (steg 1/steg 2 sine felt). De ble tidligere kun synkronisert ÉN gang,
|
||||||
|
// idet banen først velges (pickCourse i step1-course-time.tsx) -- endrer
|
||||||
|
// brukeren utslag i "Bane & tid"-bekreftelsen ETTERPÅ, eller statistikknivå
|
||||||
|
// i "Spilleform", flyter de to fra hverandre. For utslag var dette rent
|
||||||
|
// kosmetisk (steg 3 viste et gammelt utslag, men submit() leser
|
||||||
|
// state.teeId direkte for eieren) -- for statistikknivå var det en REELL
|
||||||
|
// datafeil: "Statistikk for deg selv"-valget i steg 2 hadde INGEN effekt
|
||||||
|
// på selve innsendingen for eieren (kun på default for NYE medspillere via
|
||||||
|
// defaultStat-proppen), siden owner.statLevel forble hardkodet "score" fra
|
||||||
|
// loadMe() over. Bruker-rapportert regresjon 2026-08-15 (video vedlagt) --
|
||||||
|
// holder nå de to i kontinuerlig synk fremfor kun ved første valg.
|
||||||
|
useEffect(() => {
|
||||||
|
setState((s) => {
|
||||||
|
const owner = s.players.find((p) => p.kind === "owner")
|
||||||
|
if (!owner || (owner.teeId === s.teeId && owner.statLevel === s.statLevel)) return s
|
||||||
|
return {
|
||||||
|
...s,
|
||||||
|
players: s.players.map((p) => (p.kind === "owner" ? { ...p, teeId: s.teeId, statLevel: s.statLevel } : p)),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [state.teeId, state.statLevel])
|
||||||
|
|
||||||
const hasTeamStep = showsTeamStep(state.format)
|
const hasTeamStep = showsTeamStep(state.format)
|
||||||
const visibleSteps = useMemo(() => (hasTeamStep ? [1, 2, 3, 4, 5] : [1, 2, 3, 5]), [hasTeamStep])
|
const visibleSteps = useMemo(() => (hasTeamStep ? [1, 2, 3, 4, 5] : [1, 2, 3, 5]), [hasTeamStep])
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue