fix(geocode): a 'place, region' query lands in the region, not on a namesake

From Denver, 'Paris, Texas' flew to a pub in Budapest at rooftop range. The
camera-biased Photon answer listed the town first, but the pub's name equals
the whole query, and the biased path matched names only. A query with a
region now takes a candidate named for the place whose city, county, state,
country or country code (or USA/UK for US/GB) contains every word of the
region, in both the biased and the unbiased pass; with no such candidate
the existing name rules decide. A query with no region after its comma
keeps the biased name match.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
quanticsoul4772andClaude Opus 5.5 committed 2026-10-25 16:31:08 -07:00
1 parent 5ae22ac333
commit 1a61d02b7d
2 files changed
+110 -1

No files matched your search

+60
View File
@@ -30,6 +30,7 @@ import {
photonResultTypes,
photonSearchUrl,
selectPhotonFeature,
selectQualifiedFeature,
} from './keylessGeocoder.js';
import { geocodeNavigationMode } from './locations.js';
@@ -288,6 +289,52 @@ test('a "place, region" query is matched on the place, not the region', async ()
assert.equal(result.label.startsWith('Hoàn Kiếm Lake'), true, `got ${result.label}`);
});
/** Photon's real answers for "Paris, Texas" biased to Denver, then unbiased. */
const PARIS_TX = {
geometry: { type: 'Point', coordinates: [-95.5555, 33.6609] },
properties: { osm_key: 'place', osm_value: 'town', type: 'city', name: 'Paris', state: 'Texas', country: 'United States', countrycode: 'US' },
};
const PARIS_TEXAS_PUB = {
geometry: { type: 'Point', coordinates: [19.0606, 47.4868] },
properties: { osm_key: 'amenity', osm_value: 'pub', type: 'house', name: 'Paris, Texas', city: 'Budapest', country: 'Magyarország', countrycode: 'HU' },
};
const PARIS_TEXAS_SALON = {
geometry: { type: 'Point', coordinates: [153.03, -27.47] },
properties: { osm_key: 'shop', osm_value: 'hairdresser', type: 'house', name: 'Paris Texas', city: 'Brisbane', state: 'Queensland', country: 'Australia', countrycode: 'AU' },
};
test('"Paris, Texas" is the town in Texas, not a pub of that name in Budapest', async () => {
// Measured from Denver against the live service: the biased answer listed the
// town first, but the pub's name equals the whole query and won, flying the
// camera to Budapest at rooftop range.
const fetchImpl = photonPair([PARIS_TX, PARIS_TEXAS_PUB, PARIS_TEXAS_SALON], [PARIS_TX]);
const result = await geocodeKeyless('Paris, Texas', { bias: '39.70,-104.90|39.80,-104.80', fetchImpl });
assert.equal(Math.round(result.lat), 34, `got ${result.label}`);
assert.equal(fetchImpl.urls.length, 1);
});
test('a region is checked against where a candidate is, not its name', () => {
const pubFirst = [PARIS_TEXAS_PUB, PARIS_TEXAS_SALON, PARIS_TX];
assert.equal(selectQualifiedFeature(pubFirst, 'Paris, Texas'), PARIS_TX);
assert.equal(selectQualifiedFeature(pubFirst, 'Paris, United States'), PARIS_TX);
assert.equal(selectQualifiedFeature(pubFirst, 'Paris, US'), PARIS_TX);
// No region, or a region nothing lies in, leaves the choice to the name rules.
assert.equal(selectQualifiedFeature(pubFirst, 'Paris'), null);
assert.equal(selectQualifiedFeature(pubFirst, 'Paris, Ontario'), null);
assert.equal(selectQualifiedFeature(undefined, 'Paris, Texas'), null);
});
test('a region nearby fits nothing, so the unbiased answer decides', async () => {
const fetchImpl = photonPair([PARIS_TEXAS_PUB], [PARIS_TX, PARIS_TEXAS_PUB]);
const result = await geocodeKeyless('Paris, Texas', { bias: '47.40,19.00|47.50,19.10', fetchImpl });
assert.equal(Math.round(result.lat), 34, `got ${result.label}`);
assert.equal(fetchImpl.urls.length, 2);
});
test('accents and punctuation do not change what a name compares as', () => {
assert.equal(normalizeToponym('Huế'), 'hue');
assert.equal(normalizeToponym('Hạ Long Bay'), 'ha long bay');
@@ -452,3 +499,16 @@ function readGeocodingConsumer(file) {
? [file, 'annotations/resolver.js'] : [file];
return files.map((name) => fs.readFileSync(path.join(ROOT, 'src', name), 'utf8')).join('\n');
}
test('"USA" and "UK" name their countries, and a trailing comma keeps the nearby answer', async () => {
const pubFirst = [PARIS_TEXAS_PUB, PARIS_TX];
assert.equal(selectQualifiedFeature(pubFirst, 'Paris, Texas, USA'), PARIS_TX);
// "Paris," names no region: the camera-biased pass still answers.
const fetchImpl = photonPair([PARIS_TX], []);
const result = await geocodeKeyless('Paris,', {
bias: '33.60,-95.60|33.70,-95.50',
fetchImpl,
});
assert.equal(Math.round(result.lat), 34, `got ${result.label}`);
assert.equal(fetchImpl.urls.length, 1);
});