diff --git a/lyra/poker.py b/lyra/poker.py index 8d928c6..6987813 100644 --- a/lyra/poker.py +++ b/lyra/poker.py @@ -644,6 +644,28 @@ def update_hand(hand_id: int, **fields) -> dict | None: return get_hand(hand_id) +def disown_hand(hand_id: int) -> dict | None: + """Reclassify a hand as OBSERVED (not Brian's) — fixes one that was mislabeled + as his. Clears the flat hero fields and rewrites the structured JSON with + hero_involved=false so the replay stops showing him as hero.""" + h = get_hand(hand_id) + if not h: + return None + structured = h.get("structured") + if isinstance(structured, str): + structured = _safe_json(structured) + if isinstance(structured, dict): + structured = normalize_structured({**structured, "hero_involved": False}) + conn = _c() + with conn: + conn.execute( + "UPDATE poker_hands SET position = NULL, hole_cards = NULL, result = NULL, " + "structured = ? WHERE id = ?", + (json.dumps(structured) if structured else None, hand_id), + ) + return get_hand(hand_id) + + def list_hands(session_id: int | None = None) -> list[dict]: sid = _resolve(session_id) if sid is None: diff --git a/lyra/web/server.py b/lyra/web/server.py index 34933e3..10c24d0 100644 --- a/lyra/web/server.py +++ b/lyra/web/server.py @@ -192,6 +192,13 @@ def create_app() -> FastAPI: logbus.log("info", "hand edited", id=hand_id, fields=list(body)) return {"ok": h is not None, "hand": h} + @app.post("/hand/{hand_id}/disown") + async def hand_disown(hand_id: int) -> dict: + """Reclassify a hand as observed (not Brian's) — fix a misattributed one.""" + h = await asyncio.to_thread(poker.disown_hand, hand_id) + logbus.log("info", "hand disowned", id=hand_id) + return {"ok": h is not None, "hand": h} + @app.delete("/hand/{hand_id}") async def hand_delete(hand_id: int) -> dict: """Delete a logged hand.""" diff --git a/lyra/web/static/hand.html b/lyra/web/static/hand.html index 0b475e7..d0168c7 100644 --- a/lyra/web/static/hand.html +++ b/lyra/web/static/hand.html @@ -282,8 +282,54 @@ const h = await r.json(); if(!h || !h.id){ document.getElementById('root').innerHTML='
Hand not found.
'; return; } render(h); + renderEditor(h); }catch(e){ document.getElementById('root').innerHTML='Couldn\'t load the hand.
'; } } + + function renderEditor(h){ + const wrap = document.createElement('div'); + wrap.style.cssText = 'max-width:520px;margin:18px auto 0;border-top:1px solid #241a10;padding-top:12px;'; + const tags = ['','well_played','leak','cooler','confidence','notable']; + wrap.innerHTML = ` +