From 90184ad30769e9da37c0393a45ba1e43cf498670 Mon Sep 17 00:00:00 2001 From: Alex Mikhalev Date: Thu, 26 Mar 2026 18:19:15 +0100 Subject: [PATCH] feat(nightwatch): add active hours window for drift evaluation Nightwatch evaluate() is now gated by active_start_hour / active_end_hour in NightwatchConfig. Defaults to 0-24 (always active) for backwards compatibility. Supports wrap-around past midnight (e.g. 22-06). This allows the orchestrator to run nightwatch only during off-peak hours, e.g. 2am-6am, reducing noise during active development. Co-Authored-By: Claude Opus 4.6 --- crates/terraphim_orchestrator/src/config.rs | 11 +++++++++++ crates/terraphim_orchestrator/src/lib.rs | 15 +++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/crates/terraphim_orchestrator/src/config.rs b/crates/terraphim_orchestrator/src/config.rs index 0d2e7c5cb..271eb366c 100644 --- a/crates/terraphim_orchestrator/src/config.rs +++ b/crates/terraphim_orchestrator/src/config.rs @@ -122,6 +122,12 @@ pub struct NightwatchConfig { /// Drift percentage threshold for Critical correction. #[serde(default = "default_critical_threshold")] pub critical_threshold: f64, + /// Hour (0-23) when nightwatch evaluation starts. Default: 0 (midnight). + #[serde(default)] + pub active_start_hour: u8, + /// Hour (0-23) when nightwatch evaluation ends. Default: 24 (always active). + #[serde(default = "default_active_end_hour")] + pub active_end_hour: u8, } impl Default for NightwatchConfig { @@ -132,6 +138,8 @@ impl Default for NightwatchConfig { moderate_threshold: default_moderate_threshold(), severe_threshold: default_severe_threshold(), critical_threshold: default_critical_threshold(), + active_start_hour: 0, + active_end_hour: default_active_end_hour(), } } } @@ -151,6 +159,9 @@ fn default_severe_threshold() -> f64 { fn default_critical_threshold() -> f64 { 0.70 } +fn default_active_end_hour() -> u8 { + 24 +} /// Compound review settings. #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/crates/terraphim_orchestrator/src/lib.rs b/crates/terraphim_orchestrator/src/lib.rs index 44cc4b443..ce79ece95 100644 --- a/crates/terraphim_orchestrator/src/lib.rs +++ b/crates/terraphim_orchestrator/src/lib.rs @@ -62,6 +62,7 @@ pub use nightwatch::{ pub use persona::{MetapromptRenderError, MetapromptRenderer, PersonaRegistry}; pub use scheduler::{ScheduleEvent, TimeScheduler}; +use chrono::Timelike; use std::collections::HashMap; use std::path::Path; use std::time::{Duration, Instant}; @@ -597,8 +598,18 @@ impl AgentOrchestrator { // 4. Drain output events to nightwatch self.drain_output_events(); - // 5. Evaluate nightwatch drift - self.nightwatch.evaluate(); + // 5. Evaluate nightwatch drift (only during active hours) + let nw_cfg = &self.config.nightwatch; + let current_hour = chrono::Local::now().hour() as u8; + let in_window = if nw_cfg.active_start_hour <= nw_cfg.active_end_hour { + current_hour >= nw_cfg.active_start_hour && current_hour < nw_cfg.active_end_hour + } else { + // Wraps past midnight, e.g. start=22 end=6 + current_hour >= nw_cfg.active_start_hour || current_hour < nw_cfg.active_end_hour + }; + if in_window { + self.nightwatch.evaluate(); + } // 6. Sweep expired handoff buffer entries let swept = self.handoff_buffer.sweep_expired();