From 8b1c73cf4f91708efdcf5893d0439efba57f34e0 Mon Sep 17 00:00:00 2001 From: Erol Haagenrud Date: Sat, 8 Aug 2026 12:37:09 +0200 Subject: [PATCH] =?UTF-8?q?Fiks=20rundedeling:=20minst=20=C3=A9n=20kategor?= =?UTF-8?q?i=20er=20nok,=20ikke=20alle=20(ADR-036=20E)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bruker rapporterte at en runde delt med kategorien "Make" ikke ble synlig for vedkommendes ektefelle. Diagnostisert direkte mot ekte teecup_db (skrivebeskyttede spørringer): eieren hadde kategorisert ektefellen under tre kategorier, mens runden kun delte to av dem. _can_view_round krevde at ALLE en venns kategorier måtte være i rundens synlige sett -- en presisering fra 2026-07-29 som kun ble dokumentert i kode-kommentarer, aldri i denne ADR-en, og som strammet inn utover ADR-036 Beslutning B sin opprinnelige "minst én kategori"-regel fra 2026-07-25. Reversert til den opprinnelige regelen i alle fire duplikate SQL-steder (_can_view_round, _friends_who_can_see_round, list_friends_on_course i rounds.py; feed-listingen i round_messages.py) -- fra "NOT EXISTS en kategori utenfor synlig sett" til "EXISTS en kategori innenfor synlig sett". Scratch-verifisert i begge retninger: venn med overlappende kategori slipper nå inn, venn med ingen overlappende kategori fortsatt korrekt avvist. Se CHANGELOG.md punkt 44 for full verifiseringsdetalj og bekreftelse mot de ekte, virkelige dataene etter utrulling. --- ARCHITECTURE_DECISIONS.md | 31 ++++++++++++++++++++++++++ app/routers/round_messages.py | 6 +---- app/routers/rounds.py | 41 +++++++++++++---------------------- 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/ARCHITECTURE_DECISIONS.md b/ARCHITECTURE_DECISIONS.md index 9f22544..0c24766 100644 --- a/ARCHITECTURE_DECISIONS.md +++ b/ARCHITECTURE_DECISIONS.md @@ -3207,6 +3207,37 @@ søk-UI i `round-detail.tsx`, "Gjest" omdøpt til "Medspiller" gjennomgående, samme viewer-relative "Deg"-fiks portert til `round-stats.tsx`/ `round-scorecard.tsx`, som hadde samme latente bug). +### Beslutning E — Kategori-match ved rundevisibilitet: MINST ÉN, ikke ALLE + +Beslutning B punkt 5 (over) spesifiserte fra start "minst én +`friend_categorization`-rad ... hvor kategorien finnes i +`round_visible_category`". En senere presisering 2026-07-29 (kun +dokumentert i kode-kommentarer, aldri i denne ADR-en — selve +dokumentasjonshullet som gjorde denne avviket vanskelig å spore) strammet +dette til at ALLE en venns kategorier måtte være i rundens synlige sett, +ikke bare én. + +**Reversert til original Beslutning B-regel 2026-08-08**, etter at +brukeren rapporterte at en runde delt med kategorien "Make" ikke ble +synlig for vedkommendes ektefelle. Årsak: ektefellen var i tillegg +kategorisert "Storfamilie" (Beslutning A tillater flere kategorier per +venn), og siden "Storfamilie" ikke var huket av på DENNE runden, blokkerte +den strenge ALLE-regelen hele synligheten -- til tross for at den +relevante kategorien ("Make") faktisk var valgt. I praksis gjorde dette +det nærmest umulig å dele pålitelig med noen som var tagget i mer enn én +kategori, uten å huke av samtlige av dem hver gang. + +**Ny/gjeninnført regel:** en venn ser runden hvis MINST ÉN av kategoriene +eieren har satt dem i, er i rundens synlige sett -- flere kategorier på +samme venn er bare flere sjanser til å matche, aldri en ekstra +begrensning. En venn med INGEN kategorier vises fortsatt aldri (uendret). + +Rettet i fire duplikate SQL-steder (`app/routers/rounds.py`: +`_can_view_round`, `_friends_who_can_see_round`, +`list_friends_on_course`; `app/routers/round_messages.py`: feed- +listingen) -- samme sted-for-sted-duplisering som opprinnelig omtalt i +Beslutning B, nå alle konsistent på MINST ÉN-varianten. + --- ## ADR-037: Individuelle turneringer, flerrunde-turneringer — grunnstruktur diff --git a/app/routers/round_messages.py b/app/routers/round_messages.py index 9d67042..1c29ccf 100644 --- a/app/routers/round_messages.py +++ b/app/routers/round_messages.py @@ -511,11 +511,7 @@ async def get_feed( AND EXISTS ( SELECT 1 FROM friend_categorization fc WHERE fc.owner_user_id = r.owner_user_id AND fc.friend_user_id = $1 - ) - AND NOT EXISTS ( - SELECT 1 FROM friend_categorization fc - WHERE fc.owner_user_id = r.owner_user_id AND fc.friend_user_id = $1 - AND fc.category NOT IN ( + AND fc.category IN ( SELECT category FROM round_visible_category WHERE round_id = r.id ) ) diff --git a/app/routers/rounds.py b/app/routers/rounds.py index 538b362..d8dfc2c 100644 --- a/app/routers/rounds.py +++ b/app/routers/rounds.py @@ -2031,13 +2031,15 @@ async def _can_view_round(conn, round_id: str, viewer_user_id: str | None) -> bo # kategorisering av viewer (ikke omvendt -- det er eieren som # begrenser, basert på egen gruppering, ADR-036 Beslutning B). # - # Presisert av bruker 2026-07-29: "ikke vise" overstyrer "vise" -- er - # vennen satt i FLERE kategorier, holder det IKKE at én av dem er - # synlig for runden; ALLE vennens kategorier må være i rundens synlige - # sett. En venn med INGEN kategorier i det hele tatt vises ALDRI (samme - # runde: kategorisering er nå obligatorisk fra vennskapet inngås, se - # friends.py -- en ukategorisert venn er derfor alltid en igjenværende - # unntakstilstand fra FØR den regelen, ikke en normal, forventet sti). + # Regel: MINST ÉN av vennens kategorier må være i rundens synlige sett + # (ADR-036 Beslutning E, 2026-08-08). En strengere "ALLE kategorier må + # være synlige"-variant gjaldt 2026-07-29--2026-08-08, men ga et reelt + # forvirrende utfall i praksis (bruker delte en runde med "Make" + # huket av, men vedkommendes ektefelle -- ALSO tagget "Storfamilie" -- + # fikk ikke se runden fordi den kategorien ikke var huket av). Reversert + # til den opprinnelige ADR-036 Beslutning B-regelen (som alltid sa + # "minst én kategori", se punkt 5 der) etter brukerrapport. En venn med + # INGEN kategorier i det hele tatt vises fortsatt ALDRI. if viewer_user_id is None: return False owner_id = row["owner_user_id"] @@ -2060,11 +2062,7 @@ async def _can_view_round(conn, round_id: str, viewer_user_id: str | None) -> bo SELECT EXISTS( SELECT 1 FROM friend_categorization WHERE owner_user_id = $1 AND friend_user_id = $2 - ) - AND NOT EXISTS( - SELECT 1 FROM friend_categorization fc - WHERE fc.owner_user_id = $1 AND fc.friend_user_id = $2 - AND fc.category NOT IN (SELECT category FROM round_visible_category WHERE round_id = $3) + AND category IN (SELECT category FROM round_visible_category WHERE round_id = $3) ) """, owner_id, @@ -2104,19 +2102,14 @@ async def _friends_who_can_see_round(conn, round_id: str, owner_user_id: str) -> return [] if row["visibility_mode"] == "public": return friend_ids - # Samme "alle kategorier må være synlige, ikke bare én"-regel som - # _can_view_round -- en venn med minst én ikke-synlig kategori - # ekskluderes fra fan-out-varselet, selv om en annen av kategoriene - # deres er valgt. + # Samme "minst én kategori er nok"-regel som _can_view_round (ADR-036 + # Beslutning E). matched = await conn.fetch( """ - SELECT fc.friend_user_id::text AS friend_id + SELECT DISTINCT fc.friend_user_id::text AS friend_id FROM friend_categorization fc WHERE fc.owner_user_id = $1 AND fc.friend_user_id = ANY($2::uuid[]) - GROUP BY fc.friend_user_id - HAVING COUNT(*) FILTER ( - WHERE fc.category NOT IN (SELECT category FROM round_visible_category WHERE round_id = $3) - ) = 0 + AND fc.category IN (SELECT category FROM round_visible_category WHERE round_id = $3) """, owner_user_id, friend_ids, @@ -2183,11 +2176,7 @@ async def list_friends_on_course(user: CurrentUser = Depends(get_current_user)) AND EXISTS( SELECT 1 FROM friend_categorization fc WHERE fc.owner_user_id = r.owner_user_id AND fc.friend_user_id = $1 - ) - AND NOT EXISTS( - SELECT 1 FROM friend_categorization fc - WHERE fc.owner_user_id = r.owner_user_id AND fc.friend_user_id = $1 - AND fc.category NOT IN ( + AND fc.category IN ( SELECT category FROM round_visible_category WHERE round_id = r.id ) )