feat(cog-pose): --adapter CLI flag for per-room calibration

Completes the end-to-end product path: cog-pose-estimation run --config
<cfg> --adapter <room.safetensors> loads the shared base + a per-room LoRA
adapter for calibrated inference. Adds InferenceEngine::with_adapter()
(default weights + adapter) and logs when a calibration adapter is active.
6/6 tests pass.

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
ruv 2026-05-31 02:28:16 -04:00
parent 3760db6c9a
commit 83299b4d04
2 changed files with 20 additions and 3 deletions

View File

@ -191,6 +191,12 @@ impl InferenceEngine {
Self::with_weights(default_weights_path().as_deref()) Self::with_weights(default_weights_path().as_deref())
} }
/// Engine from the default base weights plus an optional per-room calibration
/// adapter (ADR-150 §3.5). Used by `cog-pose-estimation run --adapter <path>`.
pub fn with_adapter(adapter_path: Option<&Path>) -> Result<Self, Box<dyn std::error::Error>> {
Self::with_weights_and_adapter(default_weights_path().as_deref(), adapter_path)
}
/// Create an engine with a specific weights path (used by `--config` /// Create an engine with a specific weights path (used by `--config`
/// in `cog-pose-estimation run`). If `weights_path` is `None`, the /// in `cog-pose-estimation run`). If `weights_path` is `None`, the
/// stub fallback is used. /// stub fallback is used.

View File

@ -42,6 +42,11 @@ enum Cmd {
/// Path to runtime config JSON. See `cog/config.schema.json`. /// Path to runtime config JSON. See `cog/config.schema.json`.
#[arg(long, value_name = "PATH")] #[arg(long, value_name = "PATH")]
config: PathBuf, config: PathBuf,
/// Optional per-room LoRA calibration adapter (ADR-150 §3.5). Fit one with
/// `aether-arena/calibration/calibrate.py`; attaching it recovers SOTA-level
/// pose in an unseen room/person.
#[arg(long, value_name = "PATH")]
adapter: Option<PathBuf>,
}, },
} }
@ -53,7 +58,7 @@ fn main() -> std::process::ExitCode {
Cmd::Version => cmd_version(), Cmd::Version => cmd_version(),
Cmd::Manifest => cmd_manifest(), Cmd::Manifest => cmd_manifest(),
Cmd::Health => cmd_health(), Cmd::Health => cmd_health(),
Cmd::Run { config } => cmd_run(config), Cmd::Run { config, adapter } => cmd_run(config, adapter),
}; };
match result { match result {
@ -99,11 +104,17 @@ fn cmd_health() -> Result<(), Box<dyn std::error::Error>> {
} }
} }
fn cmd_run(config_path: PathBuf) -> Result<(), Box<dyn std::error::Error>> { fn cmd_run(
config_path: PathBuf,
adapter: Option<PathBuf>,
) -> Result<(), Box<dyn std::error::Error>> {
let cfg = CogConfig::load(&config_path)?; let cfg = CogConfig::load(&config_path)?;
emit_event(&Event::run_started(COG_ID, &cfg)); emit_event(&Event::run_started(COG_ID, &cfg));
let engine = InferenceEngine::new()?; let engine = InferenceEngine::with_adapter(adapter.as_deref())?;
if engine.is_calibrated() {
tracing::info!("per-room calibration adapter loaded");
}
let rt = tokio::runtime::Builder::new_multi_thread() let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all() .enable_all()
.build()?; .build()?;