Where it lives vs where it IS: the away field for loans and travel

Eric: this shows where games live, but Frosthaven is in the travel
case right now, and sometimes a game is at a friend's house. A home
and a whereabouts are different facts, so a location record can now
carry away: free text for where the box IS when that isn't home.

Set it in the Right now field on any game's detail page ("travel
case", "loaned to Ben"); blank brings it back and leaves no husk of a
record behind. Home is untouched throughout: the opening assignment
stays, the spot stays reserved in the packing math — a loan is not a
move. Contents ride along the same way they ride on shelves: games
stored inside an out box read as out with it, through whole chains.
The home opening's sheet shows an "out:" chip, unshelved rows show it
too, and the exported game page appends "right now: …" beside where
it lives. Away survives locate edits, lane flips, and CSV re-imports.

Verified live, with Eric's actual fact as the test: Frosthaven marked
out to the travel case from its page — its E1 sheet row now reads
"out: travel case · standing, proud", zero page errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
Eric Wagoner
2026-08-09 16:17:31 -04:00
co-authored by Claude Fable 5
parent 6c95953dc0
commit 0ed2145f80
15 changed files with 406 additions and 13 deletions
+58
View File
@@ -1194,3 +1194,61 @@ def test_measurements_overlay(tmp_path):
state = web.post("/api/measure", json={"key": "1"}).json()
g = state["units"][0]["openings"][0]["resident_games"][0]
assert g["measured"] is False
def test_away_whereabouts(tmp_path):
"""Where it lives vs where it IS: an away note marks the box out
(travel case, a friend's house) without touching its home opening,
contents ride along, and "" brings it back — cleaning up records
that held nothing else."""
web, cfg = _web(
tmp_path,
{
"1": _entry("Frosthaven", 12.0, 12.0, 7.0, bgg_id="174430"),
"2": _entry(
"Frosthaven: Solo Scenarios", 8.0, 8.0, 1.0, stored_in="174430"
),
},
)
save_furniture(
cfg,
[
{
"name": "Wall",
"openings": [
{
"id": "big",
"label": "A1",
"zone": "",
"width_in": 26.5,
"height_in": 13.25,
"depth_in": 15.4,
}
],
}
],
)
save_locations(cfg, {"1": {"opening_id": "big", "note": ""}})
state = web.post("/api/away", json={"key": "1", "where": "travel case"}).json()
a1 = state["units"][0]["openings"][0]
frost = next(g for g in a1["resident_games"] if g["name"] == "Frosthaven")
solo = next(g for g in a1["resident_games"] if "Solo" in g["name"])
# home unchanged — still a resident, still packed — but marked out,
# and the contents ride along on the trip
assert frost["away"] == "travel case"
assert solo["away"] == "travel case" and solo["inherited"]
assert frost["lane"] # the home spot stays reserved
record = load_locations(cfg)["1"]
assert record["opening_id"] == "big" and record["away"] == "travel case"
# coming home clears the field but never the home
state = web.post("/api/away", json={"key": "1", "where": ""}).json()
assert "away" not in load_locations(cfg)["1"]
# an unshelved game can be out too; bringing it back leaves no husk
web.post("/api/away", json={"key": "2", "where": "loaned to Ben"})
assert load_locations(cfg)["2"] == {
"opening_id": None,
"note": "",
"away": "loaned to Ben",
}
web.post("/api/away", json={"key": "2", "where": ""})
assert "2" not in load_locations(cfg)