Opening moves become row-honest: ← → within the row, clamped at edges
Eric asked what the ↑↓ buttons did — the honest answer was "reorder a flat list that no longer exists, and fragment your wall diagram if pushed across a row boundary" (A1, B1, A2 renders as THREE rows under the letter-grouped layout). The useful half survives as ← → "move within its row"; the endpoint clamps at row-letter boundaries so the diagram can't fragment. Tests pin both the clamp and the legitimate within-row swap; the acceptance flow's reorder step updated to match the new semantics. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
co-authored by
Claude Fable 5
parent
75162c3e2e
commit
a23b97d2f9
+42
-5
@@ -268,16 +268,19 @@ def test_acceptance_full_furniture_flow_without_touching_json(tmp_path):
|
||||
assert saved[0]["openings"][0]["label"] == "wide left"
|
||||
assert saved[-1]["openings"][0].get("width_in") is None # virtual
|
||||
|
||||
# editable, deletable, reorderable
|
||||
# editable, deletable, reorderable (within a row — moves clamp at
|
||||
# row-letter boundaries so the wall diagram can't fragment)
|
||||
first_cube = saved[0]["openings"][2]["id"]
|
||||
second_cube = saved[0]["openings"][3]["id"]
|
||||
web.post("/api/furniture/edit-opening", json={"id": first_cube, "zone": "kids"})
|
||||
web.post("/api/furniture/move-opening", json={"id": first_cube, "direction": -1})
|
||||
web.post(
|
||||
"/api/furniture/delete-opening", json={"id": saved[0]["openings"][3]["id"]}
|
||||
)
|
||||
saved_mid = json.loads(cfg.furniture_path.read_text())["units"]
|
||||
assert saved_mid[0]["openings"][2]["id"] == first_cube # clamped: row edge
|
||||
web.post("/api/furniture/move-opening", json={"id": second_cube, "direction": -1})
|
||||
web.post("/api/furniture/delete-opening", json={"id": first_cube})
|
||||
saved2 = json.loads(cfg.furniture_path.read_text())["units"]
|
||||
assert len(saved2[0]["openings"]) == 13
|
||||
assert saved2[0]["openings"][1]["id"] == first_cube # moved up one
|
||||
assert saved2[0]["openings"][2]["id"] == second_cube # swapped within row
|
||||
|
||||
|
||||
def test_locate_flow_and_stored_in_refusal(tmp_path):
|
||||
@@ -599,6 +602,40 @@ def test_second_grid_continues_row_letters(tmp_path):
|
||||
assert len(set(labels)) == 6 # unique: label-addressed CSVs stay usable
|
||||
|
||||
|
||||
def test_move_clamps_at_row_boundaries(tmp_path):
|
||||
"""A move must never fragment a row: B1 cannot cross above A2 (the
|
||||
renderer would draw A, B, A as three rows), but B2 and B1 can swap."""
|
||||
web, cfg = _web(tmp_path, {})
|
||||
web.post("/api/furniture/add-unit", json={"name": "Wall"})
|
||||
web.post(
|
||||
"/api/furniture/add-openings",
|
||||
json={
|
||||
"unit": "Wall",
|
||||
"rows": 2,
|
||||
"cols": 2,
|
||||
"width_in": 13.0,
|
||||
"height_in": 13.0,
|
||||
"depth_in": 15.0,
|
||||
},
|
||||
)
|
||||
|
||||
def labels():
|
||||
return [
|
||||
o["label"] for o in web.get("/api/shelves").json()["units"][0]["openings"]
|
||||
]
|
||||
|
||||
ids = {
|
||||
o["label"]: o["id"]
|
||||
for o in web.get("/api/shelves").json()["units"][0]["openings"]
|
||||
}
|
||||
# cross-row move clamps: B1 stays put
|
||||
web.post("/api/furniture/move-opening", json={"id": ids["B1"], "direction": -1})
|
||||
assert labels() == ["A1", "A2", "B1", "B2"]
|
||||
# within-row move works: B2 left of B1
|
||||
web.post("/api/furniture/move-opening", json={"id": ids["B2"], "direction": -1})
|
||||
assert labels() == ["A1", "A2", "B2", "B1"]
|
||||
|
||||
|
||||
def test_move_opening_boundaries_no_op(tmp_path):
|
||||
web, cfg = _web(tmp_path, {})
|
||||
web.post("/api/furniture/add-unit", json={"name": "Den"})
|
||||
|
||||
Reference in New Issue
Block a user