fix(m3): Option A must-fix #79 #82 #83 #84 #89 #98

- #79 publish SKU/create via WooClient (User-Agent + typed 403 unrecoverable)
- #82 stale_field current_options from live taxonomy + owner labels
- #83 create allowlist/extra-key safe; taxonomy+enum 4xx on create
- #84 health woo_reachable real probe (non-failing); version 0.5.0-m3
- #89 review persists assembled title/short after taxonomy lock; UI applies
- #98 live-edge from synced term; attrs resolved by slug then name
This commit is contained in:
Ty
2026-09-21 12:49:53 -07:00
parent 96a697a50a
commit 0c00d25cc7
7 changed files with 328 additions and 108 deletions
+38 -11
View File
@@ -340,18 +340,45 @@ def test_create_rejects_unknown_fields(client, db):
def test_update_stale_field_returns_live_options(client, db):
# #82: stale_field error returns the LIVE taxonomy ids, not the submitted value.
# #82: stale_field returns LIVE taxonomy options (id+name), not the submitted id.
slab_id = str(uuid.uuid4())
payload = {"id": slab_id, "sku": "SKU001", "length_in":10,"thickness_in":2,"sqft":20,"bdft":5,"width_min_in":1,"width_max_in":2,"width_avg_in":1.5,"species_id":1,"wood_category_ids":json.dumps([2]),"edge_type_term_id":1,"figure_term_ids":json.dumps([1]),"grade_term_id":1,"thickness_term_id":1,"moisture_term_id":1,"fig_tag_ids":json.dumps([1]),"feat_tag_ids":json.dumps([2]),"price":100,"price_source":"recommendation","title":"Test","short_description":"short","description":"desc","content_source":"manual"}
client.post("/api/v1/slabs", json=payload)
# Submit a wood_category_id that doesn't exist in the taxonomy (id=999).
resp = client.put(f"/api/v1/slabs/{slab_id}", json={"client_rev": 1, "wood_category_ids": json.dumps([999])})
payload = {
"id": slab_id, "sku": "SKU-STALE", "length_in": 10, "thickness_in": 2, "sqft": 20, "bdft": 5,
"width_min_in": 1, "width_max_in": 2, "width_avg_in": 1.5,
}
assert client.post("/api/v1/slabs", json=payload).status_code == 201
resp = client.put(f"/api/v1/slabs/{slab_id}", json={"client_rev": 1, "edge_type_term_id": 999})
assert resp.status_code == 422
body = resp.json()
assert body["error"]["code"] == "stale_field"
detail = body["error"]["detail"]
assert detail["submitted"] == [999]
# current_options must be the LIVE ids from woo_categories, not [999].
assert 999 not in detail["current_options"]
# The seeded taxonomy has ids 1 and 2 in woo_categories.
assert set(detail["current_options"]) == {1, 2}
opts = body["error"]["detail"]["current_options"]
assert isinstance(opts, list) and opts
assert all(isinstance(o, dict) and "id" in o and "name" in o for o in opts)
assert 999 not in [o["id"] for o in opts]
assert "Edge type" in body["error"]["message"] or "edge" in body["error"]["message"].lower()
def test_create_extra_key_and_bad_taxonomy_are_4xx(client, db):
"""#83: server-managed/extra keys and bad taxonomy/enums are 4xx, not 500."""
base = {
"id": str(uuid.uuid4()), "sku": "SKU-XTRA", "length_in": 10, "thickness_in": 2, "sqft": 20, "bdft": 5,
"width_min_in": 1, "width_max_in": 2, "width_avg_in": 1.5,
"status": "published", # server-managed → unknown field 400
}
r = client.post("/api/v1/slabs", json=base)
assert r.status_code == 400, r.text
assert "status" in r.json()["error"]["detail"]["fields"]
# Bad taxonomy on create
r2 = client.post("/api/v1/slabs", json={
"id": str(uuid.uuid4()), "sku": "SKU-BADTAX", "length_in": 10, "thickness_in": 2, "sqft": 20, "bdft": 5,
"width_min_in": 1, "width_max_in": 2, "width_avg_in": 1.5, "species_id": 999,
})
assert r2.status_code == 422
assert r2.json()["error"]["code"] == "stale_field"
# Bad enum
r3 = client.post("/api/v1/slabs", json={
"id": str(uuid.uuid4()), "sku": "SKU-BADENUM", "length_in": 10, "thickness_in": 2, "sqft": 20, "bdft": 5,
"width_min_in": 1, "width_max_in": 2, "width_avg_in": 1.5, "price_source": "not-a-source",
})
assert r3.status_code == 400
assert r3.json()["error"]["code"] == "validation"