hyf

Context-aware query service for Radroots
git clone https://radroots.dev/git/hyf.git
Log | Files | Refs | README | LICENSE

commit aded5b534a068424110a5d07472b65723a9ec55b
parent d148842002034f154f1c0e4f67a4860b92f442fc
Author: triesap <tyson@radroots.org>
Date:   Mon, 21 Sep 2026 13:01:36 +0000

core: add allocation and plan types

Diffstat:
Asrc/hyf_core/domain/plan.mojo | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/test_domain.mojo | 32++++++++++++++++++++++++++++++++
2 files changed, 139 insertions(+), 0 deletions(-)

diff --git a/src/hyf_core/domain/plan.mojo b/src/hyf_core/domain/plan.mojo @@ -0,0 +1,107 @@ +from std.collections import List + + +@fieldwise_init +struct Allocation(Copyable, Movable): + var lot_id: String + var revision: String + var line_id: String + var value: Int + var scale: Int + + +@fieldwise_init +struct LotCapacity(Copyable, Movable): + var lot_id: String + var revision: String + var value: Int + var scale: Int + + +@fieldwise_init +struct MatchPlan(Copyable, Movable): + var plan_id: String + var supplier_id: String + var allocations: List[Allocation] + + +def allocation( + lot_id: String, revision: String, line_id: String, value: Int, scale: Int +) raises -> Allocation: + if lot_id.strip() == "" or revision.strip() == "" or line_id.strip() == "": + raise Error("allocation requires lot id, revision and line id") + if value < 0: + raise Error("allocation value must be non-negative") + return Allocation( + lot_id=String(lot_id), + revision=String(revision), + line_id=String(line_id), + value=value, + scale=scale, + ) + + +def match_plan( + plan_id: String, supplier_id: String, allocations: List[Allocation] +) raises -> MatchPlan: + if plan_id.strip() == "" or supplier_id.strip() == "": + raise Error("plan requires plan id and supplier id") + var copied = List[Allocation]() + for entry in allocations: + copied.append(entry.copy()) + return MatchPlan( + plan_id=String(plan_id), supplier_id=String(supplier_id), allocations=copied^ + ) + + +def _rescale(value: Int, scale: Int, target: Int) -> Int: + var result = value + for _ in range(target - scale): + result *= 10 + return result + + +def plan_conservation_violations( + plan: MatchPlan, lots: List[LotCapacity] +) raises -> List[String]: + var violations = List[String]() + var lot_keys = List[String]() + var allocated = List[Int]() + var allocated_scale = List[Int]() + for entry in plan.allocations: + var key = entry.lot_id + "@" + entry.revision + var found = -1 + for index in range(len(lot_keys)): + if lot_keys[index] == key: + found = index + var scale = entry.scale + var value = entry.value + if found >= 0: + if allocated_scale[found] > scale: + scale = allocated_scale[found] + value = _rescale(value, entry.scale, scale) + _rescale( + allocated[found], allocated_scale[found], scale + ) + allocated[found] = value + allocated_scale[found] = scale + else: + lot_keys.append(String(key)) + allocated.append(value) + allocated_scale.append(scale) + + for index in range(len(lot_keys)): + var capacity_value = -1 + var capacity_scale = 0 + for lot in lots: + if lot.lot_id + "@" + lot.revision == lot_keys[index]: + capacity_value = lot.value + capacity_scale = lot.scale + var scale = capacity_scale if capacity_scale > allocated_scale[index] else allocated_scale[index] + if capacity_value < 0: + violations.append(lot_keys[index] + ": unknown capacity") + continue + if _rescale(allocated[index], allocated_scale[index], scale) > _rescale( + capacity_value, capacity_scale, scale + ): + violations.append(lot_keys[index] + ": over-allocated") + return violations^ diff --git a/tests/test_domain.mojo b/tests/test_domain.mojo @@ -493,3 +493,35 @@ def test_eligibility_precedence() raises: assert_equal(compose_eligibility(optional_only), "eligible") with assert_raises(): _ = constraint_assessment("product", "maybe", True, "x") + + +from hyf_core.domain.plan import ( + Allocation, + LotCapacity, + MatchPlan, + allocation, + match_plan, + plan_conservation_violations, +) + + +def test_plan_conservation_across_lots() raises: + var lots = List[LotCapacity]() + lots.append(LotCapacity(lot_id="lot-1", revision="l1", value=30, scale=0)) + lots.append(LotCapacity(lot_id="lot-2", revision="l1", value=40, scale=0)) + var allocations = List[Allocation]() + allocations.append(allocation("lot-1", "l1", "line-1", 30, 0)) + allocations.append(allocation("lot-2", "l1", "line-1", 40, 0)) + var plan = match_plan("p1", "farm-1", allocations) + assert_equal(len(plan_conservation_violations(plan, lots)), 0) + + var over = List[Allocation]() + over.append(allocation("lot-1", "l1", "line-1", 31, 0)) + var bad = match_plan("p2", "farm-1", over) + assert_true(len(plan_conservation_violations(bad, lots)) > 0) + + var shared = List[Allocation]() + shared.append(allocation("lot-1", "l1", "line-1", 20, 0)) + shared.append(allocation("lot-1", "l1", "line-2", 20, 0)) + var shared_plan = match_plan("p3", "farm-1", shared) + assert_true(len(plan_conservation_violations(shared_plan, lots)) > 0)