mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-25 14:53:34 +00:00
fix(routines): surface errors when sandbox unavailable for full_job routines (#769)
* feat(db): add list_dispatched_routine_runs to RoutineStore trait Add method to query routine runs with status='running' AND job_id IS NOT NULL, enabling the routine engine to sync completion status from background jobs. Implements for both PostgreSQL and libSQL backends. [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix(routines): sync dispatched full-job runs with background job status (#697) Full-job routines were immediately marked Ok on dispatch, so failures/completions were never reflected in the routine run record. Now dispatch returns Running status, and a periodic sync checks linked jobs to update the run when the job completes, fails, or is cancelled. Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix(routines): fail fast when sandbox unavailable at dispatch time (#697) Thread sandbox_available bool from Docker detection through AgentDeps to RoutineEngine. Full-job routines now fail immediately with a clear error message when sandbox is enabled but Docker is not available, instead of dispatching a job that silently fails. Co-Authored-By: Claude Opus 4.6 <[email protected]> * feat(startup): notify user when sandbox unavailable (#697) When sandbox is enabled but Docker is not installed or not running, send a user-visible warning through all channels at startup (with a 2s delay to let channels connect). Previously this was only logged via tracing::warn, invisible to TUI/web users. Co-Authored-By: Claude Opus 4.6 <[email protected]> * style: fix formatting in routine_engine.rs Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix(tests): set sandbox_available=true in test rig for full_job traces Test rig doesn't use real Docker — full_job routines execute via trace replay. Setting sandbox_available=true allows the routine_news_digest trace test to dispatch full_job routines as before. Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix(routines): address review feedback on sync_dispatched_runs (#697) - Sanitize last_reason from job transitions before using in notifications (truncate to 500 chars, strip control characters) - Treat Submitted as in-progress (can still transition to Failed), only Completed and Accepted are terminal success states - Add test for sanitize_summary Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix(tests): add missing sandbox_available field to test constructors Staging added sandbox_available to AgentDeps and RoutineEngine::new. Add the missing field/argument in test files to fix CI compilation. Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: sanitize job reason in notifications, fix state handling for Submitted/Accepted - Enhance sanitize_summary to strip HTML tags and collapse whitespace, preventing injection via untrusted container job reasons - Use char-boundary-safe truncation to avoid panics on multi-byte strings - Treat Submitted and Accepted as in-progress states (continue polling) rather than terminal success, since they can still transition to Failed - Increase channel-connect delay from 2s to 5s and add debug log for sandbox-unavailable warning delivery Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * Replace sandbox_available bool with SandboxReadiness enum Distinguishes DisabledByConfig from DockerUnavailable so full-job routine errors give actionable guidance instead of a generic message. Co-Authored-By: Claude Opus 4.6 <[email protected]> * ci: re-trigger CI with latest changes Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: add missing owner_id arg to send_notification call Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: update e2e tests to use SandboxReadiness enum Co-Authored-By: Claude Opus 4.6 <[email protected]> --------- Co-authored-by: Claude Opus 4.6 <[email protected]> Co-authored-by: [email protected] <[email protected]>
This commit is contained in:
@@ -20,7 +20,7 @@ mod tests {
|
||||
RunStatus, Trigger,
|
||||
};
|
||||
use ironclaw::agent::routine_engine::RoutineEngine;
|
||||
use ironclaw::agent::{HeartbeatConfig, HeartbeatRunner, Scheduler};
|
||||
use ironclaw::agent::{HeartbeatConfig, HeartbeatRunner, SandboxReadiness, Scheduler};
|
||||
use ironclaw::channels::IncomingMessage;
|
||||
use ironclaw::config::{AgentConfig, RoutineConfig, SafetyConfig};
|
||||
use ironclaw::context::{ContextManager, JobContext};
|
||||
@@ -266,6 +266,7 @@ mod tests {
|
||||
Some(scheduler),
|
||||
registry,
|
||||
safety,
|
||||
SandboxReadiness::DisabledByConfig,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -346,6 +347,7 @@ mod tests {
|
||||
None,
|
||||
tools,
|
||||
safety,
|
||||
SandboxReadiness::DisabledByConfig,
|
||||
));
|
||||
|
||||
// Insert a cron routine with next_fire_at in the past.
|
||||
@@ -423,6 +425,7 @@ mod tests {
|
||||
None,
|
||||
tools,
|
||||
safety,
|
||||
SandboxReadiness::DisabledByConfig,
|
||||
));
|
||||
|
||||
// Insert an event routine matching "deploy.*production".
|
||||
@@ -516,6 +519,7 @@ mod tests {
|
||||
None,
|
||||
tools,
|
||||
safety,
|
||||
SandboxReadiness::DisabledByConfig,
|
||||
));
|
||||
|
||||
let routine = make_routine(
|
||||
@@ -623,6 +627,7 @@ mod tests {
|
||||
None,
|
||||
tools,
|
||||
safety,
|
||||
SandboxReadiness::DisabledByConfig,
|
||||
));
|
||||
|
||||
let mut filters = std::collections::HashMap::new();
|
||||
@@ -764,6 +769,7 @@ mod tests {
|
||||
None,
|
||||
tools,
|
||||
safety,
|
||||
SandboxReadiness::DisabledByConfig,
|
||||
));
|
||||
|
||||
// Insert an event routine with 1-hour cooldown.
|
||||
@@ -949,6 +955,7 @@ mod tests {
|
||||
None,
|
||||
tools,
|
||||
safety,
|
||||
SandboxReadiness::DisabledByConfig,
|
||||
));
|
||||
|
||||
(engine, db, dir)
|
||||
@@ -1078,6 +1085,7 @@ mod tests {
|
||||
None, // no scheduler — rejected before dispatch
|
||||
tools,
|
||||
safety,
|
||||
SandboxReadiness::DisabledByConfig,
|
||||
));
|
||||
|
||||
// Create a full_job routine with max_concurrent = 1
|
||||
@@ -1186,6 +1194,7 @@ mod tests {
|
||||
None,
|
||||
tools,
|
||||
safety,
|
||||
SandboxReadiness::DisabledByConfig,
|
||||
));
|
||||
|
||||
// Insert a due cron routine
|
||||
|
||||
@@ -198,6 +198,7 @@ mod tests {
|
||||
http_interceptor: None,
|
||||
transcription: None,
|
||||
document_extraction: None,
|
||||
sandbox_readiness: ironclaw::agent::SandboxReadiness::DisabledByConfig,
|
||||
builder: None,
|
||||
};
|
||||
|
||||
|
||||
@@ -257,6 +257,7 @@ impl GatewayWorkflowHarness {
|
||||
http_interceptor: None,
|
||||
transcription: None,
|
||||
document_extraction: None,
|
||||
sandbox_readiness: ironclaw::agent::SandboxReadiness::DisabledByConfig,
|
||||
builder: None,
|
||||
},
|
||||
channels,
|
||||
|
||||
@@ -578,6 +578,7 @@ impl TestRigBuilder {
|
||||
None,
|
||||
components.tools.clone(),
|
||||
components.safety.clone(),
|
||||
ironclaw::agent::SandboxReadiness::Available, // tests don't use real Docker
|
||||
));
|
||||
components
|
||||
.tools
|
||||
@@ -642,6 +643,7 @@ impl TestRigBuilder {
|
||||
},
|
||||
transcription: None,
|
||||
document_extraction: None,
|
||||
sandbox_readiness: ironclaw::agent::SandboxReadiness::Available, // tests don't use real Docker
|
||||
builder: None,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user