# ============================================================ # IND-02 SOP→约束规则包黄金测试 # ============================================================ from __future__ import annotations from server.aps_domain.changeover import lookup_setup_minutes from server.aps_domain.constraints import get_constraint, is_enabled from server.aps_domain.sop_rules import ( apply_sop_pack, compile_sop_by_asset, compile_sop_by_query, compile_sop_asset, ) from server.knowledge import get_knowledge from server.state.seed import seed_world def test_compile_changeover_sop(): kb = get_knowledge() asset = next(a for a in kb.assets if a.get("title") == "换线标准SOP") pack = compile_sop_asset(asset) assert pack["effects"] ops = {e["op"] for e in pack["effects"]} assert "constraint.set" in ops assert "changeover.policy" in ops cross = next(e for e in pack["effects"] if e["op"] == "changeover.policy") assert cross["defaultCrossFamilyMin"] == 60 assert cross.get("noChangeoverAfter") == "16:00" def test_compile_by_asset_and_apply(): world = seed_world() asset = next(a for a in get_knowledge().assets if a.get("title") == "换线标准SOP") compiled = compile_sop_by_asset(get_knowledge().assets, asset["assetId"]) assert compiled["ok"] pack = compiled["pack"] before_cross = lookup_setup_minutes(world, "CTRL", "PDU") # 无矩阵时用默认 applied = apply_sop_pack(world, pack) assert "constraint:C10_changeover" in applied["applied"] assert "changeover.policy" in applied["applied"] assert is_enabled(world, "C13_sop") c13 = get_constraint(world, "C13_sop") assert c13 and c13.get("params", {}).get("sourceTitle") == "换线标准SOP" assert float((world.get("changeoverPolicy") or {})["defaultCrossFamilyMin"]) == 60 after_cross = lookup_setup_minutes(world, "CTRL", "PDU") assert after_cross == 60 assert after_cross != before_cross or before_cross == 60 assert len(world.get("rulePacks") or []) == 1 def test_compile_kit_sop(): asset = next(a for a in get_knowledge().assets if a.get("title") == "库存与齐套口径") compiled = compile_sop_by_asset(get_knowledge().assets, asset["assetId"]) assert compiled["ok"] ids = [e.get("id") for e in compiled["pack"]["effects"] if e.get("op") == "constraint.set"] assert "C6_material_kit" in ids def test_query_shell_requires_explicit_asset_id(): compiled = compile_sop_by_query(get_knowledge().assets, "换线") assert compiled["ok"] is False assert "assetId" in compiled["error"]