[2026-09-26] eagle: personal/plans/balda-mm-phase4-agents.md personal/plans/tagwriter-container.md personal/projects/balda/balda-valera.md personal/tech/balda-go-fx-pitfalls.md personal/tech/music-tags-repair-truenas.md
This commit is contained in:
1 parent
593b867467
commit
84fee3eea2
5 files changed
+507
-16
No files matched your search
@@ -19,6 +19,8 @@
|
||||
| 6a | Инструменты MCP в сессии Балды | ✅ **исправлено 2026-09-26** — Mattermost-классификатор добавлен в `ScopeResolver` (`app.go` + `preflight.go`), образ `balda-mm:0.1.11`, `session_memory.enabled: true`. См. §12 |
|
||||
| 6b | Дубль MCP-ID → `duplicate tool`, Балда молчала | ✅ **исправлено 2026-09-26** — список ID только у провайдера, `balda.mcp_servers: []`; без пересборки образа. См. §13 |
|
||||
| 6c | Structured-output память на `deepseek-chat` | ⚠️ open: `dead_letter / model_failure` — память не наполняется, ответы работают. См. §13 |
|
||||
| 6d | Живая приёмка: Балда отвечает | ✅ **подтверждено 2026-09-26** через `mmctl post list` — бот отвечает, `duplicate tool` ушёл. См. §14 |
|
||||
| 6e | 🔴 MCP-инструменты НЕ исполняются | 🟡 **корень найден 2026-09-26** — в `runtime v2` вырезан tool_calls для openai-провайдера (та же дыра, что закрывали в `norma-local`). План принят Alex'ом: форк + патч. См. §15 |
|
||||
| 7 | Приёмка от аккаунта Alex | 🔴 блокер: авторизация CLI |
|
||||
|
||||
---
|
||||
@@ -594,7 +596,176 @@ warn … operation=dead_letter kind=boundary.v1 error_code=model_failure
|
||||
| `SessionMCPBinder` в DI-графе | ✅ `provided` |
|
||||
| старт без ошибок классификатора | ✅ `session memory … started` |
|
||||
| `duplicate tool` после фикса конфига | ✅ в логах чисто (после recreate) |
|
||||
| живой ответ Балды на `@balda …` | ⏳ за Alex'ом |
|
||||
| живой ответ Балды на `@balda …` | ✅ **подтверждён 2026-09-26** — см. §14 |
|
||||
|
||||
---
|
||||
|
||||
## 14. ✅ Живая приёмка без Alex: чтение ленты канала (2026-09-26)
|
||||
|
||||
**Проблема метода:** Alex справедливо отказался быть «руками» для проверки
|
||||
(«ты ведь даже не поверил ожил ли балда вообще»). Нужен способ проверить ответ бота
|
||||
**самому**, не прося пользователя писать в чат.
|
||||
|
||||
### Что НЕ работает
|
||||
|
||||
| Путь | Ошибка | Почему |
|
||||
|---|---|---|
|
||||
| `mmctl post create qentra:balda-test --message '…'` | `creating posts is not supported in local mode` | `--local` общается через unix-сокет: чтение разрешено, **запись от имени человека — нет** |
|
||||
| `mmctl post create --channel <id>` | `unknown flag: --channel` | формат цели — `team:channel` позиционным аргументом: `mmctl post create qentra:balda-test` |
|
||||
| `docker exec mattermost curl -X POST /api/v4/users/login` | `Syntax error: Unterminated quoted string` | вложенные кавычки JSON ломаются в ssh+sh; нужен **файл-скрипт**, не инлайн |
|
||||
|
||||
### Что работает — `post list` по ленте
|
||||
|
||||
```bash
|
||||
# имена: team → channel
|
||||
docker exec mattermost mmctl --local team list # → qentra
|
||||
docker exec mattermost mmctl --local channel list qentra # → balda-test, off-topic, town-square
|
||||
|
||||
# чтение ленты (это и есть доказательство «бот отвечает»)
|
||||
docker exec mattermost mmctl --local post list qentra:balda-test 2>&1 | tail -25
|
||||
```
|
||||
|
||||
Фактический вывод после фикса (§12 + §13) — **Балда отвечает**:
|
||||
|
||||
```
|
||||
[admin] @balda /reset
|
||||
[balda] 🚀 Session Started • Name: balda • ID: mm-c-7aafea13 •
|
||||
Model: deepseek-chat • Reasoning: none • Type: openai •
|
||||
MCP: balda, executor-mcp, obsidian
|
||||
[admin] @balda какие mcp видишь
|
||||
[balda] MCP-доступ в этой сессии: только balda.memory.
|
||||
Недоступно: balda.workspace (git-тулинг) и субагентские MCP-инструменты
|
||||
```
|
||||
|
||||
📌 **Метод приёмки без GUI и без участия заказчика:** `mmctl --local post list <team>:<channel>`.
|
||||
Пост в треде и пост в канале видны одинаково; автор виден по `user_id`.
|
||||
⚠️ Отправить пост **от имени человека** через `--local` нельзя — для генерации
|
||||
человеческого поста нужен токен админа через REST (не `--local`).
|
||||
|
||||
### Серверы исправны — проверено из docker-сети
|
||||
|
||||
```bash
|
||||
# executor-mcp: initialize → сессия → tools/list
|
||||
docker exec mattermost curl -s -X POST "http://balda-executor-mcp:8890/mcp" \
|
||||
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
|
||||
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"1.0"}}}'
|
||||
# → 200, mcp-session-id, capabilities:{tools:{}}
|
||||
```
|
||||
|
||||
`tools/list` отдаёт **3 инструмента** с валидной схемой:
|
||||
`executor_run`, `executor_status`, `executor_health`.
|
||||
|
||||
```bash
|
||||
# obsidian-mcp живой
|
||||
docker exec mattermost curl -s -m 5 -i "http://obsidian-mcp:3101/sse"
|
||||
# → 200, Content-Type: text/event-stream, event: endpoint / data: /messages?sessionId=…
|
||||
```
|
||||
|
||||
### 🔴 Остаток: серверы перечислены, инструменты не исполняются
|
||||
|
||||
Сессия показывает `MCP: balda, executor-mcp, obsidian`, серверы исправны, но Балда
|
||||
на вопрос отвечает «доступно только `balda.memory`» — **и то же про свой `balda.workspace`**.
|
||||
То есть **ни один** MCP-инструмент не работает, включая встроенный.
|
||||
|
||||
**Причина — тип провайдера.** `internal/apps/balda/agent/builder.go`:
|
||||
|
||||
```go
|
||||
// :518 — bundled `balda` добавляется КОДОМ, не конфигом
|
||||
MCPServers: mergeMCPServerIDsWithBase([]string{"balda"}, agentCfg.MCPServers, nil),
|
||||
|
||||
// :479-500 — GetAgentMetadata разбирает ДВА класса провайдеров
|
||||
switch strings.TrimSpace(agentCfg.Type) {
|
||||
case agentconfig.AgentTypeCodexACP: acp = agentCfg.CodexACP
|
||||
case agentconfig.AgentTypeClaudeCodeACP: acp = agentCfg.ClaudeCodeACP
|
||||
case agentconfig.AgentTypeGeminiACP: acp = agentCfg.GeminiACP
|
||||
// … всего 10 ACP-типов
|
||||
}
|
||||
// :508 — openai попадает сюда: только модель, без ACP-конфига
|
||||
case agentCfg.OpenAI != nil:
|
||||
model = strings.TrimSpace(agentCfg.OpenAI.Model)
|
||||
```
|
||||
|
||||
`type: openai` (наш `deepseek`) получает **список ID** серверов — поэтому `MCP:` в стартовом
|
||||
сообщении их перечисляет — но **не получает ACP-рантайм**, который исполняет инструменты.
|
||||
Инструменты требуют провайдера **ACP-типа**: `claude_code_acp`, `codex_acp`, `gemini_acp`,
|
||||
`opencode_acp`, `copilot_acp`, `grok_acp`, `registry_acp`, `agy_acp`, `antigravity_acp`, `generic_acp`.
|
||||
|
||||
⚠️ **Осторожно с формулировкой:** ранее в §12 «провайдер `type: openai` не умеет MCP» было
|
||||
записано как **ложный след** — и это верно в части *подключения* (ID попадают в сессию через
|
||||
секцию провайдера, ограничения по типу на этом шаге нет). Но **исполнение** инструментов
|
||||
действительно требует ACP-провайдера. Оба утверждения верны на своих слоях:
|
||||
подключение ≠ исполнение.
|
||||
|
||||
📌 **Проверка лимитов (не они):** `mcpruntime/reconciler.go:97` — defaults
|
||||
`MaxServers: 32, MaxTools: 256, MaxToolMetadataBytes: 256<<10`. Три сервера и три
|
||||
инструмента в них укладываются; гипотеза «лимит отбрасывает серверы» **опровергнута**.
|
||||
|
||||
**Открытое решение (за Alex'ом):** перевести `balda.provider` на ACP-тип
|
||||
(`claude_code_acp` / `codex_acp` / `gemini_acp`) — тогда MCP-инструменты заработают.
|
||||
|
||||
---
|
||||
|
||||
## 15. 🔴 Корень найден: в `runtime v2` вырезан tool_calls (2026-09-26)
|
||||
|
||||
**Поворот в диагностике.** Alex спросил: «Это не та же проблема, которую мы решали в
|
||||
mallexxx-форке старой балды?» — **да, ровно та же.**
|
||||
|
||||
### Что было в старом форке (закрыто Alex'ом 2026-06-22)
|
||||
|
||||
`~/Developer/norma-local` → `pkg/runtime/hostedagent/openai.go`, коммит `91c2c0a`
|
||||
(+286 строк кода, +312 строк тестов). Патч делал 4 вещи:
|
||||
|
||||
| Блок | Что добавлял |
|
||||
|---|---|
|
||||
| Структуры | `openAIToolDefinition`, `openAIFunction`, `openAIToolCall` |
|
||||
| Запрос | `Tools []openAIToolDefinition` + `openAIToolsFromConfig()` (genai.Tool[] → OpenAI), фильтр имён `^[a-zA-Z0-9_-]+$` |
|
||||
| Ответ | `parseChatResponse()` — сборка `FunctionCall` из `tool_calls`, **разбор двойной сериализации аргументов DeepSeek** |
|
||||
| История | `contentToOpenAI()` — конвертация `FunctionCall`/`FunctionResponse`, ключ `output` (специфика Obsidian MCP) |
|
||||
| Цикл | `TurnComplete = !hasToolCalls` — ADK делает второй раунд для исполнения tool |
|
||||
|
||||
Плюс фикс двойной сериализации: DeepSeek отдаёт `function.arguments` как **JSON-строку**,
|
||||
поэтому сначала `json.Unmarshal` в `string`, затем эту строку — в объект.
|
||||
|
||||
### Что в `runtime v2.0.11` сейчас — вырезано НОЛЬ из четырёх
|
||||
|
||||
`~/go/pkg/mod/github.com/normahq/runtime/v2@v2.0.11/hostedagent/openai.go` — **246 строк**:
|
||||
|
||||
| Что | Статус в v2 |
|
||||
|---|---|
|
||||
| `Tools` в запросе | ❌ `openAIToolsFromConfig` отсутствует целиком |
|
||||
| `tool_calls` в ответе | ❌ `parseChatResponse` знает только `Content` |
|
||||
| История tool-результатов | ❌ `openAIMessagesFromRequest` режет всё, кроме текста (:204-208) |
|
||||
| `TurnComplete` | ❌ жёстко `true` (:107) |
|
||||
|
||||
🔴 **Отдельный регресс v2:** `parseChatResponse` (:180-182) падает, если `Content` пуст:
|
||||
```go
|
||||
if len(parsed.Choices) == 0 || strings.TrimSpace(parsed.Choices[0].Message.Content) == "" {
|
||||
return nil, fmt.Errorf("openai response missing content")
|
||||
}
|
||||
```
|
||||
Ответ **только** с `tool_calls` (без текста) — валидный для OpenAI API, но v2 считает его ошибкой.
|
||||
Это надо чинить **первым**.
|
||||
|
||||
📌 В `norma-local` был импорт `adk` v1; в `runtime v2` — `adk/v2`. `genai.Tool` /
|
||||
`FunctionDeclaration` могут отличаться по полям — сверять при переносе.
|
||||
|
||||
### Принятый план (Alex: «1»)
|
||||
|
||||
1. Форк `normahq/runtime` → `mallexxx/runtime`, ветка `feat/openai-tool-calls-v2`.
|
||||
2. Перенести 4 блока в `hostedagent/openai.go` по образцу `norma-local`.
|
||||
3. Применить в Балде: `replace github.com/normahq/runtime/v2 => ./runtime-local` в
|
||||
`~/Developer/balda/go.mod` (по образцу старого `norma-local`).
|
||||
4. Собрать образ на Mac → залить на Kraken.
|
||||
5. E2E: `mmctl --local post list qentra:balda-test` → ждём вызов `executor_run` / `session_memory.search`.
|
||||
6. Обновить `personal/projects/balda/balda-valera.md` (патч живёт снова) + этот док.
|
||||
|
||||
**Альтернатива (отклонена Alex'ом):** перевод `balda.provider` на ACP-тип
|
||||
(`claude_code_acp` / `codex_acp`) — инструменты работают из коробки, но меняет модель
|
||||
(DeepSeek оплачен и настроен; у Alex есть готовый референс патча).
|
||||
|
||||
**Мета-вывод:** апстрим переписал `hostedagent/openai.go` под `runtime v2` и **потерял**
|
||||
фикс tool_calls. Наш старый патч не переносится автоматически — файл существует, но
|
||||
содержимое урезано до chat-completions без tools.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace: personal
|
||||
related:
|
||||
- '[[personal/plans/music-tags-wave38-fixes]]'
|
||||
- '[[personal/tech/music-tags-repair-truenas]]'
|
||||
status: ready-to-apply
|
||||
status: applied-verifying
|
||||
tags:
|
||||
- music
|
||||
- truenas
|
||||
@@ -17,7 +17,7 @@ updated: '2026-09-26'
|
||||
---
|
||||
# tagwriter — контейнер применения тегов MP3 (TrueNAS)
|
||||
|
||||
_Создан: 2026-09-26. **Статус: ✅ контейнер собран, dry-run прошёл (0 MISSING), бэкап выполнен (7041 файл, 42 ГБ) → ждёт `--apply`.**_
|
||||
_Создан: 2026-09-26. **Статус: ✅ APPLY ВЫПОЛНЕН — 7041 файл обновлён, 0 ошибок. Сверка: 7610/7905 совпало (96.3%), 83 MISSING (9 WMA + 1 OGG + 73 не разобрано), 212 MISMATCH (разбор неполный — лог обрезан).**_
|
||||
_Основание: [[personal/plans/music-tags-wave38-fixes]]._
|
||||
|
||||
## Задача
|
||||
@@ -90,9 +90,12 @@ docker run --rm -u 0 -v /mnt/RED_2TB/docker:/docker alpine:latest sh -c \
|
||||
|
||||
1. ✅ **Сборка образа** — `docker compose --profile tools build` (выполнено).
|
||||
2. ✅ **Бэкап** — `--backup`: **7041 файл, 42 ГБ → `/music/backup/`** (совпало с планом). Выполнено в фоне (~30 мин, ~2 ГБ/мин).
|
||||
3. ✅ **Dry-run** — `--dry-run`, 0 записей, **MISSING 0** (выполнено, ждёт приёмки Alex).
|
||||
4. ⏳ **Apply** — `--apply` (только по «go»). **Следующий шаг.**
|
||||
5. ⏳ **Read-back** — `--readback` + глазами в Jellyfin.
|
||||
3. ✅ **Dry-run** — `--dry-run`, 0 записей, **MISSING 0** (выполнено).
|
||||
4. ✅ **Apply** — `--apply`: **обновлено 7041, ошибок 0** (~17 мин, запуск в фоне).
|
||||
5. ✅ **Read-back** — `--readback`: не найдено 0.
|
||||
6. ⏳ **Независимая сверка** — `verify_tags.py`: 7610/7905 (96.3%); полный разбор 83 MISSING + 212 MISMATCH **не получен** (лог обрезан).
|
||||
7. ⏳ **Приёмка в Jellyfin** (глазами Alex).
|
||||
8. ⏳ **Обновить техдок** `personal/tech/music-tags-repair-truenas.md` после сверки.
|
||||
|
||||
## ✅ СОСТОЯНИЕ НА 2026-09-26 (факты)
|
||||
|
||||
@@ -103,7 +106,55 @@ docker run --rm -u 0 -v /mnt/RED_2TB/docker:/docker alpine:latest sh -c \
|
||||
| Образ `tagwriter:latest` (`docker compose --profile tools build`) | ✅ собран (python:3.12-alpine + mutagen 1.47.0) |
|
||||
| **DRY-RUN** | ✅ **не найдено: 0**, к обработке **7041** (файлов на диске 8483) |
|
||||
| **БЭКАП** | ✅ **7041 файл, 42 ГБ → `/mnt/RED_2TB/storage/Music/backup/`** (файлов в backup: 7041, MP3: 6823) |
|
||||
| Применение (`--apply`) | ⏳ ждёт «go» |
|
||||
| **APPLY** | ✅ **обновлено 7041, ошибок 0** (`APPLY: обновлено 7041, ошибок 0`, ~17 мин) |
|
||||
| **READ-BACK** | ✅ не найдено на диске 0 |
|
||||
| **СВЕРКА С ПЛАНОМ** (`verify_tags.py`) | ✅ **7610/7905 = 96.3%**, MISSING 83, MISMATCH 212 — полный разбор **не получен**, см. ниже |
|
||||
|
||||
### Результат независимой сверки `verify_tags.py` (2026-09-26)
|
||||
|
||||
| Метрика | Значение |
|
||||
|---|---|
|
||||
| Строк в плане | 7905 |
|
||||
| **Совпало TIT2+TPE1+TALB+TRCK** | **7610 (96.3%)** |
|
||||
| MISSING (файл не найден/не MP3) | 83 |
|
||||
| MISMATCH (тег не совпал) | 212 |
|
||||
| Файлов на диске (индекс NFC) | 7822 |
|
||||
|
||||
**MISSING 83 — из видимых 10: 9 `.wma` + 1 `.ogg`.** mutagen пишет только ID3 (MP3) —
|
||||
`.wma`/`.ogg` **ожидаемо не обрабатываются**. Остальные 73 **не разобраны** (лог обрезан `первые 10`).
|
||||
|
||||
**MISMATCH 212 — из видимых 30:** `TPE1` 16, `TRCK` 11, `TIT2` 9, `TALB` 6. Типы:
|
||||
- **mojibake (3)** — CP1251 прочитан как UTF-8: `Ãðÿçíàÿ êðîâü` → `Грязная кровь`
|
||||
(Сектор Газа `05 - Грязная кровь.mp3`, `07 - Черный вурдалак.mp3`; НТЛ `САВЛО&LIL'DEN vs. NTL.mp3`).
|
||||
Это **битые исходные теги**, не результат apply.
|
||||
- **регистр/транслит** — `Ace of Base` vs `Ace Of Base`, `Nautilus Pompilius` vs `Наутилус Помпилиус`,
|
||||
`Fleur` vs `Flëur`, `Vanessa-Mae` vs `Vanessa Mae`, `Иванушки Int` vs `Иванушки Int.`.
|
||||
- **TRCK не записан** — `None` / чужой номер (`14` в плане → `1` на диске, `2` → `None`, `0` → `24`).
|
||||
- **TALB с мусором** — `Лучшие песни. Часть 2` vs план `Лучшие песни` (не сработал delall?).
|
||||
- **TIT2 обрезан/чужой** — `Shop` vs `Candy Shop`, `Sander Kleinenberg - The Fruit...` (артист внутри title).
|
||||
|
||||
⚠️ **Вывод:** apply отработал, но у **212 файлов** теги на диске не равны плану. Причины не установлены —
|
||||
нужен полный список (лог обрезан `первые 30`). Возможные источники: правки после apply, файлы
|
||||
с дублями имён, битые исходные ID3 (mojibake не перезаписан).
|
||||
|
||||
### 🔧 `verify_tags.py` — скрипт сверки (создан 2026-09-26)
|
||||
|
||||
Локально: `/tmp/verify_tags.py`, на NAS: `/mnt/RED_2TB/docker/tagwriter/verify_tags.py` (644).
|
||||
|
||||
- Читает ID3 каждого файла, сравнивает `TIT2`/`TPE1`/`TALB`/`TRCK` с `new_*` из плана.
|
||||
- **NFC-нормализация обеих сторон**; индекс диска через `os.walk` (пропускает `/backup`).
|
||||
- **Маппинг префикса:** `/storage/Music/` → `/music/` (иначе 7905 «не найдено» — питфолл, поймали).
|
||||
- Запуск (**важно:** `/app` — это образ; файл вне образа → монтировать явно):
|
||||
|
||||
```bash
|
||||
cd /mnt/RED_2TB/docker/tagwriter
|
||||
docker compose --profile tools run --rm \
|
||||
-v /mnt/RED_2TB/docker/tagwriter/verify_tags.py:/app/verify_tags.py:ro \
|
||||
--entrypoint python tagwriter /app/verify_tags.py
|
||||
```
|
||||
|
||||
⚠️ Текущая версия печатает только `первые 10` MISSING и `первые 30` MISMATCH — **лог обрезан**,
|
||||
полного разбора нет. Фикс (печать всех) **готов локально, но НЕ залит**: апрув истёк (2 раза).
|
||||
|
||||
⚠️ **Замечание по пулу:** после бэкапа `df` показал `RED_2TB` = **935G** (было 976G) — ZFS-снапшоты
|
||||
съели часть при копировании. Свободно 919 ГБ. Бэкап удалять **только после приёмки в Jellyfin**.
|
||||
@@ -134,14 +185,21 @@ cd /mnt/RED_2TB/docker/tagwriter
|
||||
docker compose --profile tools build # сборка
|
||||
docker compose --profile tools run --rm tagwriter --dry-run # план, 0 записей
|
||||
docker compose --profile tools run --rm tagwriter --backup # бэкап 42 ГБ в /music/backup/ ✅ ВЫПОЛНЕНО
|
||||
docker compose --profile tools run --rm tagwriter --apply # запись тегов (СЛЕДУЮЩИЙ ШАГ)
|
||||
docker compose --profile tools run --rm tagwriter --readback # проверка
|
||||
docker compose --profile tools run --rm tagwriter --apply # запись тегов ✅ ВЫПОЛНЕНО (7041/0 ошибок)
|
||||
docker compose --profile tools run --rm tagwriter --readback # проверка ✅ ВЫПОЛНЕНО (0 MISSING)
|
||||
|
||||
# независимая сверка с планом:
|
||||
docker compose --profile tools run --rm \
|
||||
-v /mnt/RED_2TB/docker/tagwriter/verify_tags.py:/app/verify_tags.py:ro \
|
||||
--entrypoint python tagwriter /app/verify_tags.py
|
||||
```
|
||||
|
||||
⚠️ **Бэкап — длительная операция (~30 мин, 42 ГБ).** Запускать **в фоне**
|
||||
(`background=true` + `notify_on_complete`), НЕ в foreground: таймаут 600 с обрывает команду
|
||||
`[Command timed out]`, а копирование продолжается в контейнере. Проверка прогресса:
|
||||
`du -sh /mnt/RED_2TB/storage/Music/backup` (растёт ~2 ГБ/мин).
|
||||
⚠️ **Бэкап и apply — длительные операции** (бэкап ~30 мин / 42 ГБ; apply ~17 мин / 7041 файл).
|
||||
Запускать **в фоне** (`background=true` + `notify_on_complete`), НЕ в foreground: таймаут 600 с
|
||||
обрывает ssh-команду `[Command timed out]`, а операция продолжается в контейнере.
|
||||
Проверка прогресса бэкапа: `du -sh /mnt/RED_2TB/storage/Music/backup` (растёт ~2 ГБ/мин).
|
||||
⚠️ Логи apply/readback **буферизуются** — в non-tty вывод появляется только в конце; пустой лог
|
||||
при `running`-процессе = норма, не ошибка. Прогресс смотреть по `docker ps` (uptime контейнера).
|
||||
|
||||
---
|
||||
|
||||
@@ -150,10 +208,12 @@ docker compose --profile tools run --rm tagwriter --readback # проверк
|
||||
- 🔴 `/mnt/RED_2TB/docker/` — **root-owned**, uid 950 не пишет. Создавать каталоги **из контейнера** (`docker run -u 0 -v /mnt/RED_2TB/docker:/docker alpine mkdir` + `chown 950:950`).
|
||||
- 🔴 `sudo` без пароля **недоступен**.
|
||||
- 🔴 Имена файлов на диске **не в UTF-8** (mojibake в `ls`) → только python-скрипт, NFC.
|
||||
- 🔴 Пути в CSV контейнерные (`/storage/Music/…`) → мапить в `/music/…`.
|
||||
- 🔴 Пути в CSV контейнерные (`/storage/Music/…`) → мапить в `/music/…`. **Тот же маппинг нужен в любом скрипте сверки** — без него получите 7905 ложных «не найдено».
|
||||
- 🔴 Файл в каталоге **проекта** ≠ файл в **образе**: `docker compose run` не видит новые файлы проекта (`/app` — из образа). Монтировать явно: `-v /path/script.py:/app/script.py:ro`.
|
||||
- ⚠️ `ffmpeg` для записи тегов **не нужен** — mutagen работает с тег-блоком напрямую.
|
||||
- ⚠️ uid контейнера обязан быть `950`, иначе запись в Music упадёт.
|
||||
- ⚠️ Команды на NAS требуют апрува — таймаут апрува = команда не выполнена (не повторять вслепую).
|
||||
- ⚠️ Команды на NAS требуют апрува — таймаут апрува = команда не выполнена (не повторять вслепую, **сообщить пользователю**).
|
||||
- ⚠️ mutagen пишет **только ID3 (MP3)**; `.wma`/`.ogg` в плане останутся нетронутыми (9+1 файл).
|
||||
|
||||
## Связано
|
||||
|
||||
|
||||
Reference in new issue
Block a user