The refresh rewrote the whole row it read before a download whose length
the provider controls, so an admin's delete, disable or edit made in the
meantime was undone; Update had the mirror problem. Both now write only
their own columns, and a refresh of a row that was deleted or re-pointed
stores nothing.
Around the same path:
- the preview fetches without creating (and leaking) a scratch row, and
Create keeps enabled=false instead of falling back to the column default;
- fetch errors name the host but not the subscription URL, which is a
credential and ends up in the log and in lastError;
- each fetch closes its transport's idle connections;
- one document loads at most 2000 links, and the cut is reported;
- wireguard outbounds from a subscription always run on the userspace TUN;
- editing a subscription schedules an Xray reload like delete and move do.
Most tests opened a throwaway panel DB with database.InitDB, which runs the
full AutoMigrate + seed on an empty file every time: ~230ms, and ~850ms under
-race because GORM's reflection-heavy migration is what the detector slows
most. internal/web/service does this in ~550 of its 830 tests, so the CI race
job spent ~10 of its ~14.6 minutes re-migrating empty databases.
internal/database/dbtest.InitDB migrates once per test process, then hands
each test its own copy of that file (~130ms under -race) and registers the
CloseDB cleanup. The copy then goes through InitDB like a panel restart, so
every test still starts from the state a fresh install has. Tests that reopen
an existing file, migrate a hand-built legacy DB or target Postgres keep
calling database.InitDB.
Locally under -race: internal/web/service 626s (last CI run) -> 114s,
internal/sub 246s -> 35s.