Artifact 12719601fde6aae437da2caa64a925ba990bd65106e03592dc7a05d6b35ca4a6:
- File
internal/verify/verify.go
— part of check-in
[cd98ba38cb]
at
2026-10-20 00:25:58
on branch feat/submanifest-reader
— feat(manifest,verify): commit over a sparse store, and count absences
A commit over a store with a store cone leaves out the R card (draft-fossil-sparse-cone-00 §4.3). It refers to out-of-cone files the store lacks by hash alone (§5.3). VerifyRCard skips over a sparse store, and skips a manifest that has no R card, since an absent R card is not damage.
verify.Report gains Phantoms (transit) and Elided. Neither is an Issue, so a store complete within its cone verifies OK (§5.2). Rebuild keeps the store cone and reports the same counts. (user: [email protected], size: 3550) [annotate] [blame] [check-ins using] [more...]
// Package verify provides comprehensive repository verification and rebuild. package verify import ( "fmt" "time" "github.com/danmestas/go-libfossil/internal/content" libfossil "github.com/danmestas/go-libfossil/internal/fsltype" "github.com/danmestas/go-libfossil/internal/repo" ) // IssueKind categorizes the type of verification issue found. type IssueKind int const ( IssueHashMismatch IssueKind = iota IssueBlobCorrupt IssueDeltaDangling IssuePhantomOrphan IssueEventMissing IssueEventMismatch IssueMlinkMissing IssuePlinkMissing IssueTagxrefMissing IssueFilenameMissing IssueLeafIncorrect IssueMissingReference ) // Issue represents a single verification problem found in the repository. type Issue struct { Kind IssueKind RID libfossil.FslID UUID string Table string Message string } // Report contains the results of a repository verification pass. type Report struct { Issues []Issue BlobsChecked int BlobsOK int BlobsFailed int BlobsSkipped int MissingRefs int // Phantoms counts the artifacts the store names but lacks and still // wants: transit phantoms, which synchronization requests. Shunned and // elided artifacts are not among them. Phantoms int // Elided counts the artifacts deliberately absent under the store cone // (draft-fossil-sparse-cone-00 §5.2). Elision is healthy: it is never an // Issue, so a store complete within its cone verifies OK, and it is // counted apart from damage and from Phantoms so that neither hides the // other. It is zero for a dense store. Elided int TablesRebuilt []string Duration time.Duration } // OK returns true if no issues were found during verification. func (r *Report) OK() bool { return len(r.Issues) == 0 } // addIssue appends a new issue to the report. func (r *Report) addIssue(issue Issue) { r.Issues = append(r.Issues, issue) } // Verify performs comprehensive repository verification. // It checks blob integrity, delta chains, phantom records, and derived tables, // and counts what the store lacks by absence class. // Returns a report of all issues found. Never stops early - reports all problems. func Verify(r *repo.Repo) (*Report, error) { if r == nil { panic("verify: nil repo") } start := time.Now() report := &Report{} // Phase 1: Blob integrity (content hash verification) if err := checkBlobs(r, report); err != nil { return nil, err } // Phase 2: Structural integrity (delta chains, phantoms) if err := checkDeltaChains(r, report); err != nil { return nil, err } if err := checkPhantoms(r, report); err != nil { return nil, err } // Phase 3: Derived tables (event, mlink, plink, tagxref, filename, leaf) if err := checkDerived(r, report); err != nil { return nil, err } // Phase 4: what the store lacks, by absence class. if err := countAbsences(r, report); err != nil { return nil, err } report.Duration = time.Since(start) return report, nil } // countAbsences fills Phantoms and Elided from the store's phantoms, // classified against its store cone. It runs after the derived-table checks // because elision is read from mlink, a derived table. func countAbsences(r *repo.Repo, report *Report) error { if r == nil { panic("verify.countAbsences: nil *repo.Repo") } if report == nil { panic("verify.countAbsences: nil *Report") } a, err := content.LoadAbsences(r.DB()) if err != nil { return fmt.Errorf("verify: %w", err) } report.Phantoms = a.Count(content.Transit) report.Elided = a.Count(content.Elided) return nil }