game kit: free a deposited trinket 7d after it goes in-use; retire COIN's room cooldown — TDD

A deposited trinket binds `Token.current_room` (the 'In-Use: <room>' Game Kit
label), set on deposit + cleared only on MANUAL return. Once a seat's token cost
lapsed (7d → GATE VIEW returns to prompt re-deposit) nothing freed the binding —
`cost_current` is a render-time prop, so no 7d mutation — leaving e.g. a CARTE
used a week prior stuck 'In-Use' (staging, 2026-06-08).

Fix — a uniform, type-agnostic in-use clock:
- New `Token.in_use_since`, stamped when `current_room` is set (`debit_token`
  COIN, `drop_token` CARTE). `release_lapsed_trinkets(tokens)` frees
  `current_room` + `in_use_since` + `slots_claimed` once held >= the room's
  `renewal_period` (7d). The SEAT is untouched — renewal grace (to 2xspan) +
  auto-BYE stay `_expire_lapsed_seats`'s job (a separate, later threshold).
- PASS/BAND never bind (reusable keys) -> no-op; COIN + CARTE covered by the one
  rule. Fires on the gameboard / `_game_kit_context` render (the gamer sees it
  freed immediately) + the cron backstop (`expire_lapsed_room_seats`).
- Migration 0018 backfills `in_use_since` from the earliest backing-slot
  `filled_at` so existing staging bindings release on accurate timing (old free
  on next sweep, recent keep grace) instead of every legacy NULL releasing early.

Retired COIN's bespoke ROOM cooldown: `debit_token` no longer sets
`next_ready_at` + `return_token` no longer clears it. `next_ready_at` is now
My-Sea-exclusive (the 24h DRAW cooldown, no room context) — the two clocks no
longer share a meaning + can't clash (user-spec 2026-06-08).

TDD: ReleaseLapsedTrinketsTest (6) + cron release + 2 gameboard-immediacy tests +
updated return/tooltip/bind assertions; 1124 lyric+epic+gameboard ITs green.

[[feedback-equip-slot-gates-trinket-use]] [[feedback-my-sea-cooldown-design]]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-06-08 16:35:35 -04:00
parent d50645b216
commit dcfa54f522
10 changed files with 264 additions and 10 deletions

View File

@@ -918,6 +918,7 @@ def drop_token(request, room_id):
if token.current_room_id and token.current_room_id != room.id:
return HttpResponse(status=409)
token.current_room = room
token.in_use_since = timezone.now() # room in-use clock (7d release)
token.save()
if request.user.equipped_trinket_id == token.pk:
request.user.equipped_trinket = None
@@ -1029,6 +1030,7 @@ def return_token(request, room_id):
debited_token_type=None, debited_token_expires_at=None,
)
carte.current_room = None
carte.in_use_since = None
carte.slots_claimed = 0
carte.save()
request.session.pop("kit_token_id", None)
@@ -1057,7 +1059,7 @@ def return_token(request, room_id):
).first()
if coin:
coin.current_room = None
coin.next_ready_at = None
coin.in_use_since = None
coin.save()
elif slot.debited_token_type in (Token.FREE, Token.TITHE):
Token.objects.create(