# email-storage-format Specification ## Purpose Формат хранения архива писем: `email.md` (YAML-frontmatter + текст) в структуре `//YYYY/MM//`, выбранный по итогам анализа STORAGE_ANALYSIS.md (9 критериев: полнота заголовков, инкрементальность, идемпотентность, удобство поиска и др.). Хранит полные заголовки письма в frontmatter и тело как Markdown; доп. поля (classification, handled_*, attachments) расширяют frontmatter без изменения формата. ## Requirements ### Requirement: REQ-EMA-STORAGE-001: Обоснование выбора формата хранения **MUST** — проект должен содержать документ `STORAGE_ANALYSIS.md` в корне `/opt/hermes/email-assistant/`, объективно сравнивающий текущий формат хранения (`email.md` в `//YYYY/MM/UID/`) с Maildir, MBOX и notmuch. #### Scenario: Документ анализа существует **GIVEN** файл `STORAGE_ANALYSIS.md` существует **WHEN** его открывают **THEN** он содержит: - таблицу сравнения по критериям (производительность, устойчивость, интеграция, пригодность для LLM, совместимость с MUA, масштабируемость, бэкапы) - явную рекомендацию (остаться на текущем / мигрировать на Maildir / иное) - обоснование рекомендации с учётом мотивации пользователя (локальная LLM в скриптах, без облака) ### Requirement: REQ-EMA-STORAGE-002: Ссылка из README **MUST** — `README.md` проекта должен содержать ссылку на `STORAGE_ANALYSIS.md`. #### Scenario: README содержит ссылку **GIVEN** `README.md` проекта **WHEN** открываем его **THEN** в разделе «Оценка альтернатив» (или аналогичном) есть ссылка `[Анализ формата хранения (ФС vs Maildir)](STORAGE_ANALYSIS.md)`. ### Requirement: REQ-EMA-STORAGE-003: Без изменения данных **MUST** — change не должен модифицировать, мигрировать или удалять существующие письма в `/opt/hermes/email/`. Анализ — только документация. #### Scenario: Архив не изменён **GIVEN** архив `/opt/hermes/email/` **WHEN** change применён **THEN** файлы писем остаются без изменений (проверка: `find /opt/hermes/email -name 'email.md' | wc -l` — то же число, что и до change). ### Requirement: Архивация не помечает письмо прочитанным Чтение тела письма при архивации MUST NOT выставлять IMAP-флаг `\Seen`. `mail_archive.py` для получения тела использует `himalaya message read` с флагом `--preview` (документировано: читает БЕЗ установки `\Seen`). #### Scenario: Архивация непрочитанного письма - **GIVEN** письмо в INBOX с флагами `()` (непрочитанное) - **WHEN** `mail_archive.py` архивирует письмо (пишет `email.md`) - **THEN** в frontmatter `email.md` флаг `Seen` отсутствует И на IMAP флаги письма остаются `()` #### Scenario: Флаги в frontmatter соответствуют IMAP - **GIVEN** письмо заархивировано после фикса - **WHEN** флаги письма на IMAP меняются (пользователь прочитал/ответил) - **THEN** frontmatter `email.md` после следующей синхронизации отражает флаги IMAP (Seen появляется только если письмо реально прочитано пользователем)