{"record":{"id":"93a4f698798134d1","repo":"unicity-aos/aos-ce","slug":"subscribe-is-empty-or-missing-the-capsule-cannot-receive-any","errorCode":null,"errorMessage":"[subscribe] is empty or missing — the capsule cannot receive any event.","messagePattern":"\\[subscribe\\] is empty or missing — the capsule cannot receive any event\\.","errorType":"validation","errorClass":"Finding","httpStatus":null,"severity":"warning","filePath":"capsules/capsule-forge/src/checks.rs","lineNumber":204,"sourceCode":"                \"Remove `scope`; shared/operator-only env scope is not honoured from the manifest.\",\n            ));\n        }\n    }\n}\n\n/// Collect the `[publish]` and `[subscribe]` topic keys, warning if a table is\n/// empty (fail-closed: the capsule then can't publish/subscribe at all).\nfn collect_topics(root: &Toml, out: &mut Vec<Finding>) -> (Vec<String>, Vec<String>) {\n    let pub_keys = table_keys(root, \"publish\");\n    let sub_keys = table_keys(root, \"subscribe\");\n    if pub_keys.is_empty() {\n        out.push(Finding::warn(\n            \"[publish] is empty or missing — the capsule cannot publish any event.\",\n            \"Add the tool-bus publish keys `tool.v1.execute.*.result` and `tool.v1.response.describe.*`.\",\n        ));\n    }\n    if sub_keys.is_empty() {\n        out.push(Finding::warn(\n            \"[subscribe] is empty or missing — the capsule cannot receive any event.\",\n            \"Add one `tool.v1.execute.<tool>` per tool plus `tool.v1.request.describe`.\",\n        ));\n    }\n    (pub_keys, sub_keys)\n}\n\nfn table_keys(root: &Toml, table: &str) -> Vec<String> {\n    root.get(table)\n        .and_then(Toml::as_table)\n        .map(|t| t.keys().cloned().collect())\n        .unwrap_or_default()\n}\n\n/// Check the mandatory tool-bus wiring: each `tool.v1.execute.<x>` subscribe has\n/// a handler, the two mandatory publish keys exist, and the describe request is\n/// subscribed.\nfn check_tool_bus(sub_keys: &[String], pub_keys: &[String], root: &Toml, out: &mut Vec<Finding>) {","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/unicity-aos/aos-ce/blob/f6f22024fb1e8d122f28a1b4a9f75aee448ae839/capsules/capsule-forge/src/checks.rs#L186-L222","documentation":"collect_topics also gathers keys from [subscribe] and warns when it is empty or missing. Subscription is fail-closed: without declared subscribe topics the capsule receives no events at all. Forge expects tool capsules to subscribe to one `tool.v1.execute.<tool>` topic per tool plus `tool.v1.request.describe`.","triggerScenarios":"validate_manifest -> collect_topics finds table_keys(root, \"subscribe\") empty — no [subscribe] section in the manifest, or it has zero topic keys.","commonSituations":"Fresh manifest skeleton without wiring yet; author renamed tools and removed subscriptions but never re-added them; copied a publish-only template; typo putting topics under [publish] instead of [subscribe].","solutions":["Add a [subscribe] section containing `tool.v1.execute.<tool>` for each tool the capsule implements plus `tool.v1.request.describe`.","Check topics weren't accidentally declared under [publish]; move them to [subscribe].","If the capsule is intentionally publish-only, accept the warning as documenting that no events are received."],"exampleFix":"# before\n[publish]\n\"tool.v1.execute.*.result\" = {}\n# after\n[publish]\n\"tool.v1.execute.*.result\" = {}\n\n[subscribe]\n\"tool.v1.execute.echo\" = {}\n\"tool.v1.request.describe\" = {}","handlingStrategy":"validation","validationCode":"# ensure [subscribe] exists with required keys before shipping\ntomlq '.subscribe | keys' capsule.toml | grep -q 'tool.v1.execute' || echo \"missing subscribe topics\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Declare one tool.v1.execute.<tool> per implemented tool plus tool.v1.request.describe","Don't mix publish/subscribe sections when copying templates","Run forge validate in CI on every manifest"],"tags":["manifest","subscribe","topics","validation"],"backgroundTag":"empty-required-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"}