Update Todos

Designe walkover/konsesjon-API (match- og turnering-nivå)

Implementere apply_concession + POST .../matches/{id}/concede i scoring.py

Implementere POST .../tournaments/{id}/concede i tournaments.py

Skrive ADR-024 for walkover/konsesjon

Scratch-verifisere backend grundig

Bygge frontend-UI for walkover/konsesjon

Ekte typesjekket frontend-build

Deploy etter eksplisitt bekreftelse + oppdatere .md-filer
Walkover/konsesjon er live (ADR-024):

Kun den tapende siden (kaptein, eller org-admin) kan erklære — speiler ekte golf-etikette, ingen kan kreve seier på motstanderens vegne.
Ensidig, ingen bekreftelse fra motparten kreves.
Både match-nivå (session-scorecard.tsx, kollapsbar "Gi opp matchen"-seksjon) og turnering-nivå (tournament-detail.tsx, "Gi opp resten av turneringen"-knapp per lag) — sistnevnte gir opp alle ikke-avgjorte matcher laget har, i én operasjon.
Kan erklæres uansett hvor mange hull som allerede er registrert — allerede registrerte resultater blir stående urørt i scorekortet.
30 automatiserte scratch-sjekker (15 match-nivå + 15 turnering-nivå), typesjekket produksjonsbuild, deployet uten migrasjon, teeoff.no upåvirket. Alle tre .md-filene er oppdatert.
This commit is contained in:
Erol Haagenrud 2026-07-19 21:36:33 +02:00
parent ab23674521
commit dd54a78ce3
3 changed files with 61 additions and 7 deletions

View file

@ -1018,8 +1018,9 @@ nødvendig. Status-teksten "Walkover (A)"/"Walkover (B)" følger samme
"(bokstav)"-visningskonvensjon som `compute_match_state.describe()` sine "(bokstav)"-visningskonvensjon som `compute_match_state.describe()` sine
egne strenger (f.eks. "9&7 (A)"). egne strenger (f.eks. "9&7 (A)").
**Status: ✅ BYGGET 2026-07-19.** Ingen migrasjon (ren applogikk, ingen **Status: ✅ BYGGET OG LIVE 2026-07-19.** Ingen migrasjon (ren applogikk,
skjemaendring). Se CLAUDE.md-status for scratch-verifisering og utrulling. ingen skjemaendring). Se CLAUDE.md-status for scratch-verifisering og
utrulling.
--- ---

View file

@ -1390,13 +1390,66 @@ Ferdig og verifisert:
begge containere boot-et rent (`Application startup complete`, Next.js begge containere boot-et rent (`Application startup complete`, Next.js
`Ready`), `/health` og `/dashboard` → 200, `teeoff.no` upåvirket. `Ready`), `/health` og `/dashboard` → 200, `teeoff.no` upåvirket.
- **Walkover/konsesjon LIVE (2026-07-19, ADR-024):** direkte oppfølging av
Brukerroller-runden samme dag — brukeren ba eksplisitt om å ta fatt på
dette som naturlig neste steg. Løser det lenge kjente hullet: en side som
aldri stiller nok spillere fikk aldri beregnet handicap og matchen kunne
derfor aldri avgjøres — hang uendelig.
Fire beslutninger avklart eksplisitt med bruker (AskUserQuestion) før
bygging — tre anbefalte valg, ett (omfang: match+turnering-nivå samtidig,
ikke bare match) valgt utover anbefalingen.
**Bygget:** ny `apply_concession`-hjelpefunksjon i `app/routers/
scoring.py` (skriver til de samme fire kolonnene som
`recompute_and_cache_match_state` -- `status_text`/`points_side_a/b`/
`leading_side` -- men direkte, ikke utledet fra hull). Ny
`POST /orgs/{id}/matches/{id}/concede` (kun kaptein for det TAPENDE laget,
speiler ekte golf-etikette -- du gir bort DITT tap, krever ikke seier på
motstanderens vegne -- eller org-admin, gjenbruker `user_is_team_captain`
fra ADR-023 uendret). Ny `POST /orgs/{id}/tournaments/{id}/concede`
(`app/routers/tournaments.py`) som gir opp ALLE ikke-avgjorte matcher
laget har i turneringen i én operasjon -- v1s to-lags-grense (ADR-011)
gjør dette trivielt (bare én motstander uansett), `FOR UPDATE`-låser alle
berørte match-rader (samme race-vern som ellers). Kan erklæres uansett
hvor mange hull som allerede er registrert (match-play teller kun
seier/tap/delt for poeng, ikke marginen) -- allerede registrerte hull i
`hole_score`/`match_hole_result` forblir urørt, kun matchens
avgjørelses-felt endres.
**Frontend:** `session-scorecard.tsx` fikk en kollapsbar
"Gi opp matchen (walkover)"-seksjon (to knapper, én per lag, med
bekreftelsessteg) synlig når matchen ikke er avgjort.
`tournament-detail.tsx` sin `TeamPanel` fikk en tilsvarende "Gi opp resten
av turneringen for laget"-knapp nederst i hvert lagkort. Ingen
klientside-forhåndsfiltrering på kapteinstatus noe sted -- begge knappene
vises alltid, en 403 fra backend vises bare som vanlig feiltekst (samme
mønster som resten av appen).
**Verifisert grundig mot fersk `teecup_scratch`** (isolert
`teecup_app_scratch`-rolle, isolert scratch-MinIO, engangs
API-container): to separate 15-punkts Python/httpx-testløp. Match-nivå:
vinnende lags kaptein NEKTES å konsedere på vegne av det tapende laget
(kan ikke kreve seier på andres vegne), tapende lags kaptein FÅR, allerede
avgjort match avvist 409, fremmed team_id avvist 400, konsesjon ETTER at
ett hull allerede er registrert bekreftet å fungere OG bekreftet at det
registrerte hull-resultatet forblir synlig i scorekortet etterpå (ikke
overskrevet), org-admin FÅR konsedere direkte uavhengig av kapteinmerke.
Turnering-nivå: feil lags kaptein nektes, riktig kaptein FÅR gi opp
resten (kun de faktisk ikke-avgjorte matchene telles -- allerede avgjorte
matcher fra match-nivå-testene i samme løp ble korrekt hoppet over),
gjentatt kall er trygt (0 nye, idempotent i praksis), ukjent team_id gir
404. `test_isolation.sql` 12/12 uendret (ingen skjemaendring). Ekte
typesjekket produksjonsbuild av frontend kjørt og bekreftet, alle 11
ruter listet.
**Rullet ut live 2026-07-19**, bruker bekreftet eksplisitt: ingen
migrasjon, `docker compose up -d --build teecup_api teecup_frontend`,
begge containere boot-et rent, `/health` og `/dashboard` → 200,
`teeoff.no` upåvirket.
Neste steg: Neste steg:
1. PWA-egenskaper (manifest, service worker, offline-cache) — ikke startet. 1. PWA-egenskaper (manifest, service worker, offline-cache) — ikke startet.
2. Kommunikasjon (chat/feed) — ikke startet. 2. Kommunikasjon (chat/feed) — ikke startet.
3. Fortsatt åpne beslutninger fra FEATURE_BACKLOG.md: walkover/konsesjon 3. Fortsatt åpne beslutninger fra FEATURE_BACKLOG.md: sanntid/WebSockets vs.
(kan nå tas fatt på — ventet tidligere på brukerroller/ADR-023, som nå er polling, tilskuer-rolle (bevisst utsatt til Kommunikasjon-runden),
avgjort og bygget), sanntid/WebSockets vs. polling, tilskuer-rolle kode-regenerering for ADR-020, turnering-status (draft/active/completed/
(bevisst utsatt til Kommunikasjon-runden), kode-regenerering for ADR-020. archived) via API, korrigering-godkjenning fra motpart.
4. Ved fremtidige nye V0-skjermer/-design i V0 (fortsett i samme prosjekt), 4. Ved fremtidige nye V0-skjermer/-design i V0 (fortsett i samme prosjekt),
FORVENT en full re-eksport hver gang — diff mot live-treet i et FORVENT en full re-eksport hver gang — diff mot live-treet i et
scratch-område før noe pakkes ut over eksisterende filer, og sjekk om scratch-område før noe pakkes ut over eksisterende filer, og sjekk om

View file

@ -352,7 +352,7 @@
Turnering har et `status`-felt (draft/active/completed/archived) men Turnering har et `status`-felt (draft/active/completed/archived) men
INGEN endepunkt endrer det ennå — organisator kan ikke markere en turnering INGEN endepunkt endrer det ennå — organisator kan ikke markere en turnering
ferdig via API-et i dag (eget, senere punkt). ferdig via API-et i dag (eget, senere punkt).
- **Walkover/konsesjon — ✅ BYGGET 2026-07-19 (ADR-024).** Løste det - **Walkover/konsesjon — ✅ BYGGET OG LIVE 2026-07-19 (ADR-024).** Løste det
opprinnelige hullet: en side som aldri stiller nok spillere kan nå opprinnelige hullet: en side som aldri stiller nok spillere kan nå
avsluttes ved at den TAPENDE siden (kaptein, eller org-admin) erklærer avsluttes ved at den TAPENDE siden (kaptein, eller org-admin) erklærer
walkover — ensidig, ingen bekreftelse fra motparten. `POST /orgs/{id}/ walkover — ensidig, ingen bekreftelse fra motparten. `POST /orgs/{id}/