[AZ-810] Clamp UAV test-fixture coordinates to OSM-valid range
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful

The AZ-810 metadata validator rejects lat outside [-90, 90] and lon
outside [-180, 180]. Two NextTestCoordinate() helpers seeded their
counter from `(Ticks/TicksPerSecond) % 1_000_000` and returned
`60 + n*0.0005`, producing lat well above 90° for almost any seed
(e.g. n=200000 -> lat=160). Pre-AZ-810 there was no validator and no
DB constraint, so the out-of-range values were silently accepted; the
new validator (correctly) rejected them at HTTP 400.

Clamp both helpers to non-overlapping OSM-valid ranges:
  - UavUploadTests.cs:           lat in [50, 70),  lon in [10, 40)
  - UavUploadValidationTests.cs: lat in [-70, -50), lon in [-40, -10)

Non-overlap (not the prior +5_000_000 counter offset) is what now
guarantees AZ-488 and AZ-810 suites don't collide on the per-source
UNIQUE index when both run against the same DB.

No production code change; AZ-810 validator behaviour is unchanged.

Also:
- Correct AC-9 in batch_04_cycle8_report.md: the original claim
  ("verified by tracing source") was a false-PASS; the autodev
  Step 11 test run surfaced the gap. Now confirmed by full-suite
  green (scripts/run-tests.sh --full).
- Add ring-buffer lesson on AC-verification standards for input-
  validation changes: tracing fixture variables to their generators
  is insufficient; only a green integration-test run is sound
  evidence for a "no-regression" AC.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-23 14:20:45 +03:00
parent bbe87835a9
commit b763da3f24
5 changed files with 26 additions and 12 deletions
@@ -511,9 +511,14 @@ public static class UavUploadTests
private static (double Latitude, double Longitude) NextTestCoordinate()
{
// Spread test coordinates far enough apart to fall into distinct tile cells
// so concurrent runs don't collide on the per-source unique index.
// so concurrent runs don't collide on the per-source unique index. Wrap on
// 40_000-cell axes so the result always stays strictly inside the
// OSM-valid ranges enforced by UavTileMetadataValidator (AZ-810):
// lat in [50.0, 70.0), lon in [10.0, 40.0).
var n = Interlocked.Increment(ref _coordinateCounter);
return (60.0 + n * 0.0005, 30.0 + n * 0.0005);
var lat = 50.0 + ((uint)n % 40_000u) * 0.0005;
var lon = 10.0 + ((uint)n % 60_000u) * 0.0005;
return (lat, lon);
}
private static async Task<int> CountUavRowsAsync(string connectionString, double latitude, double longitude)
@@ -646,13 +646,20 @@ public static class UavUploadValidationTests
return stream.ToArray();
}
// Same coordinate-seeding strategy as UavUploadTests so AZ-810 happy-path
// inserts don't collide with the AZ-488 suite when both run back-to-back.
private static int _coordinateCounter = (int)((DateTime.UtcNow.Ticks / TimeSpan.TicksPerSecond) % 1_000_000) + 5_000_000;
// Use a southern-hemisphere range that does NOT overlap UavUploadTests'
// northern range ([50,70) x [10,40)). Non-overlap (not counter offset) is
// what guarantees the AZ-488 and AZ-810 suites don't collide on the
// per-source UNIQUE index when both run against the same DB. Wrap on
// 40_000-cell axes so the result always stays strictly inside the
// OSM-valid ranges enforced by UavTileMetadataValidator:
// lat in [-70.0, -50.0), lon in [-40.0, -10.0).
private static int _coordinateCounter = (int)((DateTime.UtcNow.Ticks / TimeSpan.TicksPerSecond) % 1_000_000);
private static (double Latitude, double Longitude) NextTestCoordinate()
{
var n = Interlocked.Increment(ref _coordinateCounter);
return (60.0 + n * 0.0005, 30.0 + n * 0.0005);
var lat = -50.0 - ((uint)n % 40_000u) * 0.0005;
var lon = -10.0 - ((uint)n % 60_000u) * 0.0005;
return (lat, lon);
}
}