ingest: закрыты мелочи приёма — вырожденное имя, контракт Result, корреляция add

- имя раздачи нормализуется на границе разбора: вырожденное `-`
  (metainfo.NoName) даёт пустое имя, пробельное схлопывается — сентинел больше
  не доходит ни до контекста распознавания, ни до source_ref, ни до подсказки
  вывода имени
- контракт «на любом пути ошибки приёма результат нулевой» объявлен в ingest и
  удерживается структурно; три транспорта перестали обещать идентификатор,
  которого нет, и коррелируют отказ по request_id
- scoped-логгер загрузки ставится до вызова внешнего сервиса в семи командах
  воркера — записи об отказе qBittorrent и метабаз получили download_id
  и infohash; граница разбора bencode записана в docs/research
This commit is contained in:
av
2026-08-06 18:20:12 +03:00
parent 52615e4e49
commit d081ef1d30
30 changed files with 2190 additions and 63 deletions
+15 -1
View File
@@ -24,6 +24,9 @@ type fakeStore struct {
transitions []transition
torrents map[string][]byte // download_id → байты .torrent
promoteErr error // если задан — PromoteCatched возвращает его, НЕ меняя state (симуляция транзиентного сбоя БД)
setStateErr error // если задан — SetDownloadState отказывает (ветка отката Retry)
retriedErr error // если задан — SetRetriedAt отказывает (best-effort сброс базиса)
missCntErr error // если задан — SetSourceMissCount отказывает (best-effort сброс счётчика)
}
type transition struct {
@@ -166,6 +169,9 @@ func (f *fakeStore) AddInfohashes(_ context.Context, id string, hashes []string)
}
func (f *fakeStore) SetDownloadState(_ context.Context, id string, st store.State, code, msg string) error {
if f.setStateErr != nil {
return f.setStateErr
}
d, ok := f.downloads[id]
if !ok {
return fmt.Errorf("download %s not found", id)
@@ -213,6 +219,9 @@ func (f *fakeStore) SetParsedContext(_ context.Context, id, jsonStr string) erro
}
func (f *fakeStore) SetSourceMissCount(_ context.Context, id string, n int) error {
if f.missCntErr != nil {
return f.missCntErr
}
d, ok := f.downloads[id]
if !ok {
return fmt.Errorf("download %s not found", id)
@@ -233,6 +242,9 @@ func (f *fakeStore) SetSourceAddedAt(_ context.Context, id string, t time.Time)
}
func (f *fakeStore) SetRetriedAt(_ context.Context, id string, t time.Time) error {
if f.retriedErr != nil {
return f.retriedErr
}
d, ok := f.downloads[id]
if !ok {
return fmt.Errorf("download %s not found", id)
@@ -283,6 +295,7 @@ type fakeQbt struct {
torrentsErr error
onTorrents func() // вклинивается в момент листинга (симуляция гонки между снимком и re-read)
added []qbt.AddRequest
addCtx []context.Context // ctx каждого вызова Add (проверка scoped-логгера)
addErr error
onAdd func() // вклинивается в момент Add (симуляция отмены в окне после add)
files []qbt.File
@@ -321,7 +334,8 @@ func (f *fakeQbt) Torrents(_ context.Context, category string) ([]qbt.Torrent, e
return out, nil
}
func (f *fakeQbt) Add(_ context.Context, ar qbt.AddRequest) error {
func (f *fakeQbt) Add(ctx context.Context, ar qbt.AddRequest) error {
f.addCtx = append(f.addCtx, ctx)
if f.onAdd != nil {
f.onAdd()
}