@@ -87,17 +87,21 @@ describe("sql_quality event shape", () => {
8787// 3. Finding extraction patterns (validates what tools produce)
8888// ---------------------------------------------------------------------------
8989describe ( "tool finding extraction patterns" , ( ) => {
90- test ( "sql_analyze issues map to findings via issue. type" , ( ) => {
91- // issue.type is coarse: "lint", "semantic", " safety"
90+ test ( "sql_analyze issues use rule for lint, fall back to type otherwise " , ( ) => {
91+ // Lint issues have rule (e.g. "select_star"), semantic/ safety don't
9292 const issues = [
93- { type : "lint" , severity : "warning" , message : "..." , recommendation : "..." , confidence : "high" } ,
93+ { type : "lint" , rule : "select_star" , severity : "warning" , message : "..." , recommendation : "..." , confidence : "high" } ,
94+ { type : "lint" , rule : "filter_has_func" , severity : "warning" , message : "..." , recommendation : "..." , confidence : "high" } ,
95+ { type : "semantic" , severity : "warning" , message : "..." , recommendation : "..." , confidence : "medium" } ,
9496 { type : "safety" , severity : "high" , message : "..." , recommendation : "..." , confidence : "high" } ,
9597 ]
96- const findings : Telemetry . Finding [ ] = issues . map ( ( i ) => ( {
97- category : i . type ,
98+ const findings : Telemetry . Finding [ ] = issues . map ( ( i : any ) => ( {
99+ category : i . rule ?? i . type ,
98100 } ) )
99101 expect ( findings ) . toEqual ( [
100- { category : "lint" } ,
102+ { category : "select_star" } ,
103+ { category : "filter_has_func" } ,
104+ { category : "semantic" } ,
101105 { category : "safety" } ,
102106 ] )
103107 } )
@@ -195,6 +199,111 @@ describe("tool finding extraction patterns", () => {
195199 const by_category = Telemetry . aggregateFindings ( findings )
196200 expect ( by_category ) . toEqual ( { correction_applied : 2 } )
197201 } )
202+
203+ test ( "check tool aggregates validation, lint, safety, and pii findings" , ( ) => {
204+ const data = {
205+ validation : { valid : false , errors : [ { message : "syntax error" } ] } ,
206+ lint : { clean : false , findings : [ { rule : "select_star" , severity : "warning" , message : "..." } , { rule : "filter_has_func" , severity : "warning" , message : "..." } ] } ,
207+ safety : { safe : false , threats : [ { type : "sql_injection" , severity : "high" , description : "..." } ] } ,
208+ pii : { findings : [ { column : "email" , category : "email" , confidence : "high" } ] } ,
209+ }
210+ const findings : Telemetry . Finding [ ] = [ ]
211+ for ( const _ of data . validation . errors ) findings . push ( { category : "validation_error" } )
212+ for ( const f of data . lint . findings ) findings . push ( { category : f . rule ?? "lint" } )
213+ for ( const t of data . safety . threats ) findings . push ( { category : ( t as any ) . type ?? "safety_threat" } )
214+ for ( const _ of data . pii . findings ) findings . push ( { category : "pii_detected" } )
215+ const by_category = Telemetry . aggregateFindings ( findings )
216+ expect ( by_category ) . toEqual ( {
217+ validation_error : 1 ,
218+ select_star : 1 ,
219+ filter_has_func : 1 ,
220+ sql_injection : 1 ,
221+ pii_detected : 1 ,
222+ } )
223+ } )
224+
225+ test ( "policy violations use rule as category" , ( ) => {
226+ const data = {
227+ pass : false ,
228+ violations : [
229+ { rule : "no_select_star" , severity : "error" , message : "..." } ,
230+ { rule : "require_where" , severity : "error" , message : "..." } ,
231+ { severity : "warning" , message : "..." } , // no rule
232+ ] ,
233+ }
234+ const findings : Telemetry . Finding [ ] = data . violations . map ( ( v : any ) => ( {
235+ category : v . rule ?? "policy_violation" ,
236+ } ) )
237+ const by_category = Telemetry . aggregateFindings ( findings )
238+ expect ( by_category ) . toEqual ( {
239+ no_select_star : 1 ,
240+ require_where : 1 ,
241+ policy_violation : 1 ,
242+ } )
243+ } )
244+
245+ test ( "schema diff uses change_type as category" , ( ) => {
246+ const changes = [
247+ { severity : "breaking" , change_type : "column_dropped" , message : "..." } ,
248+ { severity : "warning" , change_type : "type_changed" , message : "..." } ,
249+ { severity : "info" , change_type : "column_added" , message : "..." } ,
250+ { severity : "breaking" , change_type : "column_dropped" , message : "..." } ,
251+ ]
252+ const findings : Telemetry . Finding [ ] = changes . map ( ( c ) => ( {
253+ category : c . change_type ?? ( c . severity === "breaking" ? "breaking_change" : "schema_change" ) ,
254+ } ) )
255+ const by_category = Telemetry . aggregateFindings ( findings )
256+ expect ( by_category ) . toEqual ( {
257+ column_dropped : 2 ,
258+ type_changed : 1 ,
259+ column_added : 1 ,
260+ } )
261+ } )
262+
263+ test ( "optimize tool combines anti-patterns and suggestions" , ( ) => {
264+ const result = {
265+ anti_patterns : [
266+ { type : "cartesian_product" , severity : "error" , message : "..." } ,
267+ { type : "select_star" , severity : "warning" , message : "..." } ,
268+ ] ,
269+ suggestions : [
270+ { type : "cte_elimination" , impact : "high" , description : "..." } ,
271+ ] ,
272+ }
273+ const findings : Telemetry . Finding [ ] = [
274+ ...result . anti_patterns . map ( ( ap ) => ( { category : ap . type ?? "anti_pattern" } ) ) ,
275+ ...result . suggestions . map ( ( s ) => ( { category : s . type ?? "optimization_suggestion" } ) ) ,
276+ ]
277+ const by_category = Telemetry . aggregateFindings ( findings )
278+ expect ( by_category ) . toEqual ( {
279+ cartesian_product : 1 ,
280+ select_star : 1 ,
281+ cte_elimination : 1 ,
282+ } )
283+ } )
284+
285+ test ( "impact analysis produces findings only when downstream affected" , ( ) => {
286+ // No impact — no findings
287+ const safeFindings : Telemetry . Finding [ ] = [ ]
288+ expect ( safeFindings ) . toEqual ( [ ] )
289+
290+ // High impact — findings per dependent
291+ const findings : Telemetry . Finding [ ] = [ ]
292+ const direct = [ { name : "model_a" } , { name : "model_b" } ]
293+ const transitive = [ { name : "model_c" } ]
294+ const totalAffected = direct . length + transitive . length
295+ if ( totalAffected > 0 ) {
296+ findings . push ( { category : "impact_medium" } )
297+ for ( const _ of direct ) findings . push ( { category : "impact_direct_dependent" } )
298+ for ( const _ of transitive ) findings . push ( { category : "impact_transitive_dependent" } )
299+ }
300+ const by_category = Telemetry . aggregateFindings ( findings )
301+ expect ( by_category ) . toEqual ( {
302+ impact_medium : 1 ,
303+ impact_direct_dependent : 2 ,
304+ impact_transitive_dependent : 1 ,
305+ } )
306+ } )
198307} )
199308
200309// ---------------------------------------------------------------------------
0 commit comments