Server locations: no user threshold

The public projection of a server's place showed only the country for
servers reporting fewer than 10 users. The owner never decided that
threshold: every located server now shows its city, coordinates (0.1°)
and network, and a CDN-fronted one still shows only its CDN, since the
address reached is the CDN's edge. Statistics:PublicCityMinUsers is
gone; the ROADMAP decision on server locations, CLAUDE.md and the
/stargazing explainer are corrected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-04 11:12:02 +02:00
1 parent 31d1d21d1e
commit eb7552e8f3
9 files changed
+56 -57

No files matched your search

+18 -11
View File
@@ -1,4 +1,4 @@
using MongoDB.Entities;
using MongoDB.Entities;
using PrivaPub.Models.Jobs;
using PrivaPub.Tests.Support;
@@ -9,9 +9,8 @@ using System.Text.Json.Nodes;
namespace PrivaPub.Tests.Http
{
// Where a server is, on the public instance API: the projection decided for public server locations (city and network
// only for servers reporting at least 10 users and not behind a CDN, the country otherwise, the CDN's name for a
// CDN-fronted one), the batch form, and this server itself.
// Where a server is, on the public instance API: where it was located (city, coordinates and network, whatever its size),
// only the CDN's name for a CDN-fronted one, the batch form, and this server itself.
[Trait("Category", "Integration")]
public sealed class InstanceLocationTests : IAsyncLifetime
{
@@ -51,7 +50,7 @@ namespace PrivaPub.Tests.Http
async Task<JsonNode> Geo(string host) => (await _host.Client().Get($"/api/privapub/v1/instances/{host}")).Ok().Body["geo"];
[Fact]
public async Task A_server_with_enough_users_shows_its_city_coordinates_and_network()
public async Task A_located_server_shows_its_city_coordinates_and_network()
{
var geo = await Geo(await Instance(50, Milan()));
@@ -66,16 +65,24 @@ namespace PrivaPub.Tests.Http
}
[Fact]
public async Task A_small_server_shows_only_its_country()
public async Task A_one_user_server_shows_its_city_too()
{
var geo = await Geo(await Instance(3, Milan()));
var geo = await Geo(await Instance(1, Milan()));
Assert.Equal("city", geo.Text("precision"));
Assert.Equal(("IT", "Milan", "Example Hosting"), (geo.Text("country"), geo.Text("city"), geo.Text("network")));
Assert.Equal(45.5, geo["latitude"]!.GetValue<double>());
}
[Fact]
public async Task A_server_located_only_to_its_country_shows_the_country()
{
var geo = await Geo(await Instance(50, new InstanceGeo { Country = "IT", Source = "DB-IP Lite 2026-10", LocatedAt = DateTime.UtcNow }));
Assert.Equal("country", geo.Text("precision"));
Assert.Equal("IT", geo.Text("country"));
Assert.Null(geo["city"]);
Assert.Null(geo["latitude"]);
Assert.Null(geo["longitude"]);
Assert.Null(geo["network"]);
}
[Fact]
@@ -102,7 +109,7 @@ namespace PrivaPub.Tests.Http
var host = await Instance(3, Milan());
var described = (await _host.Client().Get($"/api/privapub/v1/instances/{host}")).Ok().Body;
Assert.Equal("country", described["geo"].Text("precision"));
Assert.Equal("city", described["geo"].Text("precision"));
Assert.Equal(described["geo"]!.ToJsonString(), (await Geo(host))!.ToJsonString());
}
@@ -117,7 +124,7 @@ namespace PrivaPub.Tests.Http
var hosts = answer.Body!.AsArray().Select(i => i.Text("host")).ToList();
Assert.Equal(new[] { small, big }, hosts);
Assert.Equal("country", answer.Body![0]["geo"].Text("precision"));
Assert.Equal("city", answer.Body![0]["geo"].Text("precision"));
Assert.Equal("city", answer.Body![1]["geo"].Text("precision"));
Assert.Empty((await _host.Client().Get("/api/privapub/v1/instances")).Ok().Body!.AsArray());
}
+7 -7
View File
@@ -1,4 +1,4 @@
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Logging.Abstractions;
using MongoDB.Entities;
@@ -78,16 +78,16 @@ namespace PrivaPub.Tests.Statistics
}
[Fact]
public void The_public_location_depends_on_size_and_on_a_cdn()
public void The_public_location_is_where_the_server_was_located_unless_a_cdn_hides_it()
{
var geo = new InstanceGeo { Country = "DE", City = "Berlin", Latitude = 52.5, Longitude = 13.4, AsnOrg = "Hetzner", Asn = 24940 };
Assert.Equal(new PublicLocation("DE", "Berlin", 52.5, 13.4, "Hetzner", null), PublicGeo.Project(new RemoteInstance { Geo = geo, UsersTotal = 10 }, 10));
Assert.Equal(new PublicLocation("DE", null, null, null, null, null), PublicGeo.Project(new RemoteInstance { Geo = geo, UsersTotal = 1 }, 10));
Assert.Equal(new PublicLocation("DE", null, null, null, null, null), PublicGeo.Project(new RemoteInstance { Geo = geo }, 10));
Assert.Equal(new PublicLocation("DE", "Berlin", 52.5, 13.4, "Hetzner", null), PublicGeo.Project(geo));
Assert.Equal(new PublicLocation("DE", null, null, null, null, null), PublicGeo.Project(new InstanceGeo { Country = "DE" }));
Assert.Equal(new PublicLocation(null, null, null, null, null, "Cloudflare"),
PublicGeo.Project(new RemoteInstance { Geo = new InstanceGeo { Country = "US", City = "SF", Cdn = "Cloudflare" }, UsersTotal = 5000 }, 10));
Assert.Null(PublicGeo.Project(new RemoteInstance(), 10));
PublicGeo.Project(new InstanceGeo { Country = "US", City = "SF", Latitude = 37.8, Longitude = -122.4, Cdn = "Cloudflare" }));
Assert.Null(PublicGeo.Project(new InstanceGeo()));
Assert.Null(PublicGeo.Project(null));
}
}