{"record":{"id":"a306f8b3cf30be34","repo":"zeroclaw-labs/zeroclaw","slug":"sop-is-not-in-deterministic-mode-mode","errorCode":null,"errorMessage":"SOP '{}' is not in deterministic mode (mode: {})","messagePattern":"SOP '(.+?)' is not in deterministic mode \\(mode: (.+?)\\)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/sop/engine.rs","lineNumber":3684,"sourceCode":"        // / the pending-approval pool that `start_run` enforces. (When reached via\n        // `start_run` the re-check is idempotent under the same held lock.)\n        self.enforce_admission(sop_name)?;\n\n        let sop = self.get_sop(sop_name).ok_or_else(|| {\n            ::zeroclaw_log::record!(\n                WARN,\n                ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)\n                    .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                    .with_attrs(::serde_json::json!({\"sop_name\": sop_name})),\n                \"SOP engine: sop not found\"\n            );\n            anyhow::Error::msg(format!(\"SOP not found: {sop_name}\"))\n        })?;\n\n        // Reject a non-deterministic SOP BEFORE reserving a slot, so a wrong-mode direct\n        // call cannot claim (and then have to roll back) an execution slot.\n        if sop.execution_mode != SopExecutionMode::Deterministic {\n            bail!(\n                \"SOP '{}' is not in deterministic mode (mode: {})\",\n                sop_name,\n                sop.execution_mode\n            );\n        }\n\n        // Reserve + activate through the shared two-phase start path (identical run_id\n        // prefix, logging, and dispatch to the pre-refactor inline body).\n        let reservation = self.reserve_run_slot(sop_name)?;\n        self.activate_reserved_run(reservation, event)\n    }\n\n    pub fn drive_headless_deterministic(\n        &mut self,\n        run_id: &str,\n        first_action: SopRunAction,\n    ) -> Result<SopRunAction> {\n        let mut action = first_action;","sourceCodeStart":3666,"sourceCodeEnd":3702,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/sop/engine.rs#L3666-L3702","documentation":"The deterministic direct-run entry only accepts SOPs whose execution_mode is SopExecutionMode::Deterministic. The mode is checked before an execution slot is reserved, so a wrong-mode direct call cannot claim (and then have to roll back) a slot. Any other mode (e.g. supervised/agent-driven) must go through the normal start-and-approve flow.","triggerScenarios":"Calling the deterministic run entry with an SOP whose manifest declares a non-deterministic execution_mode (for example 'supervised'), or after someone edited SOP.toml to change the mode without updating callers.","commonSituations":"Automation scripts wired to the direct-run API while the SOP was authored for interactive approval; renaming or re-authoring an SOP with a different mode; copy-pasting a trigger/config from a deterministic SOP onto a supervised one.","solutions":["Use the normal SOP start/approval flow for non-deterministic SOPs instead of the deterministic direct entry.","If unattended direct runs are intended, set execution_mode = \"deterministic\" in the SOP's SOP.toml [sop] section.","Check engine.get_sop(name).execution_mode before calling, and route to the right entry based on the mode."],"exampleFix":"# before - SOP.toml\n[sop]\nname = \"nightly-backup\"\nexecution_mode = \"supervised\"\n\n# after - SOP is meant to run unattended via the deterministic entry\n[sop]\nname = \"nightly-backup\"\nexecution_mode = \"deterministic\"","handlingStrategy":"validation","validationCode":"let sop = engine\n    .get_sop(sop_name)\n    .ok_or_else(|| anyhow::anyhow!(\"SOP not found: {sop_name}\"))?;\nif sop.execution_mode != SopExecutionMode::Deterministic {\n    anyhow::bail!(\"use the start/approve flow for {}-mode SOPs\", sop.execution_mode);\n}\nengine.run_deterministic(/* ... */).await?;","typeGuard":"fn is_deterministic(sop: &Sop) -> bool {\n    sop.execution_mode == SopExecutionMode::Deterministic\n}","tryCatchPattern":"match engine.run_deterministic(/* ... */).await {\n    Err(e) if e.to_string().contains(\"is not in deterministic mode\") => {\n        // route this SOP through the supervised start/approve flow instead\n    }\n    other => other?,\n}","preventionTips":["Keep a registry mapping SOPs to their intended entry API based on execution_mode.","Assert the mode in deploy scripts before scheduling unattended runs.","Re-check execution_mode after anyone edits SOP.toml."],"tags":["sop","execution-mode","deterministic"],"backgroundTag":"wrong-execution-mode","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}