{"record":{"id":"ddc51902dc9e8de2","repo":"unicity-aos/aos-ce","slug":"topic-key-has-empty-segments-leading-trailing-consecutive","errorCode":null,"errorMessage":"Topic `{key}` has empty segments (leading/trailing/consecutive dots).","messagePattern":"Topic `(.+?)` has empty segments \\(leading/trailing/consecutive dots\\)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"capsules/capsule-forge/src/checks.rs","lineNumber":298,"sourceCode":"                    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) {\n            out.push(Finding::err(\n                format!(\"Topic `{key}` has empty segments (leading/trailing/consecutive dots).\"),\n                \"Remove the stray dots; every segment between dots must be non-empty.\",\n            ));\n        }\n        if key.split('.').count() > 8 {\n            out.push(Finding::warn(\n                format!(\"Topic `{key}` has more than 8 segments — likely a mistake.\"),\n                \"Flatten the topic; deep topic trees usually indicate a naming error.\",\n            ));\n        }\n    }\n    if out.iter().all(|f| f.level != \"error\") {\n        out.push(Finding::info(\n            \"No blocking manifest errors found.\",\n            \"Build with `aos capsule build`, then install with `aos capsule install`.\",\n        ));\n    }\n}","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/unicity-aos/aos-ce/blob/f6f22024fb1e8d122f28a1b4a9f75aee448ae839/capsules/capsule-forge/src/checks.rs#L280-L316","documentation":"check_topic_shapes validates every [publish] and [subscribe] topic key for well-formedness. A topic key containing empty segments — produced by leading dots, trailing dots, or consecutive dots (`..`) — is malformed because topic matching segments on dots, so the manifest is flagged as an error.","triggerScenarios":"validate_manifest -> check_topic_shapes receives a pub/sub key where `key.split('.')` yields any empty string, e.g. `.tool.v1.request`, `tool..v1`, or `tool.v1.`.","commonSituations":"String-building topic names with template concatenation leaving double dots, wildcard patterns typed as `tool..v1.*`, or copy-paste artifacts at the edges of the key.","solutions":["Remove leading/trailing dots and collapse consecutive dots in the topic key.","If wildcards are needed, use `*` per segment instead of empty segments.","Re-run validation; also watch for the >8-segment depth warning on the same key."],"exampleFix":"// before ([subscribe])\n\"tool..v1.request.describe\" = { wit = ..., handler = \"tool_describe\" }\n// after\n\"tool.v1.request.describe\" = { wit = ..., handler = \"tool_describe\" }","handlingStrategy":"validation","validationCode":"// Reject topic keys with empty segments before writing them\nfn topic_ok(key: &str) -> bool {\n    !key.is_empty() && key.split('.').all(|s| !s.is_empty())\n}","typeGuard":"fn is_well_formed_topic(key: &str) -> bool {\n    key.split('.').all(|seg| !seg.is_empty()) && !key.starts_with('.') && !key.ends_with('.')\n}","tryCatchPattern":null,"preventionTips":["Build topics with a helper that joins non-empty segments with '.'.","Add a unit test per topic constant asserting no empty segments.","Keep depth at or under 8 segments to also avoid the depth warning."],"tags":["manifest","config","validation","topic-naming"],"backgroundTag":"invalid-identifier-format","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"}