commit 22253d833097dd81edbcea1121097906f6d580f5
parent c8c4b5494baee49fd0287fbb89a247049c9e241c
Author: triesap <tyson@radroots.org>
Date: Thu, 9 Apr 2026 16:51:23 +0000
runtime: add hyf path contract
Diffstat:
9 files changed, 336 insertions(+), 1 deletion(-)
diff --git a/pixi.toml b/pixi.toml
@@ -18,5 +18,6 @@ mojson = { path = "../../../../vendor/mojo/mojson" }
[tasks]
run = "mojo run src/main.mojo"
test-unit = "mojo -I src tests/test_hyf.mojo"
+test-runtime = "mojo -I src tests/test_runtime_paths.mojo"
test-stdio = "mojo -I src tests/test_stdio_contract.mojo"
-test = { depends-on = ["test-unit", "test-stdio"] }
+test = { depends-on = ["test-unit", "test-runtime", "test-stdio"] }
diff --git a/src/hyf_runtime/__init__.mojo b/src/hyf_runtime/__init__.mojo
@@ -0,0 +1 @@
+
diff --git a/src/hyf_runtime/errors.mojo b/src/hyf_runtime/errors.mojo
@@ -0,0 +1,2 @@
+def raise_runtime_contract_error(message: String) raises:
+ raise Error("hyf runtime contract: " + message)
diff --git a/src/hyf_runtime/namespace.mojo b/src/hyf_runtime/namespace.mojo
@@ -0,0 +1,36 @@
+from hyf_runtime.errors import raise_runtime_contract_error
+
+
+comptime _HYF_RUNTIME_NAMESPACE = "services/hyf"
+
+
+def hyf_runtime_namespace() -> String:
+ return _HYF_RUNTIME_NAMESPACE
+
+
+def validate_runtime_namespace(namespace: String) raises:
+ if namespace != _HYF_RUNTIME_NAMESPACE:
+ raise_runtime_contract_error(
+ "namespace must be '" + _HYF_RUNTIME_NAMESPACE + "'"
+ )
+
+
+def _trim_trailing_slashes(path: String) -> String:
+ var trimmed = String(String(path).strip())
+ while trimmed.byte_length() > 1 and trimmed.endswith("/"):
+ trimmed = String(trimmed[byte = 0 : trimmed.byte_length() - 1])
+ return trimmed^
+
+
+def join_runtime_path(left: String, right: String) raises -> String:
+ var normalized_left = _trim_trailing_slashes(left)
+ var normalized_right = String(String(right).strip())
+
+ if normalized_left == "":
+ raise_runtime_contract_error("path root must not be empty")
+ if normalized_right == "":
+ raise_runtime_contract_error("path leaf must not be empty")
+
+ if normalized_left == "/":
+ return "/" + normalized_right
+ return normalized_left + "/" + normalized_right
diff --git a/src/hyf_runtime/paths.mojo b/src/hyf_runtime/paths.mojo
@@ -0,0 +1,63 @@
+from hyf_runtime.namespace import (
+ hyf_runtime_namespace,
+ join_runtime_path,
+ validate_runtime_namespace,
+)
+from hyf_runtime.roots import (
+ RuntimeRootSet,
+ runtime_roots_for_unix_profile,
+)
+
+
+@fieldwise_init
+struct RuntimePaths(Copyable, Movable):
+ var namespace: String
+ var config_dir: String
+ var config_path: String
+ var data_dir: String
+ var cache_dir: String
+ var logs_dir: String
+ var diagnostics_dir: String
+ var run_dir: String
+ var secrets_dir: String
+ var identity_path: String
+
+
+def runtime_paths_for_namespace(
+ roots: RuntimeRootSet, namespace: String
+) raises -> RuntimePaths:
+ validate_runtime_namespace(namespace)
+
+ var config_dir = join_runtime_path(roots.config_root, namespace)
+ var data_dir = join_runtime_path(roots.data_root, namespace)
+ var cache_dir = join_runtime_path(roots.cache_root, namespace)
+ var logs_dir = join_runtime_path(roots.logs_root, namespace)
+ var run_dir = join_runtime_path(roots.run_root, namespace)
+ var secrets_dir = join_runtime_path(roots.secrets_root, namespace)
+
+ return RuntimePaths(
+ namespace=String(namespace),
+ config_dir=String(config_dir),
+ config_path=join_runtime_path(config_dir, "config.toml"),
+ data_dir=String(data_dir),
+ cache_dir=String(cache_dir),
+ logs_dir=String(logs_dir),
+ diagnostics_dir=join_runtime_path(logs_dir, "diagnostics"),
+ run_dir=String(run_dir),
+ secrets_dir=String(secrets_dir),
+ identity_path=join_runtime_path(secrets_dir, "identity.secret.json"),
+ )
+
+
+def hyf_runtime_paths_for_roots(roots: RuntimeRootSet) raises -> RuntimePaths:
+ return runtime_paths_for_namespace(roots, hyf_runtime_namespace())
+
+
+def hyf_runtime_paths_for_unix_profile(
+ profile: String,
+ user_home: String,
+ repo_local_base_root: String,
+) raises -> RuntimePaths:
+ return hyf_runtime_paths_for_roots(
+ runtime_roots_for_unix_profile(profile, user_home, repo_local_base_root)
+ )
diff --git a/src/hyf_runtime/platform.mojo b/src/hyf_runtime/platform.mojo
@@ -0,0 +1,39 @@
+from hyf_runtime.errors import raise_runtime_contract_error
+from hyf_runtime.namespace import join_runtime_path
+
+
+def _require_non_empty_path(path: String, context: String) raises -> String:
+ var trimmed = String(String(path).strip())
+ if trimmed == "":
+ raise_runtime_contract_error(context + " must not be empty")
+ return trimmed^
+
+
+def interactive_user_base_root(user_home: String) raises -> String:
+ return join_runtime_path(
+ _require_non_empty_path(user_home, "interactive_user home"), ".radroots"
+ )
+
+
+def service_host_config_root() -> String:
+ return "/etc/radroots"
+
+
+def service_host_data_root() -> String:
+ return "/var/lib/radroots"
+
+
+def service_host_cache_root() -> String:
+ return "/var/cache/radroots"
+
+
+def service_host_logs_root() -> String:
+ return "/var/log/radroots"
+
+
+def service_host_run_root() -> String:
+ return "/run/radroots"
+
+
+def service_host_secrets_root() -> String:
+ return "/etc/radroots/secrets"
diff --git a/src/hyf_runtime/profile.mojo b/src/hyf_runtime/profile.mojo
@@ -0,0 +1,35 @@
+from hyf_runtime.errors import raise_runtime_contract_error
+
+
+comptime _INTERACTIVE_USER_PROFILE = "interactive_user"
+comptime _SERVICE_HOST_PROFILE = "service_host"
+comptime _REPO_LOCAL_PROFILE = "repo_local"
+
+
+def interactive_user_profile() -> String:
+ return _INTERACTIVE_USER_PROFILE
+
+
+def service_host_profile() -> String:
+ return _SERVICE_HOST_PROFILE
+
+
+def repo_local_profile() -> String:
+ return _REPO_LOCAL_PROFILE
+
+
+def validate_runtime_profile(profile: String) raises:
+ if (
+ profile != _INTERACTIVE_USER_PROFILE
+ and profile != _SERVICE_HOST_PROFILE
+ and profile != _REPO_LOCAL_PROFILE
+ ):
+ raise_runtime_contract_error(
+ "profile must be '"
+ + _INTERACTIVE_USER_PROFILE
+ + "', '"
+ + _SERVICE_HOST_PROFILE
+ + "', or '"
+ + _REPO_LOCAL_PROFILE
+ + "'"
+ )
diff --git a/src/hyf_runtime/roots.mojo b/src/hyf_runtime/roots.mojo
@@ -0,0 +1,74 @@
+from hyf_runtime.errors import raise_runtime_contract_error
+from hyf_runtime.namespace import join_runtime_path
+from hyf_runtime.platform import (
+ interactive_user_base_root,
+ service_host_cache_root,
+ service_host_config_root,
+ service_host_data_root,
+ service_host_logs_root,
+ service_host_run_root,
+ service_host_secrets_root,
+)
+from hyf_runtime.profile import (
+ interactive_user_profile,
+ repo_local_profile,
+ service_host_profile,
+ validate_runtime_profile,
+)
+
+
+@fieldwise_init
+struct RuntimeRootSet(Copyable, Movable):
+ var config_root: String
+ var data_root: String
+ var cache_root: String
+ var logs_root: String
+ var run_root: String
+ var secrets_root: String
+
+
+def runtime_roots_from_base_root(base_root: String) raises -> RuntimeRootSet:
+ if String(base_root).strip() == "":
+ raise_runtime_contract_error("base root must not be empty")
+
+ return RuntimeRootSet(
+ config_root=join_runtime_path(base_root, "config"),
+ data_root=join_runtime_path(base_root, "data"),
+ cache_root=join_runtime_path(base_root, "cache"),
+ logs_root=join_runtime_path(base_root, "logs"),
+ run_root=join_runtime_path(base_root, "run"),
+ secrets_root=join_runtime_path(base_root, "secrets"),
+ )
+
+
+def interactive_user_runtime_roots(user_home: String) raises -> RuntimeRootSet:
+ return runtime_roots_from_base_root(interactive_user_base_root(user_home))
+
+
+def service_host_runtime_roots() -> RuntimeRootSet:
+ return RuntimeRootSet(
+ config_root=service_host_config_root(),
+ data_root=service_host_data_root(),
+ cache_root=service_host_cache_root(),
+ logs_root=service_host_logs_root(),
+ run_root=service_host_run_root(),
+ secrets_root=service_host_secrets_root(),
+ )
+
+
+def runtime_roots_for_unix_profile(
+ profile: String,
+ user_home: String,
+ repo_local_base_root: String,
+) raises -> RuntimeRootSet:
+ validate_runtime_profile(profile)
+
+ if profile == interactive_user_profile():
+ return interactive_user_runtime_roots(user_home)
+
+ if profile == service_host_profile():
+ return service_host_runtime_roots()
+
+ if String(repo_local_base_root).strip() == "":
+ raise_runtime_contract_error("repo_local profile requires a base root")
+ return runtime_roots_from_base_root(repo_local_base_root)
diff --git a/tests/test_runtime_paths.mojo b/tests/test_runtime_paths.mojo
@@ -0,0 +1,84 @@
+from std.testing import TestSuite, assert_equal, assert_raises
+
+from hyf_runtime.paths import (
+ hyf_runtime_paths_for_unix_profile,
+ runtime_paths_for_namespace,
+)
+from hyf_runtime.roots import runtime_roots_from_base_root
+
+
+def test_runtime_paths_repo_local_contract_vector() raises:
+ var paths = hyf_runtime_paths_for_unix_profile(
+ "repo_local", "/home/unused", "/tmp/radroots-local/"
+ )
+
+ assert_equal(paths.namespace, "services/hyf")
+ assert_equal(paths.config_dir, "/tmp/radroots-local/config/services/hyf")
+ assert_equal(
+ paths.config_path,
+ "/tmp/radroots-local/config/services/hyf/config.toml",
+ )
+ assert_equal(paths.data_dir, "/tmp/radroots-local/data/services/hyf")
+ assert_equal(paths.cache_dir, "/tmp/radroots-local/cache/services/hyf")
+ assert_equal(paths.logs_dir, "/tmp/radroots-local/logs/services/hyf")
+ assert_equal(
+ paths.diagnostics_dir,
+ "/tmp/radroots-local/logs/services/hyf/diagnostics",
+ )
+ assert_equal(paths.run_dir, "/tmp/radroots-local/run/services/hyf")
+ assert_equal(
+ paths.identity_path,
+ "/tmp/radroots-local/secrets/services/hyf/identity.secret.json",
+ )
+
+
+def test_runtime_paths_interactive_user_contract_vector() raises:
+ var paths = hyf_runtime_paths_for_unix_profile(
+ "interactive_user", "/Users/radroots-test", ""
+ )
+
+ assert_equal(
+ paths.config_path,
+ "/Users/radroots-test/.radroots/config/services/hyf/config.toml",
+ )
+ assert_equal(
+ paths.data_dir, "/Users/radroots-test/.radroots/data/services/hyf"
+ )
+ assert_equal(
+ paths.secrets_dir,
+ "/Users/radroots-test/.radroots/secrets/services/hyf",
+ )
+
+
+def test_runtime_paths_service_host_contract_vector() raises:
+ var paths = hyf_runtime_paths_for_unix_profile(
+ "service_host", "/home/unused", ""
+ )
+
+ assert_equal(paths.config_path, "/etc/radroots/services/hyf/config.toml")
+ assert_equal(paths.data_dir, "/var/lib/radroots/services/hyf")
+ assert_equal(paths.cache_dir, "/var/cache/radroots/services/hyf")
+ assert_equal(paths.logs_dir, "/var/log/radroots/services/hyf")
+ assert_equal(paths.run_dir, "/run/radroots/services/hyf")
+ assert_equal(paths.secrets_dir, "/etc/radroots/secrets/services/hyf")
+
+
+def test_runtime_paths_reject_invalid_profile_namespace_and_base_root() raises:
+ with assert_raises():
+ _ = hyf_runtime_paths_for_unix_profile(
+ "developer_laptop", "/Users/radroots-test", ""
+ )
+
+ with assert_raises():
+ _ = hyf_runtime_paths_for_unix_profile(
+ "repo_local", "/Users/radroots-test", ""
+ )
+
+ with assert_raises():
+ _ = runtime_paths_for_namespace(
+ runtime_roots_from_base_root("/tmp/radroots-local"), "hyf"
+ )
+
+
+def main() raises:
+ TestSuite.discover_tests[__functions_in_module()]().run()