use std::fmt::Write as _;
use super::attest::{Attestation, Verdict};
use super::schema::{ObjectKind, SchemaSnapshot};
use super::text_columns::TextClass;
fn class_marker(class: Option<TextClass>) -> &'static str {
match class {
Some(TextClass::FreeText) => " ← FREE TEXT",
Some(TextClass::EmbeddedPayload) => " ← EMBEDDED PAYLOAD",
Some(TextClass::Unclassified) => " ← UNCLASSIFIED TEXT",
Some(TextClass::Constrained) | None => "",
}
}
pub fn schema_report(snapshot: &SchemaSnapshot) -> String {
let mut out = String::new();
let version = snapshot.schema_version.map_or_else(
|| "unknown (no schema_migrations table)".to_string(),
|v| v.to_string(),
);
let _ = writeln!(out, "tga database schema — migration version {version}");
let _ = writeln!(out);
for object in &snapshot.objects {
match object.kind {
ObjectKind::Table => {
let rows = object.row_count.unwrap_or(0);
let _ = writeln!(
out,
"TABLE {} ({} column(s), {rows} row(s))",
object.name,
object.columns.len()
);
}
ObjectKind::View => {
let _ = writeln!(
out,
"VIEW {} ({} column(s))",
object.name,
object.columns.len()
);
}
}
for column in &object.columns {
let declared = if column.declared_type.is_empty() {
"(untyped)"
} else {
&column.declared_type
};
let pk = if column.pk_position > 0 { " PK" } else { "" };
let not_null = if column.not_null { " NOT NULL" } else { "" };
let _ = writeln!(
out,
" {:<28} {declared}{pk}{not_null}{}",
column.name,
class_marker(column.text_class)
);
}
let _ = writeln!(out);
}
let flagged: Vec<_> = snapshot
.text_columns()
.into_iter()
.filter(|(_, c)| c.text_class.is_some_and(TextClass::is_scanned))
.collect();
let _ = writeln!(out, "Free-text and payload columns ({}):", flagged.len());
for (table, column) in flagged {
let _ = writeln!(
out,
" {}.{}{}",
table.name,
column.name,
class_marker(column.text_class)
);
}
out
}
pub fn attestation_report(attestation: &Attestation) -> String {
let mut out = String::new();
let _ = writeln!(out, "{}", attestation.claim);
let _ = writeln!(out);
let _ = writeln!(out, "{}", attestation.caveat);
let _ = writeln!(out);
let version = attestation
.schema_version
.map_or_else(|| "unknown".to_string(), |v| v.to_string());
let _ = writeln!(
out,
"Scanned {} table(s) at migration version {version}.",
attestation.tables_scanned
);
let _ = writeln!(out);
let _ = writeln!(out, "Content-bearing columns");
if attestation.content_columns.is_empty() {
let _ = writeln!(
out,
" none — no BLOB column, and no column named for a diff, patch, hunk, or file body."
);
} else {
for finding in &attestation.content_columns {
let _ = writeln!(
out,
" {}.{} ({}) — {}",
finding.table, finding.column, finding.declared_type, finding.reason
);
}
}
let _ = writeln!(out);
let _ = writeln!(
out,
"Free-text columns, as they stand in this database\n \
{:<44} {:>10} {:>10} {:>9} CLASS",
"COLUMN", "POPULATED", "MAX BYTES", "DIFFS"
);
for scan in &attestation.scanned_columns {
let class = match scan.class {
TextClass::FreeText => "free text",
TextClass::EmbeddedPayload => "embedded payload",
TextClass::Unclassified => "UNCLASSIFIED",
TextClass::Constrained => "constrained",
};
let _ = writeln!(
out,
" {:<44} {:>10} {:>10} {:>9} {class}",
format!("{}.{}", scan.table, scan.column),
scan.populated,
scan.max_len,
scan.diff_shaped_rows
);
}
let _ = writeln!(
out,
" DIFFS counts rows carrying a unified-diff marker. Any non-zero value \
contradicts the claim above."
);
let _ = writeln!(out);
let _ = writeln!(
out,
"Callers of collect::git::diff::diff_for_commit ({})",
attestation.diff_text_consumers.len()
);
for consumer in attestation.diff_text_consumers {
let _ = writeln!(
out,
" {} — {}",
consumer.source_path, consumer.disposition
);
}
let _ = writeln!(
out,
" This list is pinned in source and re-derived from the source tree by \
`cargo test -p tga`, so a new caller fails the build rather than passing unnoticed."
);
let _ = writeln!(out);
let _ = match attestation.verdict {
Verdict::Consistent => writeln!(
out,
"VERDICT: consistent — the claim holds for this database."
),
Verdict::Findings => writeln!(
out,
"VERDICT: findings — review the rows above before quoting the claim."
),
};
out
}