Deflate changed vault files from disk into redb. Scans the vault working copy, detects changes, and updates the database. Returns the list of paths that were updated. This is the inverse of `vault_materialize_all`. Together they form the inflate/deflate cycle: - `vault_materialize_all`: redb -> disk (for humans to read/edit) - `vault_record_working_copy`: disk -> redb (after humans edit)
(&self)
| 652 | /// - `vault_materialize_all`: redb -> disk (for humans to read/edit) |
| 653 | /// - `vault_record_working_copy`: disk -> redb (after humans edit) |
| 654 | pub fn vault_record_working_copy(&self) -> Result<Vec<String>, RepositoryError> { |
| 655 | let changes = self.vault_scan_working_copy()?; |
| 656 | |
| 657 | let mut updated_paths = Vec::new(); |
| 658 | |
| 659 | for change in &changes { |
| 660 | match change.change_type { |
| 661 | VaultChangeType::New | VaultChangeType::Modified => { |
| 662 | // Infer entry type from path |
| 663 | let entry_type = infer_entry_type(&change.path); |
| 664 | |
| 665 | // T5b record-time grant-lapse (gap #2): a raw on-disk |
| 666 | // substance edit to a `done` Draft intent reaches the vault |
| 667 | // through THIS path (not `vault_intent_update`), so apply the |
| 668 | // same demote-only lapse here. `record_time_lapse_frontmatter` |
| 669 | // is Intent-only, demote-only, and returns the demoted |
| 670 | // frontmatter iff a lapse applied; otherwise the incoming |
| 671 | // frontmatter is stored unchanged. Single store, no recursion. |
| 672 | let lapsed_fm = self.record_time_lapse_frontmatter(change, entry_type); |
| 673 | let frontmatter_json = lapsed_fm |
| 674 | .clone() |
| 675 | .unwrap_or_else(|| change.frontmatter_json.clone()); |
| 676 | |
| 677 | self.vault_store( |
| 678 | &change.path, |
| 679 | entry_type, |
| 680 | change.content.clone(), |
| 681 | frontmatter_json.clone(), |
| 682 | )?; |
| 683 | |
| 684 | // `vault_store` maintains only counts/merkle for Intent |
| 685 | // entries — it does not sync the IntentSummary status/pin, |
| 686 | // and the manifest summary is what `intent list` and triage |
| 687 | // read. |
| 688 | // |
| 689 | // This used to run only when a lapse rewrote the |
| 690 | // frontmatter, so an ordinary edit to an intent's `status:` |
| 691 | // landed in the entry and nowhere else: `intent show` |
| 692 | // reported the new status while `intent list` and every |
| 693 | // gate kept the stale one, forever. Mirror the effective |
| 694 | // frontmatter on every intent store — the lapse case is |
| 695 | // just the variant where `lapsed_fm` replaced it. |
| 696 | if entry_type == VaultEntryType::Intent { |
| 697 | self.sync_intent_summary_from_frontmatter(&change.path, &frontmatter_json)?; |
| 698 | } |
| 699 | |
| 700 | updated_paths.push(change.path.clone()); |
| 701 | } |
| 702 | VaultChangeType::Deleted => { |
| 703 | self.vault_delete(&change.path)?; |
| 704 | updated_paths.push(change.path.clone()); |
| 705 | } |
| 706 | } |
| 707 | } |
| 708 | |
| 709 | // Index any intent entries the manifest is missing — even when no |
| 710 | // file changed. Entries can predate this call (clone bootstrap |
| 711 | // deflates inherited files) and `update_manifest_for_store` leaves |