mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
fix: the first write of a newer wall model is not an outdated client (#319)
A stale client can only echo the stored model_version, never raise it. The 'unchanged wall catalogue' refusal now applies only when the submitted model is not above the stored one; the first v9 write over a v8 document with an orphan open_span/open_to legitimately drops the legacy projection without touching the catalogue and passes. The regression pair fixture is produced by the real writers (stored: v1.68.0-beta.2, sent: current migration) and is pinned on the frontend byte-for-byte so it cannot drift. Issue: #319 User-Visible: yes
This commit is contained in:
@@ -223,6 +223,45 @@ def test_stale_client_echoing_v8_catalog_gets_the_named_error() -> None:
|
||||
validate_wall_model_transition(non_structural, previous)
|
||||
|
||||
|
||||
def test_first_write_of_a_newer_model_is_not_outdated_even_without_catalog_change() -> None:
|
||||
"""#319: a client can only echo the stored model_version, never raise it.
|
||||
|
||||
The pair fixture is generated by real writers: `stored` by the
|
||||
v1.68.0-beta.2 (model v8) writer with one orphan open_span, `sent` by the
|
||||
current initial migration — the catalogue is byte-identical, the orphan
|
||||
span is dropped. Before the fix this exact pair raised
|
||||
WallModelClientOutdatedError and wedged every structural write forever.
|
||||
"""
|
||||
fixture = json.loads((
|
||||
Path(__file__).parents[1] / "test" / "fixtures"
|
||||
/ "319-orphan-span-migration.json"
|
||||
).read_text(encoding="utf-8"))
|
||||
stored, sent = fixture["stored"], fixture["sent"]
|
||||
assert stored["model_version"] == 8 and sent["model_version"] == 9
|
||||
assert stored["spaces"][0]["wall_segments"] == sent["spaces"][0]["wall_segments"]
|
||||
assert "open_spans" in stored["spaces"][0]
|
||||
assert "open_spans" not in sent["spaces"][0]
|
||||
|
||||
# AC1: the pure migration write passes.
|
||||
validate_wall_model_transition(copy.deepcopy(sent), stored)
|
||||
|
||||
# AC2: the same write with the user's first draft (the first click of the
|
||||
# Walls tool, independent geometry per #314) passes too.
|
||||
with_draft = copy.deepcopy(sent)
|
||||
with_draft["spaces"][0].setdefault("room_drafts", []).append({
|
||||
"id": "d-319", "points": [[0.7, 0.7], [0.8, 0.7]],
|
||||
"segments": [{"id": "seg-d-319", "cm": 20}],
|
||||
})
|
||||
validate_wall_model_transition(with_draft, stored)
|
||||
|
||||
# AC3: the same-version echo (9 → 9) with changed contours and an
|
||||
# unchanged catalogue keeps the named refusal.
|
||||
echoed = copy.deepcopy(sent)
|
||||
echoed["spaces"][0]["rooms"][0]["poly"][0][0] += 0.01
|
||||
with pytest.raises(WallModelClientOutdatedError, match="unchanged wall catalogue"):
|
||||
validate_wall_model_transition(echoed, copy.deepcopy(sent))
|
||||
|
||||
|
||||
def test_current_wall_model_independent_geometry_does_not_require_contour_catalog_change() -> None:
|
||||
"""Drafts, partitions, columns and hosted openings own their identity (#314)."""
|
||||
previous, _ = commit_wall_segment_model(_config({
|
||||
|
||||
Reference in New Issue
Block a user