commit 5747fc98cf717c5064d6acc1e403baa444466053
parent 115d11a98470f60f186a87f2474d082bc8500bdb
Author: triesap <tyson@radroots.org>
Date: Mon, 21 Sep 2026 13:00:48 +0000
core: add demand line and constraint types
Diffstat:
2 files changed, 98 insertions(+), 0 deletions(-)
diff --git a/src/hyf_core/domain/demand.mojo b/src/hyf_core/domain/demand.mojo
@@ -0,0 +1,70 @@
+from std.collections import List, Optional
+
+from hyf_core.domain.product import ProductRef
+
+
+@fieldwise_init
+struct Condition(Copyable, Movable):
+ var kind: String
+ var strength: String
+ var value: Optional[String]
+
+
+@fieldwise_init
+struct DemandLine(Copyable, Movable):
+ var line_id: String
+ var product: ProductRef
+ var quantity_state: String
+ var quantity_value: Int
+ var quantity_scale: Int
+ var unit: String
+ var conditions: List[Condition]
+
+
+def condition(kind: String, strength: String, value: Optional[String]) raises -> Condition:
+ if kind.strip() == "":
+ raise Error("condition kind must not be empty")
+ var strengths = ["mandatory", "preferred", "excluded", "permitted"]
+ var known = False
+ for candidate in strengths:
+ if candidate == strength:
+ known = True
+ if not known:
+ raise Error("unknown condition strength: " + strength)
+ if strength != "excluded" and not value:
+ raise Error("non-excluded condition requires a value")
+ return Condition(kind=String(kind), strength=String(strength), value=value.copy())
+
+
+def demand_line(
+ line_id: String,
+ product: ProductRef,
+ quantity_state: String,
+ quantity_value: Int,
+ quantity_scale: Int,
+ conditions: List[Condition],
+) raises -> DemandLine:
+ if line_id.strip() == "":
+ raise Error("demand line requires an id")
+ if quantity_state != "known" and quantity_state != "unknown":
+ raise Error("demand quantity state must be 'known' or 'unknown'")
+ var copied = List[Condition]()
+ for entry in conditions:
+ copied.append(entry.copy())
+ return DemandLine(
+ line_id=String(line_id),
+ product=product.copy(),
+ quantity_state=String(quantity_state),
+ quantity_value=quantity_value,
+ quantity_scale=quantity_scale,
+ unit="kg",
+ conditions=copied^,
+ )
+
+
+def condition_is_exclusion(value: Condition) -> Bool:
+ return value.strength == "excluded"
+
+
+def missing_information_is_prohibition() -> Bool:
+ return False
diff --git a/tests/test_domain.mojo b/tests/test_domain.mojo
@@ -421,3 +421,31 @@ def test_clarification_refines_without_overwriting_original() raises:
assert_equal(refined.value.value(), "60")
assert_true(not clarification_is_stale(evidence, "r2"))
assert_true(clarification_is_stale(evidence, "r3"))
+
+
+from hyf_core.domain.demand import (
+ Condition,
+ DemandLine,
+ condition,
+ condition_is_exclusion,
+ demand_line,
+ missing_information_is_prohibition,
+)
+
+
+def test_demand_lines_and_condition_strength() raises:
+ var tomatoes = resolved_product("tomatoes", "tomato")
+ var lines = List[DemandLine]()
+ var conditions_a = List[Condition]()
+ conditions_a.append(condition("fulfillment", "mandatory", Optional[String]("delivery")))
+ conditions_a.append(condition("fulfillment_excluded", "excluded", Optional[String]("pickup")))
+ lines.append(demand_line("l1", tomatoes, "known", 25, 0, conditions_a))
+ var conditions_b = List[Condition]()
+ conditions_b.append(condition("grade", "permitted", Optional[String]("seconds")))
+ lines.append(demand_line("l2", tomatoes, "unknown", 0, 0, conditions_b))
+ assert_equal(len(lines), 2)
+ assert_true(condition_is_exclusion(lines[0].conditions[1]))
+ assert_true(not condition_is_exclusion(lines[0].conditions[0]))
+ assert_true(not missing_information_is_prohibition())
+ with assert_raises():
+ _ = condition("grade", "maybe", Optional[String]("x"))