@@ -83,6 +83,31 @@ def test_committed_sample_candidates_have_three_audit_cited_examples():
8383 )
8484
8585
86+ def test_candidates_carry_affected_line_counts ():
87+ contents = {1 : "event a" , 2 : "event b" , 3 : "event c" }
88+ records = []
89+ rows = []
90+ for i in range (1 , 13 ):
91+ content = contents .get (i , "event a" )
92+ decision = "matched" if i == 2 else "new_cluster"
93+ records .append (
94+ {
95+ "line" : i ,
96+ "cluster" : "T1" ,
97+ "decision" : decision ,
98+ "similarity" : 0.5 if i == 2 else 0.0 ,
99+ "template" : "event <*>" ,
100+ }
101+ )
102+ rows .append (row (i , "T1" , "event <*>" , content ))
103+
104+ (candidate ,) = select_candidates (records , rows )
105+
106+ assert candidate .kind == "low_confidence"
107+ assert candidate .target_line == 2
108+ assert candidate .affected_lines == 12
109+
110+
86111def test_candidates_without_three_examples_are_not_sent ():
87112 records = [
88113 {
@@ -345,5 +370,97 @@ def test_apply_decisions_rejects_unequal_length_merge():
345370 apply_decisions (source , [{"change" : "merge" , "cluster_ids" : ["T1" , "T2" ]}])
346371
347372
373+ def test_big_split_is_held_for_human_review ():
374+ candidate = Candidate (
375+ kind = "low_confidence" ,
376+ cluster_ids = ("T3" ,),
377+ cited_audit_lines = (18 , 3 , 21 ),
378+ examples = ("target" , "peer one" , "peer two" ),
379+ templates = ("event <*>" ,),
380+ similarity = 0.5 ,
381+ target_line = 18 ,
382+ affected_lines = 410 ,
383+ )
384+ assert decide (candidate , "TWO" ) == (
385+ "needs-human" ,
386+ "none" ,
387+ "split of 410 lines in T3 held for human review" ,
388+ )
389+
390+
391+ def test_big_merge_is_held_for_human_review ():
392+ candidate = Candidate (
393+ kind = "near_duplicate" ,
394+ cluster_ids = ("T7" , "T11" ),
395+ cited_audit_lines = (7 , 15 , 10 ),
396+ examples = ("event a" , "event b" , "event c" ),
397+ templates = ("event <*>" , "event <*>" ),
398+ similarity = None ,
399+ target_line = None ,
400+ affected_lines = 160 ,
401+ )
402+ assert decide (candidate , "SAME" ) == (
403+ "needs-human" ,
404+ "none" ,
405+ "merge of 160 lines in T7,T11 held for human review" ,
406+ )
407+
408+
409+ def test_small_accepts_still_apply ():
410+ split = Candidate (
411+ kind = "low_confidence" ,
412+ cluster_ids = ("T1" ,),
413+ cited_audit_lines = (2 , 1 , 3 ),
414+ examples = ("target" , "peer one" , "peer two" ),
415+ templates = ("event <*>" ,),
416+ similarity = 0.5 ,
417+ target_line = 2 ,
418+ affected_lines = 3 ,
419+ )
420+ assert decide (split , "TWO" ) == ("accept" , "split" , "model said TWO" )
421+ merge = Candidate (
422+ kind = "near_duplicate" ,
423+ cluster_ids = ("T1" , "T2" ),
424+ cited_audit_lines = (1 , 2 , 3 ),
425+ examples = ("event a" , "event b" , "event c" ),
426+ templates = ("event <*>" , "event <*>" ),
427+ similarity = None ,
428+ target_line = None ,
429+ affected_lines = 6 ,
430+ )
431+ assert decide (merge , "SAME" ) == ("accept" , "merge" , "model said SAME" )
432+
433+
434+ def test_needs_human_records_are_not_materialized ():
435+ source = [
436+ row (1 , "T1" , "event <*>" , "event a" ),
437+ row (2 , "T1" , "event <*>" , "event b" ),
438+ row (3 , "T2" , "event <*>" , "event c" ),
439+ ]
440+ reviews = [
441+ {
442+ "decision" : "needs-human" ,
443+ "change" : "none" ,
444+ "target_line" : 2 ,
445+ "cluster_ids" : ["T1" ],
446+ },
447+ {
448+ "decision" : "needs-human" ,
449+ "change" : "none" ,
450+ "target_line" : None ,
451+ "cluster_ids" : ["T1" , "T2" ],
452+ },
453+ ]
454+
455+ assisted = apply_decisions (source , reviews )
456+
457+ assert [item ["EventId" ] for item in assisted ] == ["T1" , "T1" , "T2" ]
458+ assert [item ["EventTemplate" ] for item in assisted ] == [
459+ "event <*>" ,
460+ "event <*>" ,
461+ "event <*>" ,
462+ ]
463+
464+
348465def test_apply_decisions_accepts_empty_parse ():
349466 assert apply_decisions ([], []) == []
0 commit comments