* fix(api): explicit sweep scope, audit log and atomic delete for completed batches
Follow-up to #12969 (GHSA-wvxc-jp3v-5mg5) from the omni-code-review battery
(LEDGER-1/2/3/4/7/8/9/10):
- deleteCompletedBatches takes an explicit scope `{ apiKeyId } | { allTenants: true }`;
a missing/empty id throws instead of silently sweeping the whole instance
- route branches on the dashboard session explicitly; keys only sweep their own
batches; batches with no owner stay out of a key-scoped sweep on purpose (JSDoc)
- every sweep is logged (warn for instance-wide, info for key-scoped); a failing
sweep returns a sanitized 500 via buildErrorBody
- the file soft-deletes, checkpoint delete and batch delete run in one transaction;
the empty catch around deleteFile now logs the failure
- route-level regression test through the real handler; test files self-isolate
their DATA_DIR so the single-file command never touches ~/.omniroute
- changelog.d fragment
* fix(api): key-first sweep scope, audit at warn, mixed-scope guard for completed batches
Round-2 findings of the omni-code-review battery on the previous commit:
- a presented API key always scopes the sweep to that key, even when the request
also carries a dashboard session cookie (parity with GET /v1/batches; a leaked
or over-shared key can never widen a destructive sweep); only a session without
a key sweeps the whole instance
- both sweep modes log at warn so the audit trail survives APP_LOG_LEVEL=warn;
the failure log carries the error stack
- a scope carrying both apiKeyId and allTenants is rejected instead of widening
- changelog fragment links the PR
* test(batches): pin APP_LOG_LEVEL in the sweep-ownership test so the log assertion is environment-independent
* fix(api): fail closed on an unresolvable API key in the completed-batch sweep; no-op key sweeps log at info