Result Aggregation and Validation
The result aggregator combines and validates corrections from multiple sources (pattern matching, different LLM models, etc.) to produce a final set of high-confidence corrections.
Core Implementation
defmodule Codexis.QualityChecker.ResultAggregator do
@moduledoc """
Aggregates and validates scanno detection results
"""
def aggregate_results(detection_results) do
detection_results
|> flatten_corrections()
|> remove_duplicates()
|> sort_by_position()
|> group_by_confidence()
|> validate_corrections()
end
defp flatten_corrections(results) do
results
|> Map.values()
|> List.flatten()
|> Enum.filter(&is_map/1)
end
defp remove_duplicates(corrections) do
corrections
|> Enum.uniq_by(fn c ->
{c["absolute_position"], c["original"], c["corrected"]}
end)
end
defp sort_by_position(corrections) do
Enum.sort_by(corrections, & &1["absolute_position"])
end
defp group_by_confidence(corrections) do
%{
high: Enum.filter(corrections, fn c -> c["confidence"] >= 0.9 end),
medium: Enum.filter(corrections, fn c ->
c["confidence"] >= 0.7 && c["confidence"] < 0.9
end),
low: Enum.filter(corrections, fn c ->
c["confidence"] >= 0.5 && c["confidence"] < 0.7
end)
}
end
defp validate_corrections(grouped_corrections) do
# Additional validation logic
grouped_corrections
|> validate_overlapping_corrections()
|> validate_context_consistency()
|> add_metadata()
end
defp validate_overlapping_corrections(grouped) do
# Check for overlapping corrections and resolve conflicts
Map.new(grouped, fn {confidence, corrections} ->
{confidence, resolve_overlaps(corrections)}
end)
end
defp resolve_overlaps(corrections) do
corrections
|> Enum.sort_by(& &1["absolute_position"])
|> Enum.reduce([], fn correction, acc ->
if overlaps_with_previous?(correction, List.last(acc)) do
resolve_overlap(List.last(acc), correction, acc)
else
acc ++ [correction]
end
end)
end
defp overlaps_with_previous?(current, nil), do: false
defp overlaps_with_previous?(current, previous) do
current_start = current["absolute_position"]
current_end = current_start + String.length(current["original"])
prev_end = previous["absolute_position"] + String.length(previous["original"])
current_start < prev_end
end
defp resolve_overlap(previous, current, acc) do
# Keep the correction with higher confidence
if current["confidence"] > previous["confidence"] do
List.replace_at(acc, -1, current)
else
acc
end
end
defp validate_context_consistency(grouped) do
# Ensure corrections make sense in context
grouped
end
defp add_metadata(grouped) do
timestamp = DateTime.utc_now()
Map.new(grouped, fn {confidence, corrections} ->
updated = Enum.map(corrections, fn c ->
Map.merge(c, %{
"validated_at" => timestamp,
"status" => "pending_review"
})
end)
{confidence, updated}
end)
end
end
Advanced Aggregation
defmodule Codexis.QualityChecker.AdvancedAggregator do
@moduledoc """
Advanced result aggregation with multi-source fusion
"""
def aggregate_multi_source(results_by_source) do
# Combine results from different sources (patterns, LLMs, etc.)
all_corrections = extract_all_corrections(results_by_source)
all_corrections
|> group_by_location()
|> fuse_corrections()
|> apply_confidence_weighting()
|> rank_corrections()
end
defp extract_all_corrections(results_by_source) do
Enum.flat_map(results_by_source, fn {source, results} ->
results
|> List.flatten()
|> Enum.map(fn correction ->
Map.put(correction, "source", source)
end)
end)
end
defp group_by_location(corrections) do
Enum.group_by(corrections, fn c ->
{c["absolute_position"], c["original"]}
end)
end
defp fuse_corrections(grouped) do
Enum.map(grouped, fn {{position, original}, group} ->
fused = %{
"absolute_position" => position,
"original" => original,
"corrections" => extract_unique_corrections(group),
"sources" => extract_sources(group),
"confidence" => calculate_fused_confidence(group)
}
select_best_correction(fused)
end)
end
defp extract_unique_corrections(group) do
group
|> Enum.map(& &1["corrected"])
|> Enum.uniq()
|> Enum.map(fn corrected ->
matching = Enum.filter(group, fn c -> c["corrected"] == corrected end)
%{
text: corrected,
count: length(matching),
sources: Enum.map(matching, & &1["source"]) |> Enum.uniq(),
avg_confidence: average_confidence(matching)
}
end)
end
defp extract_sources(group) do
group
|> Enum.map(& &1["source"])
|> Enum.uniq()
end
defp calculate_fused_confidence(group) do
source_weights = %{
"pattern" => 0.8,
"qwen3.0:8b" => 1.0,
"deepseek-r1:8b" => 1.1,
"human" => 1.5
}
weighted_sum = Enum.reduce(group, 0, fn correction, sum ->
weight = Map.get(source_weights, correction["source"], 1.0)
sum + (correction["confidence"] * weight)
end)
total_weight = Enum.reduce(group, 0, fn correction, sum ->
weight = Map.get(source_weights, correction["source"], 1.0)
sum + weight
end)
weighted_sum / total_weight
end
defp select_best_correction(fused) do
best = fused["corrections"]
|> Enum.max_by(fn c -> c.avg_confidence * :math.log(c.count + 1) end)
Map.merge(fused, %{
"corrected" => best.text,
"correction_confidence" => best.avg_confidence,
"support_count" => best.count
})
end
defp apply_confidence_weighting(corrections) do
corrections
|> Enum.map(fn correction ->
weight = calculate_weight(correction)
Map.put(correction, "weighted_confidence", correction["confidence"] * weight)
end)
end
defp calculate_weight(correction) do
source_weight = length(correction["sources"]) / 3.0
support_weight = correction["support_count"] / 5.0
min(1.5, 0.5 + source_weight + support_weight)
end
defp rank_corrections(corrections) do
corrections
|> Enum.sort_by(& &1["weighted_confidence"], :desc)
|> Enum.map(fn correction ->
Map.put(correction, "rank", determine_rank(correction))
end)
end
defp determine_rank(correction) do
cond do
correction["weighted_confidence"] >= 0.95 -> :critical
correction["weighted_confidence"] >= 0.85 -> :high
correction["weighted_confidence"] >= 0.70 -> :medium
true -> :low
end
end
defp average_confidence(corrections) do
confidences = Enum.map(corrections, & &1["confidence"])
Enum.sum(confidences) / length(confidences)
end
end
Validation Pipeline
defmodule Codexis.QualityChecker.ValidationPipeline do
@moduledoc """
Validates aggregated corrections through multiple checks
"""
def validate_corrections(corrections, original_text) do
corrections
|> validate_positions(original_text)
|> validate_replacements()
|> validate_context(original_text)
|> validate_language_consistency()
|> assign_final_scores()
end
defp validate_positions(corrections, original_text) do
text_length = String.length(original_text)
Enum.filter(corrections, fn correction ->
pos = correction["absolute_position"]
orig_length = String.length(correction["original"])
# Check if position is valid
pos >= 0 && pos + orig_length <= text_length &&
# Verify the original text matches at that position
String.slice(original_text, pos, orig_length) == correction["original"]
end)
end
defp validate_replacements(corrections) do
Enum.filter(corrections, fn correction ->
# Don't suggest replacing with the same text
correction["original"] != correction["corrected"] &&
# Ensure corrected text is not empty
String.trim(correction["corrected"]) != "" &&
# Check for reasonable length changes
length_ratio(correction) < 3.0
end)
end
defp length_ratio(correction) do
orig_len = String.length(correction["original"])
corr_len = String.length(correction["corrected"])
if orig_len == 0, do: corr_len, else: corr_len / orig_len
end
defp validate_context(corrections, original_text) do
Enum.map(corrections, fn correction ->
context_valid = check_context_validity(correction, original_text)
if context_valid do
correction
else
Map.update!(correction, "confidence", fn conf -> conf * 0.7 end)
end
end)
end
defp check_context_validity(correction, text) do
# Get surrounding context
pos = correction["absolute_position"]
before_text = String.slice(text, max(0, pos - 50), min(50, pos))
after_text = String.slice(text, pos + String.length(correction["original"]), 50)
# Basic context checks
!String.contains?(before_text <> after_text, correction["corrected"])
end
defp validate_language_consistency(corrections) do
corrections
end
defp assign_final_scores(corrections) do
Enum.map(corrections, fn correction ->
score = calculate_final_score(correction)
Map.put(correction, "final_score", score)
end)
end
defp calculate_final_score(correction) do
base_score = correction["confidence"]
# Adjust based on various factors
adjustments = [
source_adjustment(correction),
support_adjustment(correction),
pattern_adjustment(correction)
]
final_score = Enum.reduce(adjustments, base_score, fn adj, score ->
score * adj
end)
min(1.0, final_score)
end
defp source_adjustment(correction) do
case correction["sources"] do
sources when length(sources) >= 3 -> 1.2
sources when length(sources) == 2 -> 1.1
_ -> 1.0
end
end
defp support_adjustment(correction) do
case correction["support_count"] do
count when count >= 5 -> 1.15
count when count >= 3 -> 1.1
count when count >= 2 -> 1.05
_ -> 1.0
end
end
defp pattern_adjustment(correction) do
if Enum.member?(correction["sources"], "pattern"), do: 1.1, else: 1.0
end
end
Statistics and Reporting
defmodule Codexis.QualityChecker.CorrectionStats do
@moduledoc """
Generates statistics and reports for corrections
"""
def generate_report(corrections, original_text) do
%{
summary: generate_summary(corrections),
details: generate_details(corrections),
patterns: analyze_patterns(corrections),
confidence_distribution: analyze_confidence(corrections),
text_coverage: calculate_coverage(corrections, original_text)
}
end
defp generate_summary(corrections) do
total = length(corrections)
by_confidence = Enum.frequencies_by(corrections, & &1["rank"])
%{
total_corrections: total,
critical: Map.get(by_confidence, :critical, 0),
high: Map.get(by_confidence, :high, 0),
medium: Map.get(by_confidence, :medium, 0),
low: Map.get(by_confidence, :low, 0)
}
end
defp generate_details(corrections) do
corrections
|> Enum.group_by(& &1["rank"])
|> Map.new(fn {rank, items} ->
{rank, Enum.map(items, &format_correction/1)}
end)
end
defp format_correction(correction) do
%{
position: correction["absolute_position"],
original: correction["original"],
corrected: correction["corrected"],
confidence: correction["confidence"],
sources: correction["sources"]
}
end
defp analyze_patterns(corrections) do
corrections
|> Enum.group_by(fn c -> {c["original"], c["corrected"]} end)
|> Enum.map(fn {{orig, corr}, group} ->
%{
pattern: "#{orig} → #{corr}",
count: length(group),
avg_confidence: average_confidence(group)
}
end)
|> Enum.sort_by(& &1.count, :desc)
|> Enum.take(20)
end
defp analyze_confidence(corrections) do
%{
mean: mean_confidence(corrections),
median: median_confidence(corrections),
std_dev: std_dev_confidence(corrections),
distribution: confidence_histogram(corrections)
}
end
defp calculate_coverage(corrections, original_text) do
total_chars = String.length(original_text)
corrected_chars = corrections
|> Enum.map(fn c -> String.length(c["original"]) end)
|> Enum.sum()
%{
total_characters: total_chars,
corrected_characters: corrected_chars,
coverage_percentage: (corrected_chars / total_chars) * 100
}
end
defp average_confidence(corrections) do
confidences = Enum.map(corrections, & &1["confidence"])
if Enum.empty?(confidences), do: 0, else: Enum.sum(confidences) / length(confidences)
end
defp mean_confidence(corrections) do
average_confidence(corrections)
end
defp median_confidence(corrections) do
confidences = Enum.map(corrections, & &1["confidence"]) |> Enum.sort()
if Enum.empty?(confidences) do
0
else
mid = div(length(confidences), 2)
if rem(length(confidences), 2) == 0 do
(Enum.at(confidences, mid - 1) + Enum.at(confidences, mid)) / 2
else
Enum.at(confidences, mid)
end
end
end
defp std_dev_confidence(corrections) do
confidences = Enum.map(corrections, & &1["confidence"])
mean = mean_confidence(corrections)
if length(confidences) < 2 do
0
else
variance = Enum.map(confidences, fn c -> :math.pow(c - mean, 2) end)
|> Enum.sum()
|> Kernel./(length(confidences) - 1)
:math.sqrt(variance)
end
end
defp confidence_histogram(corrections) do
confidences = Enum.map(corrections, & &1["confidence"])
# Create 10 bins from 0.0 to 1.0
bins = Enum.map(0..9, fn i -> i / 10.0 end)
Enum.map(bins, fn bin_start ->
bin_end = bin_start + 0.1
count = Enum.count(confidences, fn c ->
c >= bin_start && c < bin_end
end)
%{
range: "#{bin_start}-#{bin_end}",
count: count
}
end)
end
end
Export and Serialization
defmodule Codexis.QualityChecker.ResultExporter do
@moduledoc """
Exports aggregated results to various formats
"""
def export_json(results, path) do
json_data = prepare_for_json(results)
case Jason.encode(json_data, pretty: true) do
{:ok, encoded} -> File.write(path, encoded)
{:error, reason} -> {:error, reason}
end
end
def export_csv(results, path) do
csv_data = prepare_for_csv(results)
headers = ["Position", "Original", "Corrected", "Confidence", "Sources", "Rank"]
rows = Enum.map(csv_data, fn row ->
[
row.position,
row.original,
row.corrected,
row.confidence,
Enum.join(row.sources, ";"),
row.rank
]
end)
csv_content = [headers | rows]
|> CSV.encode()
|> Enum.join()
File.write(path, csv_content)
end
def export_html_report(results, stats, path) do
html_content = generate_html_report(results, stats)
File.write(path, html_content)
end
defp prepare_for_json(results) do
results
|> Map.new(fn {confidence_level, corrections} ->
{confidence_level, Enum.map(corrections, &clean_for_json/1)}
end)
end
defp clean_for_json(correction) do
correction
|> Map.drop(["validated_at"]) # Remove datetime objects
|> Map.update("confidence", 0, &Float.round(&1, 3))
end
defp prepare_for_csv(results) do
results
|> Map.values()
|> List.flatten()
|> Enum.map(fn correction ->
%{
position: correction["absolute_position"],
original: correction["original"],
corrected: correction["corrected"],
confidence: Float.round(correction["confidence"], 3),
sources: correction["sources"] || [],
rank: correction["rank"] || :unknown
}
end)
end
defp generate_html_report(results, stats) do
"""
<!DOCTYPE html>
<html>
<head>
<title>Scanno Detection Report</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.summary { background: #f0f0f0; padding: 20px; margin-bottom: 30px; }
.correction { margin: 10px 0; padding: 10px; border: 1px solid #ddd; }
.high { border-left: 5px solid #ff4444; }
.medium { border-left: 5px solid #ffaa00; }
.low { border-left: 5px solid #44ff44; }
.original { color: #cc0000; }
.corrected { color: #00cc00; }
</style>
</head>
<body>
<h1>Scanno Detection Report</h1>
<div class="summary">
<h2>Summary</h2>
<p>Total corrections: #{stats.summary.total_corrections}</p>
<p>Critical: #{stats.summary.critical}</p>
<p>High: #{stats.summary.high}</p>
<p>Medium: #{stats.summary.medium}</p>
<p>Low: #{stats.summary.low}</p>
</div>
<h2>Corrections</h2>
#{generate_corrections_html(results)}
<h2>Common Patterns</h2>
#{generate_patterns_html(stats.patterns)}
</body>
</html>
"""
end
defp generate_corrections_html(results) do
results
|> Map.to_list()
|> Enum.sort()
|> Enum.map(fn {rank, corrections} ->
"""
<h3>#{rank |> to_string() |> String.capitalize()} Priority</h3>
#{Enum.map(corrections, &correction_to_html/1) |> Enum.join("\n")}
"""
end)
|> Enum.join("\n")
end
defp correction_to_html(correction) do
"""
<div class="correction #{correction["rank"]}">
<p>Position: #{correction["absolute_position"]}</p>
<p><span class="original">#{correction["original"]}</span> →
<span class="corrected">#{correction["corrected"]}</span></p>
<p>Confidence: #{Float.round(correction["confidence"], 2)}</p>
<p>Sources: #{Enum.join(correction["sources"] || [], ", ")}</p>
</div>
"""
end
defp generate_patterns_html(patterns) do
patterns
|> Enum.map(fn pattern ->
"""
<p>#{pattern.pattern} (#{pattern.count} occurrences,
#{Float.round(pattern.avg_confidence, 2)} confidence)</p>
"""
end)
|> Enum.join("\n")
end
end