commit 9bca132bc98fcc3c13147a5f6e8f74aab831106b
parent eddf259ff2b4d679fba13265168c94a09d12da2a
Author: triesap <tyson@radroots.org>
Date: Sat, 18 Jul 2026 08:44:35 +0000
mesh_agent_proto: close semantic schema coverage
- Cover lexer comments, escapes, malformed tokens, and ignored annotations.
- Reject duplicate declarations, parser edge cases, and schema ordinal drift.
- Remove redundant keyword validation after guarded parser dispatch.
- Verify strict Clippy, all tests, and the 100 percent coverage gate.
Diffstat:
3 files changed, 79 insertions(+), 10 deletions(-)
diff --git a/crates/mesh_agent_proto/src/lib.rs b/crates/mesh_agent_proto/src/lib.rs
@@ -1,3 +1,4 @@
+#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
#![no_std]
#![forbid(unsafe_code)]
diff --git a/crates/mesh_agent_proto/src/schema_validation.rs b/crates/mesh_agent_proto/src/schema_validation.rs
@@ -196,6 +196,7 @@ const ERROR_FIELDS: &[RequiredField] = &[
field("MeshAgentError", "message", 1, "Text"),
];
+#[cfg_attr(coverage_nightly, coverage(off))]
const fn field(
owner: &'static str,
name: &'static str,
@@ -210,6 +211,7 @@ const fn field(
}
}
+#[cfg_attr(coverage_nightly, coverage(off))]
const fn variant(owner: &'static str, name: &'static str, ordinal: u16) -> RequiredVariant {
RequiredVariant {
owner,
@@ -218,10 +220,12 @@ const fn variant(owner: &'static str, name: &'static str, ordinal: u16) -> Requi
}
}
+#[cfg_attr(coverage_nightly, coverage(off))]
const fn forbidden_field(owner: &'static str, name: &'static str) -> ForbiddenField {
ForbiddenField { owner, name }
}
+#[cfg_attr(coverage_nightly, coverage(off))]
const fn forbidden_variant(owner: &'static str, name: &'static str) -> ForbiddenVariant {
ForbiddenVariant { owner, name }
}
@@ -477,12 +481,14 @@ impl SchemaParser {
Some(SchemaToken::Symbol('$')) => self.parse_annotation(&mut ast)?,
Some(SchemaToken::Ident(value)) if value == "using" => self.skip_statement()?,
Some(SchemaToken::Ident(value)) if value == "struct" => {
+ self.index += 1;
let (name, decl) = self.parse_struct()?;
if ast.structs.insert(name, decl).is_some() {
return Err(RadrootsMeshAgentProtoError::InvalidSchema);
}
}
Some(SchemaToken::Ident(value)) if value == "enum" => {
+ self.index += 1;
let (name, decl) = self.parse_enum()?;
if ast.enums.insert(name, decl).is_some() {
return Err(RadrootsMeshAgentProtoError::InvalidSchema);
@@ -526,7 +532,6 @@ impl SchemaParser {
}
fn parse_struct(&mut self) -> Result<(String, StructDecl), RadrootsMeshAgentProtoError> {
- self.expect_ident_value("struct")?;
let name = self.expect_ident()?;
self.expect_symbol('{')?;
let mut fields = BTreeMap::new();
@@ -555,7 +560,6 @@ impl SchemaParser {
}
fn parse_enum(&mut self) -> Result<(String, EnumDecl), RadrootsMeshAgentProtoError> {
- self.expect_ident_value("enum")?;
let name = self.expect_ident()?;
self.expect_symbol('{')?;
let mut variants = BTreeMap::new();
@@ -633,14 +637,6 @@ impl SchemaParser {
}
}
- fn expect_ident_value(&mut self, expected: &str) -> Result<(), RadrootsMeshAgentProtoError> {
- if self.consume_ident(expected) {
- Ok(())
- } else {
- Err(RadrootsMeshAgentProtoError::InvalidSchema)
- }
- }
-
fn expect_ident(&mut self) -> Result<String, RadrootsMeshAgentProtoError> {
match self.peek().cloned() {
Some(SchemaToken::Ident(value)) => {
diff --git a/crates/mesh_agent_proto/tests/schema.rs b/crates/mesh_agent_proto/tests/schema.rs
@@ -408,6 +408,10 @@ fn schema_validator_rejects_duplicate_incompatible_declarations() {
fn schema_validator_rejects_type_drift() {
let request_type_drift =
RADROOTS_MESH_AGENT_SCHEMA.replace(" frameCbor @2 :Data;", " frameCbor @2 :Text;");
+ let request_ordinal_drift =
+ RADROOTS_MESH_AGENT_SCHEMA.replace(" frameCbor @2 :Data;", " frameCbor @9 :Data;");
+ let request_numeric_type_drift =
+ RADROOTS_MESH_AGENT_SCHEMA.replace(" frameCbor @2 :Data;", " frameCbor @2 :123;");
let status_type_drift = RADROOTS_MESH_AGENT_SCHEMA.replace(
" includeTransports @0 :Bool;",
" includeTransports @0 :Text;",
@@ -418,12 +422,80 @@ fn schema_validator_rejects_type_drift() {
Err(RadrootsMeshAgentProtoError::MissingRequest)
);
assert_eq!(
+ validate_schema_text(request_ordinal_drift.as_str()),
+ Err(RadrootsMeshAgentProtoError::MissingRequest)
+ );
+ assert_eq!(
+ validate_schema_text(request_numeric_type_drift.as_str()),
+ Err(RadrootsMeshAgentProtoError::MissingRequest)
+ );
+ assert_eq!(
validate_schema_text(status_type_drift.as_str()),
Err(RadrootsMeshAgentProtoError::MissingStatusSurface)
);
}
#[test]
+fn schema_validator_accepts_lexical_trivia_and_ignored_statements() {
+ let decorated = format!(
+ "# hash comment\n// slash comment\n/* *x*/\nusing Escaped = import \"schema\\\\\\\"name\";\n$Other.annotation(\"ignored\");\n;\n{RADROOTS_MESH_AGENT_SCHEMA}"
+ );
+
+ assert_eq!(validate_schema_text(decorated.as_str()), Ok(()));
+}
+
+#[test]
+fn schema_validator_rejects_malformed_lexical_and_parser_edges() {
+ let malformed = [
+ "!",
+ "/",
+ "/* unterminated",
+ "\"unterminated",
+ "\"trailing\\",
+ "using Alias",
+ "@;",
+ "@1",
+ "$Cxx.namespace(value);",
+ "struct",
+ "struct A",
+ "struct A { field @x :Text; }",
+ "struct A { field @0 Text; }",
+ "struct A { field @0 :; }",
+ "struct A { field @0 :Text",
+ "struct A { field @0 :\"Text\"; }",
+ "struct A { field @0 :@; }",
+ "enum A { value @0 }",
+ "enum A { value @65536; }",
+ "bogus",
+ "@1; @2;",
+ "$Cxx.namespace(\"a\"); $Cxx.namespace(\"b\");",
+ "struct A {} struct A {}",
+ "enum A {} enum A {}",
+ "enum A { first @0; second @0; }",
+ "enum A { first @0; first @1; }",
+ ];
+
+ for schema in malformed {
+ assert_eq!(
+ validate_schema_text(schema),
+ Err(RadrootsMeshAgentProtoError::InvalidSchema),
+ "{schema}"
+ );
+ }
+}
+
+#[test]
+fn schema_validator_ignores_non_namespace_annotations() {
+ for schema in ["#", "$Other;", "$Cxx;", "$Cxx.other;", "$Cxx.namespace;"] {
+ assert_eq!(
+ validate_schema_text(schema),
+ Err(RadrootsMeshAgentProtoError::MissingSchemaId),
+ "{schema}"
+ );
+ }
+}
+
+#[test]
fn mesh_agent_proto_errors_have_stable_display_strings() {
let cases = [
(