{"record":{"id":"df1e3db442b1e8f6","repo":"unicity-aos/aos-ce","slug":"mandatory-publish-key-required-is-missing","errorCode":null,"errorMessage":"Mandatory publish key `{required}` is missing.","messagePattern":"Mandatory publish key `(.+?)` is missing\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"capsules/capsule-forge/src/checks.rs","lineNumber":279,"sourceCode":"        }\n        saw_execute_tool = true;\n        let has_handler = sub_table\n            .and_then(|t| t.get(key))\n            .and_then(|v| v.get(\"handler\"))\n            .and_then(Toml::as_str)\n            .is_some_and(|h| !h.is_empty());\n        if !has_handler {\n            out.push(Finding::err(\n                format!(\"Subscribe `{key}` has no `handler`.\"),\n                format!(\"Add `handler = \\\"tool_execute_{tool}\\\"` to the `{key}` row.\"),\n            ));\n        }\n    }\n\n    if saw_execute_tool {\n        for required in [\"tool.v1.execute.*.result\", \"tool.v1.response.describe.*\"] {\n            if !pub_keys.iter().any(|k| k == required) {\n                out.push(Finding::err(\n                    format!(\"Mandatory publish key `{required}` is missing.\"),\n                    format!(\"Add `\\\"{required}\\\" = {{ wit = ... }}` to [publish]; tool results/describe break without it.\"),\n                ));\n            }\n        }\n        if !sub_keys.iter().any(|k| k == \"tool.v1.request.describe\") {\n            out.push(Finding::err(\n                \"Subscribe `tool.v1.request.describe` is missing — tools won't be discoverable.\",\n                \"Add `\\\"tool.v1.request.describe\\\" = { wit = ..., handler = \\\"tool_describe\\\" }` to [subscribe].\",\n            ));\n        }\n    }\n}\n\n/// Flag malformed topic keys: empty segments, or absurd depth (>8 segments).\nfn check_topic_shapes(pub_keys: &[String], sub_keys: &[String], out: &mut Vec<Finding>) {\n    for key in pub_keys.iter().chain(sub_keys) {\n        if has_empty_segments(key) {","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/unicity-aos/aos-ce/blob/f6f22024fb1e8d122f28a1b4a9f75aee448ae839/capsules/capsule-forge/src/checks.rs#L261-L297","documentation":"When a manifest declares it executes tools (`saw_execute_tool`), the tool-bus protocol requires the capsule to publish results and describe responses on two mandatory topics: `tool.v1.execute.*.result` and `tool.v1.response.describe.*`. check_tool_bus scans the [publish] keys and fails the manifest if either is missing, because downstream consumers of tool results/describe would break.","triggerScenarios":"validate_manifest -> check_tool_bus with an execute-tool capability present but [publish] lacking `tool.v1.execute.*.result` or `tool.v1.response.describe.*`.","commonSituations":"Adding tool execution to a capsule without wiring result topics, trimming [publish] entries during refactoring, or copying a minimal manifest template that only covers requests.","solutions":["Add `\"tool.v1.execute.*.result\" = { wit = ... }` to the [publish] table.","Add `\"tool.v1.response.describe.*\" = { wit = ... }` to the [publish] table.","Re-run `capsule-forge validate` and check the sibling error for `tool.v1.request.describe` in [subscribe]."],"exampleFix":"// before ([publish])\n\"tool.v1.request.execute\" = { wit = ... }\n// after\n\"tool.v1.request.execute\" = { wit = ... }\n\"tool.v1.execute.*.result\" = { wit = ... }\n\"tool.v1.response.describe.*\" = { wit = ... }","handlingStrategy":"validation","validationCode":"// Check mandatory publish keys before validating\nconst REQUIRED: [&str; 2] = [\"tool.v1.execute.*.result\", \"tool.v1.response.describe.*\"];\nfor r in REQUIRED { assert!(publish.contains_key(r), \"missing {r}\"); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Start tool capsules from the full template that already includes both publish keys.","Add the required-topic list to a shared manifest schema/linter.","Review any manual edit to [publish] against the tool-bus protocol checklist."],"tags":["manifest","config","validation","protocol"],"backgroundTag":"missing-required-config-field","analyzedSha":"f6f22024fb1e8d122f28a1b4a9f75aee448ae839","analyzedAt":"2026-09-13T03:04:44.565Z","contentChangedAt":"2026-09-13T03:04:44.565Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}