Skip to content

feat(storage): Vault Doctor — health check and conflict repair#832

Merged
antonreshetov merged 17 commits into
mainfrom
feat/vault-doctor
Jun 15, 2026
Merged

feat(storage): Vault Doctor — health check and conflict repair#832
antonreshetov merged 17 commits into
mainfrom
feat/vault-doctor

Conversation

@antonreshetov

Copy link
Copy Markdown
Member

Что это

Vault Doctor — maintenance-функция в Preferences → Storage, которая сканирует markdown vault и помогает привести в порядок проблемы, которые приложение не должно чинить молча. Закрывает два болевых сценария:

  • Sync между машинами (Git/Dropbox/iCloud) — дубли id после слияния, merge-маркеры, conflicted-copy файлы.
  • Внешние редакторы (Obsidian, VS Code) — битый frontmatter, файлы без metadata, рассинхрон state/counters.

Раньше такие проблемы оставались невидимыми: doctor живёт в настройках, куда пользователь почти не заходит.

Что делает

  • Scan (read-only preview) по спейсам code / notes / http / math.
  • Дубли id → выбор canonical-файла, остальным выдаются новые id с counter-baseline (нет повторной коллизии). Решения требуют явного выбора; fingerprint-guard отклоняет, если файл изменился между preview и apply.
  • Merge-маркеры и битый frontmatterblocked, не парсятся и не переписываются.
  • Safe fixes (frontmatter, .meta.yaml, register, counters) применяются стандартным sync.
  • HTTP environments / math state — нормализация state-уровня (дубли, битый activeSheetId).

Проактивное уведомление

После загрузки приложения — неблокирующий read-only чек (в idle). При наличии конфликтов показывается sonner с кнопкой «Разобрать» → открывает Storage, автоскан, скролл к секции. Состояние вынесено в useVaultDoctor, поэтому startup-проверка и секция переиспользуют один отчёт (без двойного скана).

UI

  • Блок решений на radio-group: имя файла + папка раздельно, бейджи Оригинал/Копия, исход на строке (сохранит id / новый id), автопредвыбор вероятного оригинала.
  • Панель конфликтов на приподнятой поверхности (bg-background) для контраста границ в тёмной теме.
  • Отложенные лоадеры scan/apply (без мелькания на быстрых операциях).

Тесты

doctor.test.ts покрывает детект дублей, reassign по решению, blocked merge-маркеров, исключение trash, env/math repair, идемпотентность.

Известное ограничение

В code/notes нерешаемый blocked-файл (merge-маркер / битый frontmatter) пока замораживает применение safe fixes во всём спейсе — консервативно-безопасно, но расходится с целью полностью раздельных потоков. Кандидат на доработку отдельным PR.

🤖 Generated with Claude Code

Rework the duplicate-id decision block from button rows into a shadcn
radio-group: split file path into name + folder, add original/copy
badges, show the per-row outcome (keeps id / new id), preselect the
likely original as canonical, and surface resolved/unresolved group
status.

Add shadcn radio-group and badge primitives.
Run a non-blocking, read-only vault doctor preview after app load (in
idle) and show a sonner with a "Review" action when sync conflicts are
found. Doctor lives in Storage settings, which users rarely open, so
conflicts (duplicate ids, merge markers, invalid frontmatter) would
otherwise go unnoticed. Safe fixes are excluded since the watcher
applies them silently.
Pass a `doctor=scan` query from the startup conflict sonner and trigger
the scan on mount in Storage, then clear the query. Previously the action
landed on an empty Vault Doctor section that required pressing Scan
manually.
Move vault doctor state (report, decisions, scan/apply) into a shared
module-level composable so the startup health check and the Storage
section reuse a single report instead of scanning twice. When opened
from the startup notice, reuse the existing report (or scan if absent)
and smooth-scroll to the Vault Doctor section.
The default radio border-input (~30% L) nearly matches the card surface
(~27% L) in dark theme, making unselected radios invisible. Use
border-muted-foreground/50 for a readable outline on any surface.
Replace the per-radio border hack with a surface lift: the Needs decision
panel now sits on bg-background (matching its header), so borders and
radios inside read against the elevated surface instead of blending into
the card. Revert the radio border-color override.
Show the scan spinner only if the scan runs longer than 300ms, mirroring
the existing snippet counts loader. Fast scans no longer flash the loader
for a split second. The button stays disabled on the real scanning flag
so repeat clicks are still blocked instantly.
Apply the same delayed-loader pattern to Apply fixes: show the spinner
only if apply runs longer than 300ms. The button stays disabled on the
real applying flag so repeat clicks are blocked instantly.
@antonreshetov antonreshetov merged commit a525140 into main Jun 15, 2026
@antonreshetov antonreshetov deleted the feat/vault-doctor branch June 15, 2026 15:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant