hyf

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

commit 2f9696c6ed7a3fb1b25fac1d6fa84557458acd2f
parent 856b0e22e424151eaa9868fa282d61aec6a3f29b
Author: triesap <tyson@radroots.org>
Date:   Mon, 21 Sep 2026 13:57:01 +0000

core: compose normalized versioned preferences

Diffstat:
Asrc/hyf_application/match_ranking.mojo | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/test_application.mojo | 29+++++++++++++++++++++++++++++
2 files changed, 99 insertions(+), 0 deletions(-)

diff --git a/src/hyf_application/match_ranking.mojo b/src/hyf_application/match_ranking.mojo @@ -0,0 +1,70 @@ +from std.collections import List + + +@fieldwise_init +struct PreferenceComponent(Copyable, Movable): + var policy: String + var score: Float64 + var weight: Float64 + + +def preference_component( + policy: String, score: Float64, weight: Float64 +) raises -> PreferenceComponent: + if String(policy).strip().byte_length() == 0: + raise Error("preference component requires a policy") + if score < 0.0 or score > 1.0: + raise Error("preference score must be within [0, 1]") + if weight < 0.0: + raise Error("preference weight must be non-negative") + return PreferenceComponent(policy=String(policy), score=score, weight=weight) + + +def compose_preference(components: List[PreferenceComponent]) -> Int: + var weighted = 0.0 + var total_weight = 0.0 + for component in components: + weighted += component.score * component.weight + total_weight += component.weight + if total_weight <= 0.0: + return 0 + return Int((weighted / total_weight) * 100.0) + + +def preference_is_success_probability() -> Bool: + return False + + +def rank_by_preference( + plan_ids: List[String], scores: List[Int] +) raises -> List[String]: + if len(plan_ids) != len(scores): + raise Error("plan ids and scores must align") + var pairs = List[PreferenceComponent]() + _ = pairs + var order = List[Int]() + for index in range(len(plan_ids)): + order.append(index) + # insertion sort: deterministic desc by score, then asc by plan id + var ranked = List[Int]() + for index in order: + var inserted = False + var updated = List[Int]() + for existing in ranked: + if not inserted and ( + scores[index] > scores[existing] + or ( + scores[index] == scores[existing] + and plan_ids[index] < plan_ids[existing] + ) + ): + updated.append(index) + inserted = True + updated.append(existing) + if not inserted: + updated.append(index) + ranked = updated^ + var result = List[String]() + for index in ranked: + result.append(String(plan_ids[index])) + return result^ diff --git a/tests/test_application.mojo b/tests/test_application.mojo @@ -642,3 +642,32 @@ def test_culinary_use_semantic_scoring_gated() raises: with assert_raises(): _ = culinary_use_score(answer, 3, 0, 1) assert_true(not culinary_score_affects_feasibility()) + + +from hyf_application.match_ranking import ( + PreferenceComponent, + compose_preference, + preference_component, + preference_is_success_probability, + rank_by_preference, +) + + +def test_versioned_preference_composition_and_stable_ties() raises: + var components = List[PreferenceComponent]() + components.append(preference_component("culinary", 1.0, 1.0)) + components.append(preference_component("distance", 0.5, 1.0)) + assert_equal(compose_preference(components), 75) + assert_true(not preference_is_success_probability()) + var ids = List[String]() + ids.append("plan-b") + ids.append("plan-a") + ids.append("plan-c") + var scores = List[Int]() + scores.append(50) + scores.append(50) + scores.append(70) + var ranked = rank_by_preference(ids, scores) + assert_equal(ranked[0], "plan-c") + assert_equal(ranked[1], "plan-a") + assert_equal(ranked[2], "plan-b")