{"record":{"id":"48e776a4d80a1726","repo":"zeroclaw-labs/zeroclaw","slug":"candidate-manifest-name-does-not-match-propos","errorCode":null,"errorMessage":"candidate manifest name '{}' does not match proposal target '{}'","messagePattern":"candidate manifest name '(.+?)' does not match proposal target '(.+?)'","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/sop/procedural_memory.rs","lineNumber":244,"sourceCode":"fn load_required(engine: &SopEngine, proposal_id: &str) -> Result<ProposalRecord> {\n    engine\n        .load_proposal(proposal_id)\n        .map_err(anyhow::Error::new)?\n        .ok_or_else(|| anyhow::Error::msg(format!(\"proposal not found: {proposal_id}\")))\n}\n\nfn validate_candidate(sop_name: &str, manifest_toml: &str, procedure_markdown: &str) -> Result<()> {\n    let tmp = tempfile::tempdir()?;\n    let sop_dir = tmp.path().join(slugify(sop_name));\n    fs::create_dir_all(&sop_dir)?;\n    fs::write(sop_dir.join(\"SOP.toml\"), manifest_toml)?;\n    fs::write(sop_dir.join(\"SOP.md\"), procedure_markdown)?;\n    let sops = load_sops_from_directory(tmp.path(), super::parse_execution_mode(\"supervised\"));\n    if sops.len() != 1 {\n        bail!(\"candidate SOP did not validate as exactly one loadable SOP\");\n    }\n    if sops[0].name != sop_name {\n        bail!(\n            \"candidate manifest name '{}' does not match proposal target '{}'\",\n            sops[0].name,\n            sop_name\n        );\n    }\n    if sops[0].steps.is_empty() {\n        bail!(\"candidate SOP has no parsed steps\");\n    }\n    Ok(())\n}\n\nfn scan_candidate(manifest_toml: &str, procedure_markdown: &str) -> Option<String> {\n    let detector = LeakDetector::new();\n    let content = format!(\"{manifest_toml}\\n{procedure_markdown}\");\n    match detector.scan(&content) {\n        LeakResult::Clean => None,\n        LeakResult::Detected { patterns, .. } => Some(format!(\n            \"credential-like content detected: {}\",","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/sop/procedural_memory.rs#L226-L262","documentation":"After validate_candidate round-trip-loads the candidate SOP from a temp directory, it requires the loaded SOP's name to equal the proposal's sop_name byte-for-byte. This error means the manifest's [sop] name field and the ProposalDraft.sop_name (or the stored proposal's sop_name) disagree. The check prevents writing a directory named after one SOP whose manifest claims to be a different SOP.","triggerScenarios":"Calling create_proposal with a custom manifest_toml whose [sop] name differs from draft.sop_name (e.g. an existing SOP's manifest reused as a template for a new SOP); or apply_proposal on a stored proposal whose manifest was edited after capture so the name no longer matches; also capture_successful_run when the on-disk SOP.toml name has drifted from the name the engine loaded the SOP under.","commonSituations":"Copy-paste of another SOP's SOP.toml as a template without renaming, case-only renames (\"Deploy Check\" vs \"deploy check\") since the comparison is exact, and renaming a SOP in config while its manifest still carries the old name.","solutions":["Set the [sop] name field in manifest_toml to exactly the same string as the proposal's sop_name (case-sensitive)","Or omit manifest_toml (pass None or whitespace) so create_proposal generates a matching manifest via default_manifest_toml(sop_name, description)","For an Update proposal whose on-disk SOP.toml name drifted, fix the SOP.toml on disk first and re-capture the proposal via capture_successful_run or create_proposal"],"exampleFix":"// before\nlet manifest = r#\"[sop]\nname = \"deploy-check\"\n...\"#;\ncreate_proposal(&engine, ProposalDraft { sop_name: \"deploy verify\".into(), manifest_toml: Some(manifest.into()), .. })?;\n\n// after - manifest name must equal sop_name exactly\nlet manifest = r#\"[sop]\nname = \"deploy verify\"\n...\"#;\ncreate_proposal(&engine, ProposalDraft { sop_name: \"deploy verify\".into(), manifest_toml: Some(manifest.into()), .. })?;","handlingStrategy":"validation","validationCode":"// Before create_proposal, assert the manifest name equals the draft name:\nfn manifest_name_matches(sop_name: &str, manifest_toml: &str) -> bool {\n    manifest_toml\n        .lines()\n        .any(|l| l.trim_start_matches(' ').starts_with(\"name\") && l.contains(&format!(\"\\\"{}\\\"\", sop_name)))\n}","typeGuard":null,"tryCatchPattern":"Err(e) if e.to_string().contains(\"does not match proposal target\") => {\n    // read the expected name from the error, patch [sop].name, resubmit once\n}","preventionTips":["Derive [sop].name programmatically from draft.sop_name when building manifests","Omit manifest_toml to let default_manifest_toml produce a guaranteed-matching manifest","Treat name and directory slug as one concept: rename SOPs by re-proposing, not by editing manifests"],"tags":["sop","toml","naming","validation","procedural-memory"],"backgroundTag":"config-name-mismatch","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}