Allow direct article resolution in machine max MCP
This commit is contained in:
@@ -164,6 +164,26 @@ class CalculationApiTests(unittest.TestCase):
|
||||
["roll_diameter_nominal"],
|
||||
)
|
||||
|
||||
def test_machine_maximum_length_endpoint_does_not_accept_mcp_article_convenience(self):
|
||||
response = self.client.post(
|
||||
"/api/calculations/machine-max-product-length",
|
||||
json={
|
||||
"article_number": "218500",
|
||||
"machine": "K7",
|
||||
"core_diameter_mm": 133,
|
||||
},
|
||||
headers=self.headers,
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.get_json(), {
|
||||
"status": "invalid_parameter",
|
||||
"invalid": [{
|
||||
"field": "request",
|
||||
"message": "unknown request fields: article_number",
|
||||
}],
|
||||
})
|
||||
|
||||
def test_machine_maximum_length_endpoint_preserves_domain_outcomes(self):
|
||||
incompatible = self.client.post(
|
||||
"/api/calculations/machine-max-product-length",
|
||||
|
||||
@@ -117,6 +117,10 @@ class McpAdapterTests(unittest.TestCase):
|
||||
domain_result = calculate_machine_max_product_length(**arguments)
|
||||
domain_before_projection = copy.deepcopy(domain_result)
|
||||
|
||||
self.assertNotIn(
|
||||
"article_number",
|
||||
inspect.signature(calculate_machine_max_product_length).parameters,
|
||||
)
|
||||
result = project_machine_max_product_length_result(domain_result)
|
||||
|
||||
self.assertEqual(domain_result, domain_before_projection)
|
||||
@@ -143,6 +147,72 @@ class McpAdapterTests(unittest.TestCase):
|
||||
})
|
||||
self.assertEqual(result["warnings"], {"nominal": ["roll_diameter_mm"]})
|
||||
|
||||
def test_machine_maximum_length_adapter_resolves_exact_article_compactly(self):
|
||||
result = calculate_machine_max_product_length_result(
|
||||
article_number="218500",
|
||||
machine="K7",
|
||||
core_diameter_mm=133.0,
|
||||
)
|
||||
|
||||
self.assertEqual(result["status"], "success")
|
||||
self.assertEqual(result["article"], {
|
||||
"number": "218500",
|
||||
"name": "Stex AS 501, 6,00 x 75 m",
|
||||
})
|
||||
self.assertNotIn("thickness_mm", result)
|
||||
self.assertNotIn("final_feasibility", result)
|
||||
self.assertEqual(result["production_maximums"], {
|
||||
"nominal_length_m": 217.1900177447768,
|
||||
"nominal_governing_constraints": ["roll_diameter_nominal"],
|
||||
"conservative_length_m": 194.62073281485985,
|
||||
"conservative_governing_constraints": ["roll_diameter_conservative"],
|
||||
})
|
||||
self.assertEqual(result["material_weights_kg"], {
|
||||
"at_nominal_production_maximum": 645.570178559751,
|
||||
"at_conservative_production_maximum": 578.4858003113276,
|
||||
})
|
||||
|
||||
def test_machine_maximum_length_adapter_article_lookup_is_exact_and_core_is_caller_supplied(self):
|
||||
missing = calculate_machine_max_product_length_result(
|
||||
article_number="does-not-exist",
|
||||
machine="K7",
|
||||
core_diameter_mm=133.0,
|
||||
)
|
||||
incompatible_core = calculate_machine_max_product_length_result(
|
||||
article_number="218500",
|
||||
machine="K7",
|
||||
core_diameter_mm=194.0,
|
||||
)
|
||||
|
||||
self.assertEqual(missing, {
|
||||
"status": "article_not_found",
|
||||
"article_number": "does-not-exist",
|
||||
})
|
||||
self.assertEqual(incompatible_core["status"], "incompatible")
|
||||
self.assertEqual(
|
||||
incompatible_core["failed_compatibility_constraints"],
|
||||
["allowed_core_diameters_mm"],
|
||||
)
|
||||
|
||||
def test_machine_maximum_length_adapter_rejects_mixed_article_and_material_inputs(self):
|
||||
result = calculate_machine_max_product_length_result(
|
||||
article_number="218500",
|
||||
machine="K7",
|
||||
core_diameter_mm=133.0,
|
||||
thickness_mm=4.311611,
|
||||
)
|
||||
|
||||
self.assertEqual(result, {
|
||||
"status": "invalid_parameter",
|
||||
"invalid": [{
|
||||
"field": "article_number",
|
||||
"message": (
|
||||
"cannot be combined with explicit material properties: "
|
||||
"thickness_mm"
|
||||
),
|
||||
}],
|
||||
})
|
||||
|
||||
def test_machine_maximum_length_adapter_preserves_non_success_diagnostics(self):
|
||||
base = {
|
||||
"machine": "K7",
|
||||
@@ -344,17 +414,19 @@ class McpAdapterTests(unittest.TestCase):
|
||||
self.assertIn("Missing configured V1 roll inputs", feasibility_tool.description)
|
||||
self.assertEqual(
|
||||
maximum_tool.parameters["required"],
|
||||
["machine", "core_diameter_mm", "thickness_mm"],
|
||||
["machine", "core_diameter_mm"],
|
||||
)
|
||||
self.assertIn("article_number", maximum_tool.parameters["properties"])
|
||||
self.assertIn("product_width_m", maximum_tool.parameters["properties"])
|
||||
self.assertIn("area_weight_g_m2", maximum_tool.parameters["properties"])
|
||||
for text in (
|
||||
"Resolve the article first with search_articles/get_article",
|
||||
"exact article_number",
|
||||
"do not call get_article merely to copy properties",
|
||||
"Never mix article_number with material properties",
|
||||
"For a product name, use search_articles",
|
||||
"if candidates are multiple, ask the user to select an article number",
|
||||
"Do not supply or invent machine limits",
|
||||
"rearrange roll or weight formulas",
|
||||
"compare candidate limits yourself",
|
||||
"nominal and conservative/no-warning production maxima",
|
||||
"incompatibility rather than substituting another core or width",
|
||||
):
|
||||
self.assertIn(text, maximum_tool.description)
|
||||
self.assertEqual(
|
||||
|
||||
Reference in New Issue
Block a user