From 8a0df1d305aa1c108be0d679eb1e32731091579c Mon Sep 17 00:00:00 2001 From: Ragnor Comerford Date: Sat, 30 May 2026 21:59:54 +0200 Subject: [PATCH] Resolve param types structurally in the MCP vector lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The exposed-query advisory detected vector params with type_name.starts_with("Vector(") — a second copy of the compiler's own ScalarType::from_str_name vector parsing that could drift from it. Key the lint off PropType::from_param_type_name + ScalarType::Vector(_) instead, the one canonical resolver the type system already uses. Any future param-suppliability lint now reads the structured type rather than scanning the surface string. Behavior-preserving: the grammar forbids list-of-vector params (list_type = "[" base_type "]", and base_type excludes Vector), so the only input where the structured and string checks could differ is unparseable. Adds a guard test that an exposed String param does not false-trigger the warning. --- crates/omnigraph-server/src/queries.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/crates/omnigraph-server/src/queries.rs b/crates/omnigraph-server/src/queries.rs index 26fe19e..075a104 100644 --- a/crates/omnigraph-server/src/queries.rs +++ b/crates/omnigraph-server/src/queries.rs @@ -20,6 +20,7 @@ use omnigraph_compiler::catalog::Catalog; use omnigraph_compiler::query::ast::QueryDecl; use omnigraph_compiler::query::parser::parse_query; use omnigraph_compiler::query::typecheck::typecheck_query_decl; +use omnigraph_compiler::types::{PropType, ScalarType}; use crate::config::{OmnigraphConfig, QueryEntry}; @@ -250,7 +251,13 @@ pub fn check(registry: &QueryRegistry, catalog: &Catalog) -> CheckReport { } if query.expose { for param in &query.decl.params { - if param.type_name.starts_with("Vector(") { + // Resolve to the structured type via the compiler's own + // resolver rather than string-matching `Vector(` — one + // canonical definition of "is a vector", so this lint can't + // drift from how the parser/type system spells the type. + let is_vector = PropType::from_param_type_name(¶m.type_name, param.nullable) + .is_some_and(|pt| matches!(pt.scalar, ScalarType::Vector(_))); + if is_vector { report.warnings.push(Warning { query: query.name.clone(), message: format!( @@ -454,4 +461,20 @@ embedding: Vector(4) let report = check(®, &test_catalog()); assert!(report.is_clean(), "unexpected: {:?}", report); } + + #[test] + fn non_vector_param_on_exposed_query_does_not_warn() { + // The recommended `String` alternative on an exposed query does not + // resolve to a Vector, so the embedding advisory stays silent. Guards + // the structured type check against a false positive (and pins that + // only `Vector(_)` triggers the warning). + let reg = QueryRegistry::from_specs(vec![spec( + "search", + "query search($name: String) { match { $u: User { name: $name } } return { $u.name } }", + true, + )]) + .unwrap(); + let report = check(®, &test_catalog()); + assert!(report.is_clean(), "no breakage or warning expected: {:?}", report); + } }