Declaratively apply a [`ViewManifest`]: create the view with its declared identity if absent, then fast-forward its change log to match the manifest. # Semantics Everything is validated **before** any write: 1. The manifest's declared state must equal the fold of its log. 2. Every referenced change file must be present in the local store. 3. Every dependency of every change must appear earlier
(
&mut self,
manifest: &ViewManifest,
)
| 744 | /// resumes where it stopped. After replay the view's merkle state is |
| 745 | /// verified against the declared state. |
| 746 | pub fn apply_view_manifest( |
| 747 | &mut self, |
| 748 | manifest: &ViewManifest, |
| 749 | ) -> Result<ManifestApplyOutcome, RepositoryError> { |
| 750 | // 1. Structural integrity: declared state == fold of the log. |
| 751 | manifest.verify()?; |
| 752 | |
| 753 | // 2. Presence: every change file must exist locally. |
| 754 | let missing: Vec<&Hash> = manifest |
| 755 | .changes |
| 756 | .iter() |
| 757 | .filter(|h| !self.has_change(h)) |
| 758 | .collect(); |
| 759 | if let Some(first) = missing.first() { |
| 760 | return Err(RepositoryError::ManifestMissingChanges { |
| 761 | view: manifest.name.clone(), |
| 762 | count: missing.len(), |
| 763 | first: first.to_base32(), |
| 764 | }); |
| 765 | } |
| 766 | |
| 767 | // 3. Dependency closure: deps must be earlier in the log or already |
| 768 | // applied locally. Read from the change files (self-contained DAG). |
| 769 | { |
| 770 | let txn = self |
| 771 | .pristine |
| 772 | .read_txn() |
| 773 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 774 | let mut seen: HashSet<Hash> = HashSet::with_capacity(manifest.changes.len()); |
| 775 | for hash in &manifest.changes { |
| 776 | let change = self.load_change(hash)?; |
| 777 | for dep in change.dependencies() { |
| 778 | if seen.contains(dep) { |
| 779 | continue; |
| 780 | } |
| 781 | let applied = txn |
| 782 | .get_internal(dep) |
| 783 | .map_err(|e| RepositoryError::Database(e.to_string()))? |
| 784 | .is_some(); |
| 785 | if !applied { |
| 786 | return Err(RepositoryError::ManifestDependencyMissing { |
| 787 | view: manifest.name.clone(), |
| 788 | change: hash.to_base32(), |
| 789 | dependency: dep.to_base32(), |
| 790 | }); |
| 791 | } |
| 792 | } |
| 793 | seen.insert(*hash); |
| 794 | } |
| 795 | } |
| 796 | |
| 797 | // 4. Identity + prefix rule against the existing view (if any). |
| 798 | let prefix_len = { |
| 799 | let txn = self |
| 800 | .pristine |
| 801 | .read_txn() |
| 802 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 803 | match txn |