obsidian-sync.ru.md
docs/i18n/integrations/obsidian-sync.ru.md
Двусторонняя синхронизация с Obsidian — предлагаемый дизайн
<!-- translations:start -->
English · 한국어 · 中文 · 日本語 · Español · Français · Deutsch
<!-- translations:end -->
Статус: выпущено (Tier 1, v0.5.0). Описанные ниже overlay reader, зоны добавления user-notes, режим watch и удаление осиротевших страниц работают за
tesserae vault sync. Эта страница служит и обоснованием дизайна, и руководством пользователя. Мульти-vault федерация (Tier 3) по-прежнему вне области.
Раньше экспорт в Obsidian был строго односторонним: типизированный граф из .tesserae/graph.json проецируется в vault, а project compile перезаписывает спроецированные файлы. obsidian-sync добавляет обратное направление — отредактируйте описание в Obsidian, и оно переживёт повторную компиляцию.
Этот документ объясняет, как это работает, не делая модель данных бессвязной.
Стратегический сдвиг, сформулированный явно
Текущий README отрицает живое редактирование:
Tesserae выбирает компиляцию из исходников вместо живого редактирования. Если хотите редактировать заметки в UI, используйте Logseq или Obsidian.
Двусторонняя синхронизация меняет этот контракт для подмножества полей. Стоит подходить к этому осознанно. Цель — не «Obsidian становится редактором», а «правки пользователя в Obsidian не уничтожаются молча при повторной компиляции».
Основная идея: оверлеи, а не слияния
Вместо попытки слить две расходящиеся копии одного и того же узла, рассматриваем vault как diff-слой поверх проекции:
source markdown ──extract──▶ base_graph
+
vault_overrides ◀── computed from vault
↓
final_graph ──project──▶ vault (.md files)
vault_overrides.json лежит в .tesserae/ и вычисляется, а не пишется вручную. На каждой компиляции Tesserae обходит vault, сравнивает каждую спроецированную страницу с тем, что предыдущая проекция записала, и фиксирует каждое внесённое пользователем изменение как запись оверлея. Финальный граф — это base_graph с применёнными оверлеями. Следующая проекция записывает результат обратно на диск.
Round-trip стабильный. Повторная компиляция того же vault без изменений в источнике не даёт никаких диффов.
Владение по полям
У каждого поля узла есть владелец. Владение определяет, что происходит при расхождении источника и vault.
| Поле | Владеет источник | Vault может переопределить | Примечания |
|---|---|---|---|
id, type | да | нет | Контролируется схемой; владеет extractor |
name | первично | да | Пользователь часто лучше extractor знает каноническое имя |
aliases | первично | да | Из vault — только добавление; записи vault всегда сохраняются |
description | первично | да | Самая частая правка в Obsidian |
source_path | да | нет | Происхождение; нельзя стереть редактированием |
metadata (заявленные ключи) | первично | да | Напр., arxiv_id, github_repo — пользователь может исправить |
metadata.user.* | n/a | да | Зарезервированное пространство имён только для пользовательских ключей; extractor никогда не пишет |
| Исходящие рёбра (типизированные) | да | нет | Рёбра живут в онтологии, не в vault |
| Новые wikilink, которые пишет пользователь | n/a | да | Всплывают как edge_type=user_link, записываются в граф |
Блок <!-- user-notes --> в теле | никогда не записывается | всегда сохраняется | Зона только для добавления, которой projector никогда не касается |
Случаи конфликтов и значения по умолчанию
| Случай | По умолчанию | Почему |
|---|---|---|
description в vault отличается от повторно извлечённого description источника | Vault побеждает, логируется в .tesserae/lint-report.md в раздел «diverged fields» | Уважение к правкам пользователя: пользователь явно намеренно внёс правку. Аудиторский след позволяет проверить позже. |
| Исходный файл удалён, но спроецированная страница всё ещё в vault | Удалить узел из графа, занести в .tesserae/orphans.md | Источник авторитетен по существованию; журнал сирот позволяет решить, восстановить или принять |
| Пользователь написал wikilink на slug, которого не существует | Создать tombstone-узел (тип Stub), показать в lint-отчёте | Не игнорировать намерение пользователя; пометить для очистки |
| Пользователь добавил ключ frontmatter, которого схема не знает | Сохранить как metadata.user.<key>, никогда не перезаписывать | Совместимо с будущим, не загрязняет типизированный граф |
| Два vault на разных машинах редактируют один узел, оба синхронизируются через Obsidian Sync | Вне рамок v1. Побеждает последний пишущий на уровне файловой системы. | Настоящая мульти-vault федерация — это Tier 3; откладывается до реального сценария использования |
Зона добавления пользовательских заметок
Каждая спроецированная страница получает выделенную зону, которой projector никогда не касается:
> [!quote] Paper
> Headline contribution and method sketch projected from the graph...
<!-- user-notes:start -->
Your notes here. Anything between the markers survives recompile forever.
Wikilinks here become `user_link` edges in the graph on the next pull.
<!-- user-notes:end -->
## Outgoing
- ...
Два практических эффекта:
- Пользователи могут аннотировать любую страницу (например, «см. главу 4 моих заметок»), не теряя это при пересборке.
- Pull-проход сканирует блок user-notes на наличие wikilink и всплывает их как типизированные онтологией рёбра
user_link, давая им достижимость в графе, не загрязняя формальные типы рёбер.
Удалённый транспорт — явная нецель
Tesserae не строит сервер синхронизации, слой аутентификации, демон разрешения конфликтов или хостинг vault. «Двусторонняя» здесь означает «компиляция читает из vault» — то, как vault попадает на машину, выполняющую компиляцию, — забота пользователя, решаемая уже существующими инструментами:
| Стек | Стоимость | Примечания |
|---|---|---|
| Obsidian Sync | Платно, $4–8/мес | E2E-шифрование, официальный, предельно простой |
| iCloud / Dropbox / OneDrive | В комплекте с ОС | Работает, но UX конфликтов недружелюбен |
| Syncthing | Бесплатно, self-hosted | Лучший выбор для одиночного использования на нескольких устройствах |
| Git (vault закоммичен) | Бесплатно | UX конфликтов — лучший для технических пользователей |
| LiveSync (плагин CouchDB) | Бесплатно, требует сервер | Реальное время на нескольких устройствах |
Все пять совместимы с моделью оверлеев, потому что Tesserae видит vault как файлы на диске, а не как поток мутаций.
CLI-интерфейс
tesserae vault sync применяет правки vault к типизированному графу и заново проецирует:
# Применить оверлей один раз: подтянуть правки пользователя, заново спроецировать в vault.
tesserae vault sync
# Сначала посмотреть, что изменится. Пишет .tesserae/diverged-fields.md и
# НЕ применяет и не перепроецирует.
tesserae vault sync --dry-run
# Указать конкретный vault для этого вызова (порядок разрешения:
# --vault > config.obsidian.vault_path > .tesserae/obsidian_vault/).
tesserae vault sync --vault ~/Documents/tesserae-vault
# Сделать этот путь vault значением по умолчанию для будущих команд.
tesserae vault sync --vault ~/Documents/tesserae-vault --persist-vault
# Долгоживущий watch: заново применять оверлей при каждом изменении vault.
# Ctrl-C для остановки; --poll-interval задаёт частоту опроса (по умолчанию 1.5 с).
tesserae vault sync --watch --poll-interval 1.5
# Удалить спроецированные страницы, исходный узел которых больше не существует
# (projector только перезаписывает, никогда не удаляет). Страницы с user-notes
# сохраняются, если не передать также --force-prune-with-notes.
tesserae vault sync --prune-orphans
tesserae vault sync --prune-orphans --force-prune-with-notes
Слэш-команда /tesserae:obsidian-sync оборачивает это, а tesserae refresh (и макрос /tesserae:refresh) запускает оверлей как последний шаг своей цепочки import → compile → sync.
Статус поставки
| Этап | Объём | Статус |
|---|---|---|
| 1a | Overlay reader: обойти vault, построить vault_overrides.json, применить при синхронизации. Расхождения попадают в .tesserae/diverged-fields.md. | Выпущено |
| 1b | Зоны добавления user-notes: projector никогда не касается блоков <!-- user-notes:start --> ... <!-- user-notes:end -->. | Выпущено |
| 2 | Режим watch: долгоживущий obsidian-sync --watch пересчитывает оверлей в цикле опроса по мере изменения vault. | Выпущено |
| 3 | Мульти-vault федерация: граф хранит происхождение по каждому vault, поддерживает конкурентные правки в синхронизируемых vault. | Отложено до реального сценария |
Нецели (явно)
- Сервер синхронизации / аутентификация / хостируемый бэкенд.
- Реальное совместное редактирование внутри Obsidian (используйте LiveSync, если нужно).
- Переписывание extractor для round-trip каждого поля — исходный markdown остаётся каноничным для всего, что вне таблицы переопределений.
- Синхронизация статического HTML-сайта (
build-siteостаётся только проекцией).
Принятые решения
Это были открытые вопросы на этапе дизайна; выпущенная реализация Tier 1–2 решила их так:
- Форма lint-отчёта. Расходящиеся поля всплывают как отдельный файл
.tesserae/diverged-fields.md(пишется при--dry-runи на каждом применении), а не как секцияlint-report.md, чтобы его можно было диффить в git. - Тип tombstone-узла. Добавить
Stubкак реальный тип схемы или совместить сOpenQuestionчерез дискриминатор_kind: stub? Предложение: реальный тип с именемStub, скрытый из публичных индексов. - Pull-on-compile по умолчанию. По умолчанию ON или OFF? Предложение: ON, когда vault существует по настроенному пути, с однократным подтверждением при первой активации, чтобы пользователи осознанно соглашались.
- Что считается «предыдущей проекцией» для диффа? Снимок, хранящийся в
.tesserae/vault_snapshot.json, или повторная проекция на лету при каждой компиляции? Предложение: снимок, записываемый в конце каждой компиляции. Дешевле и избегает протекания недетерминизма extractor в оверлей. - Многоязычная проекция vault. Сегодняшняя проекция одноязычная (язык источника). Должны ли оверлеи учитывать локаль (например, правка
descriptionв корейском vault применяется только к корейской проекции)? Предложение: вне рамок v1; vault одноязычный, совпадающий с основным языком проекта.
Как это отразится в obsidian.md
Руководство для пользователей остаётся сосредоточенным на «vault можно читать и запрашивать», а затем ссылается сюда ради истории про round-trip, с одной строкой резюме: «Редактируйте поля в Obsidian — они переживут recompile. См. obsidian-sync.md для полной модели».