package infra import "sort" // VaultFileChange holds the before/after state of a file whose content changed. type VaultFileChange struct { RelPath string Prev VaultFile Curr VaultFile } // VaultDiffReport is the result of comparing two VaultFile slices. type VaultDiffReport struct { Added []VaultFile // in curr but not in prev (by rel_path) Removed []VaultFile // in prev but not in curr Changed []VaultFileChange // same rel_path, different sha256 Unchanged int // files present in both with identical sha256 } // VaultDiff computes the difference between two vault snapshots. // It indexes both slices by RelPath, then classifies each entry as // Added, Removed, Changed, or Unchanged. All output slices are sorted // by RelPath ascending. The function is pure and deterministic. func VaultDiff(prev, curr []VaultFile) VaultDiffReport { prevMap := make(map[string]VaultFile, len(prev)) for _, f := range prev { prevMap[f.RelPath] = f } currMap := make(map[string]VaultFile, len(curr)) for _, f := range curr { currMap[f.RelPath] = f } var report VaultDiffReport for _, f := range curr { p, exists := prevMap[f.RelPath] if !exists { report.Added = append(report.Added, f) } else if p.Sha256 != f.Sha256 { report.Changed = append(report.Changed, VaultFileChange{ RelPath: f.RelPath, Prev: p, Curr: f, }) } else { report.Unchanged++ } } for _, f := range prev { if _, exists := currMap[f.RelPath]; !exists { report.Removed = append(report.Removed, f) } } sort.Slice(report.Added, func(i, j int) bool { return report.Added[i].RelPath < report.Added[j].RelPath }) sort.Slice(report.Removed, func(i, j int) bool { return report.Removed[i].RelPath < report.Removed[j].RelPath }) sort.Slice(report.Changed, func(i, j int) bool { return report.Changed[i].RelPath < report.Changed[j].RelPath }) return report }