Add loopd configuration with every M2a limit

Implemented-By: Laguna S 2.1 (OpenCode)
This commit is contained in:
2026-09-17 23:07:38 -07:00
parent a0495ea36a
commit 6e8e24794d
8 changed files with 318 additions and 0 deletions
+143
View File
@@ -0,0 +1,143 @@
//! Tests for `loopd`'s configuration. Do not edit: these define the required behaviour.
use loopd::config::{Config, ConfigError, Limits, Sampling};
use std::path::{Path, PathBuf};
fn fixture(name: &str) -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures/config")
.join(name)
}
#[test]
fn minimal_file_gets_the_documented_defaults() {
let c = Config::load(&fixture("minimal.toml")).unwrap();
assert_eq!(
c.infer.socket,
PathBuf::from("/run/boxmaker/infer/infer.sock")
);
assert_eq!(c.infer.model, "ornith-1.5-35b-a3b");
assert_eq!((c.slots.main, c.slots.background), (0, 1));
assert_eq!(c.expect.n_ctx, 131_072);
assert_eq!(c.expect.slots, 2);
assert_eq!(
c.expect.template_sha256.to_hex(),
"f55f52930aa8bf44ab5cb85f99370fcc3c56e9a85640b812086d5330bce5d86b"
);
assert_eq!(
c.sampling,
Sampling {
temperature: 0.6,
top_p: 0.95,
top_k: 20
}
);
let want = Limits {
poll_ms: 5_000,
busy_wait_ms: 600_000,
load_wait_ms: 180_000,
idle_grace_ms: 30_000,
liveness_ms: 30_000,
thinking_cap: 4_096,
thinking_overrun: 256,
max_tokens: 8_192,
queue_len: 8,
retry_attempts: 4,
retry_backoff_ms: vec![2_000, 8_000, 30_000],
retry_window_ms: 300_000,
};
assert_eq!(c.limits, want);
assert_eq!(Limits::default(), want);
}
#[test]
fn full_file_overrides_every_default() {
let c = Config::load(&fixture("full.toml")).unwrap();
assert_eq!(
c.sampling,
Sampling {
temperature: 0.2,
top_p: 0.9,
top_k: 40
}
);
let want = Limits {
poll_ms: 50,
busy_wait_ms: 200,
load_wait_ms: 300,
idle_grace_ms: 150,
liveness_ms: 100,
thinking_cap: 20,
thinking_overrun: 10,
max_tokens: 512,
queue_len: 1,
retry_attempts: 2,
retry_backoff_ms: vec![10],
retry_window_ms: 1_000,
};
assert_eq!(c.limits, want);
}
#[test]
fn a_partial_limits_table_keeps_the_other_defaults() {
let text = std::fs::read_to_string(fixture("minimal.toml")).unwrap();
let c = Config::parse(&format!("{text}\n[limits]\nliveness_ms = 1234\n")).unwrap();
assert_eq!(c.limits.liveness_ms, 1234);
assert_eq!(c.limits.poll_ms, 5_000);
}
/// Every table in the file must reject a key it does not know: a misspelt limit that silently
/// fell back to its default would be a limit the owner believes is set and is not.
#[test]
fn unknown_keys_are_errors_in_every_table() {
let text = std::fs::read_to_string(fixture("full.toml")).unwrap();
assert!(Config::parse(&text).is_ok());
for table in ["infer", "slots", "expect", "sampling", "limits"] {
let header = format!("[{table}]\n");
assert!(text.contains(&header), "fixture has no [{table}] table");
let bad = text.replacen(&header, &format!("{header}zz_unknown = 1\n"), 1);
assert!(
Config::parse(&bad).is_err(),
"[{table}] accepted an unknown key"
);
}
assert!(
Config::parse(&format!("zz_unknown = 1\n{text}")).is_err(),
"top level"
);
assert!(
Config::parse(&format!("{text}\n[zz_unknown]\nx = 1\n")).is_err(),
"unknown table"
);
}
#[test]
fn required_tables_and_values_are_checked() {
let text = std::fs::read_to_string(fixture("minimal.toml")).unwrap();
for table in ["infer", "slots", "expect"] {
let without: String = text
.split("\n\n")
.filter(|block| !block.trim_start().starts_with(&format!("[{table}]")))
.collect::<Vec<_>>()
.join("\n\n");
assert!(Config::parse(&without).is_err(), "[{table}] is required");
}
let bad_hash = text.replace("f55f5293", "F55F5293");
assert!(
Config::parse(&bad_hash).is_err(),
"the hash must be lowercase hex"
);
let negative = text.replace("main = 0", "main = -1");
assert!(Config::parse(&negative).is_err());
}
#[test]
fn load_reports_which_file_failed() {
let missing = fixture("does-not-exist.toml");
match Config::load(&missing) {
Err(ConfigError::Read(path, _)) => assert_eq!(path, missing),
other => panic!("expected a read error, got {other:?}"),
}
let e: Box<dyn std::error::Error> = Box::new(Config::load(&missing).unwrap_err());
assert!(e.to_string().contains("does-not-exist.toml"));
}
+31
View File
@@ -0,0 +1,31 @@
[infer]
socket = "/tmp/infer.sock"
model = "some-model"
[slots]
main = 2
background = 3
[expect]
template_sha256 = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
n_ctx = 4096
slots = 4
[sampling]
temperature = 0.2
top_p = 0.9
top_k = 40
[limits]
poll_ms = 50
busy_wait_ms = 200
load_wait_ms = 300
idle_grace_ms = 150
liveness_ms = 100
thinking_cap = 20
thinking_overrun = 10
max_tokens = 512
queue_len = 1
retry_attempts = 2
retry_backoff_ms = [10]
retry_window_ms = 1000
+12
View File
@@ -0,0 +1,12 @@
[infer]
socket = "/run/boxmaker/infer/infer.sock"
model = "ornith-1.5-35b-a3b"
[slots]
main = 0
background = 1
[expect]
template_sha256 = "f55f52930aa8bf44ab5cb85f99370fcc3c56e9a85640b812086d5330bce5d86b"
n_ctx = 131072
slots = 2