внутренняя модель перестроена вокруг аудиозаписи
- audiorecords вместо transcribe_jobs: приложения (texts, structures, recognitions, record_events, topics) живут своими коллекциями, ссылки на исходник и на приведённую копию перестали переставляться - рубеж называет достигнутое, отказ стал признаком остановки с причиной, а сторожей стало двое: число отказов и время в рубеже - воркеры потеряли специализацию, их число задаётся [pipeline] workers, шаг выбирается по рубежу, а захват отдаёт идентификатор и признак захвата
This commit is contained in:
+10
-10
@@ -28,22 +28,22 @@ OpenSpec.
|
||||
`jq` без регулярных выражений.
|
||||
|
||||
```json
|
||||
{"time":"2026-08-10T11:23:45.123456Z","level":"INFO","msg":"job accepted","capability":"intake","job_id":"…","source":"telegram","duration_seconds":137}
|
||||
{"time":"2026-08-10T11:23:45.123456Z","level":"INFO","msg":"record accepted","capability":"intake","record_id":"…","source":"telegram","duration_seconds":137}
|
||||
```
|
||||
|
||||
*Расхождение:* `main.go` ставит `slog.NewTextHandler(os.Stdout, …)`.
|
||||
|
||||
## Сообщение
|
||||
|
||||
- `msg` — короткая константа в нижнем регистре: `job accepted`,
|
||||
- `msg` — короткая константа в нижнем регистре: `record accepted`,
|
||||
`recognition done`, `conversion failed`. Данные — в атрибутах:
|
||||
`log.Info("job accepted", "job_id", id, "source", "telegram")`.
|
||||
`log.Info("record accepted", "record_id", id, "source", "telegram")`.
|
||||
- `msg` — чистая категория без префикса подсистемы: `recognition done`, а не
|
||||
`recognize: done`. Подсистему выносим в поле `capability`, не в текст.
|
||||
- **Смена состояния задачи — единая категория `state transition`** с полями
|
||||
`from`, `to` и причиной. Любой переход пишет этот `msg`, чтобы весь
|
||||
жизненный цикл собирался одним отбором:
|
||||
`jq 'select(.msg=="state transition" and .job_id=="…")'`. Физический эффект
|
||||
`jq 'select(.msg=="state transition" and .record_id=="…")'`. Физический эффект
|
||||
сверх перехода — отдельная запись своей категории (`file converted`,
|
||||
`text delivered`), она запись перехода не подменяет.
|
||||
|
||||
@@ -100,13 +100,13 @@ OpenSpec.
|
||||
| Когда добавляем | Поля |
|
||||
| --- | --- |
|
||||
| на входящий HTTP-запрос | `transport` (`http`, `telegram`), `http.method`, `http.route`, `http.status_code`, `duration_ms` |
|
||||
| на задачу | `capability` (значения — по именам заведённых capability в `openspec/specs/`), `job_id`, `file_id`, `source` |
|
||||
| на задачу | `capability` (значения — по именам заведённых capability в `openspec/specs/`), `record_id`, `file_id`, `source` |
|
||||
| на запись об ошибке | `error` |
|
||||
| на вызов внешнего сервиса | `ext.service`, `ext.operation`, `ext.status_code`, `duration_ms`, `retry` |
|
||||
|
||||
Не заводим `service.*` и `host.*` — для одного бинарника на одном хосте это шум.
|
||||
|
||||
*Расхождение:* в коде встречаются `job_id`, `file_id`, `operation_id`,
|
||||
*Расхождение:* в коде встречаются `record_id`, `file_id`, `operation_id`,
|
||||
`worker`, `path`, `src_path`, `dest_path` — то есть словарь сложился сам и
|
||||
пересечён с этим лишь частично.
|
||||
|
||||
@@ -120,16 +120,16 @@ OpenSpec.
|
||||
чтобы ключ дописывался на каждую запись сам:
|
||||
|
||||
```go
|
||||
log := log.With("job_id", job.Id, "capability", "conversion")
|
||||
log := log.With("record_id", record.Id, "capability", "conversion")
|
||||
```
|
||||
|
||||
- Все записи одной задачи собираются одним отбором:
|
||||
`jq 'select(.job_id=="…")' app.jsonl`.
|
||||
`jq 'select(.record_id=="…")' app.jsonl`.
|
||||
|
||||
## Ошибки
|
||||
|
||||
Ошибки Go логируем как атрибут, а не как текст сообщения:
|
||||
`log.Error("conversion failed", "error", err, "job_id", id)`. Ключ — `error`.
|
||||
`log.Error("conversion failed", "error", err, "record_id", id)`. Ключ — `error`.
|
||||
|
||||
- Идиома Go — **либо лог, либо возврат, не оба**. Промежуточные слои только
|
||||
оборачивают и возвращают (`fmt.Errorf("…: %w", err)`), не логируя — контекст
|
||||
@@ -277,5 +277,5 @@ Bot API, поэтому чистка на месте употребления з
|
||||
|
||||
## Анализ
|
||||
|
||||
- Повседневно — `jq`: `jq 'select(.job_id=="…")' app.jsonl`.
|
||||
- Повседневно — `jq`: `jq 'select(.record_id=="…")' app.jsonl`.
|
||||
- Тяжёлое (сведение, соединение) — DuckDB поверх JSONL прямо из файла.
|
||||
|
||||
Reference in New Issue
Block a user