Adds a serial-lane ILM integration regression test that pins the
local-first ordering contract established by rustfs#3491, where
`expire_transitioned_object` deletes local metadata BEFORE any remote
tier cleanup so a concurrent GET can never observe live local metadata
pointing at an already-removed remote tier version (user-visible
`NoSuchVersion`).
`serial_tests::test_expire_transitioned_object_never_races_concurrent_get`
in `crates/scanner/tests/lifecycle_integration_test.rs`:
- Transitions an object to a mock warm tier, then runs a tight
concurrent GET loop while calling `expire_transitioned_object`; every
GET must return a full, correct body or a clean object/version-not-found
-- never a tier-fetch failure.
- Deterministic ordering assertion (revert-proof): immediately after
expiry the remote tier object is still present and the mock recorded
zero remote `remove` calls, proving remote cleanup is deferred to
free-version recovery. Reverting to remote-first ordering turns this
assertion red.
Supporting changes:
- Re-export `expire_transitioned_object` from `api::bucket::lifecycle`.
- Record remote-tier mutating ops in the scanner test `MockWarmBackend`.
- Update tier-ilm-debugging.md to reference the new regression test.
Runs in the CI ILM Integration (serial) lane (ci.yml
test-ilm-integration-serial), picked up by the existing
binary(lifecycle_integration_test) filter.
Refs: rustfs/backlog#1148 (ilm-2), rustfs/backlog#1155