fix(geocode): keep a nearby whole-name match as the last choice, and document the region rule

A query with a comma counted as "place, region", so a nearby place whose
own name has a comma ("Bed, Bath & Beyond") no longer won the nearby pass
and the unbiased pass could fly to a namesake far away. Its whole-name
match is now kept as the last choice, after the region checks of both
passes. CURRENT-STATE describes the place-region rule.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
quanticsoul4772andClaude Opus 5.5 committed 2026-10-25 17:07:46 -07:00
1 parent 7775f6007d
commit 91769d74b8
3 files changed
+41 -6

No files matched your search

+5 -1
View File
@@ -5191,7 +5191,11 @@ HTTP refusals and outages remain retryable. Searches share a 12-second total
deadline, with Photon requests capped at six seconds each. Caller/application
cancellation stops retries and late cache writes. Replacing a location search
cancels the previous lookup; disposing its controls cancels the active lookup. Photon uses a soft proximity bias, up to five
candidates, and an unbiased retry for name mismatches. Invalid/wrapped bounds
candidates, and an unbiased retry for name mismatches. A "place, region" query
only accepts a candidate named exactly for the place whose city, county, state,
country or country code (or USA/UK) contains the region; nearby results that
fail that check are retried unbiased, and a nearby place whose whole name is the
query (one with a comma in it) is the last choice. Invalid/wrapped bounds
are omitted rather than framing the wrong part of the globe.
### Map Stack Switcher (June 2026)
+13 -5
View File
@@ -390,16 +390,22 @@ export async function geocodeKeylessWithOutcome(
// to the wrong continent. So a biased answer is only accepted when it leads
// with the name asked for; otherwise the same query runs unbiased, which is
// what a user searching for somewhere off-screen meant in the first place.
// A query naming a region is only answered nearby by a match inside it.
// A query naming a region is answered nearby only by a match inside it.
// A nearby place whose own name has a comma ("Bed, Bath & Beyond") and
// equals the whole query is kept as the last choice, after the region
// checks of both passes.
let feature = null;
let nearbyNameMatch = null;
let everyAskAnswered = true;
if (bias) {
const biased = await ask(photonSearchUrl(trimmed, { bias, endpoint }));
if (biased === null) everyAskAnswered = false;
else
feature = queryRegion(trimmed)
? selectQualifiedFeature(biased, trimmed)
: selectPhotonFeature(biased, normalizeToponym(trimmed));
else if (queryRegion(trimmed)) {
feature = selectQualifiedFeature(biased, trimmed);
nearbyNameMatch = selectPhotonFeature(biased, normalizeToponym(trimmed));
} else {
feature = selectPhotonFeature(biased, normalizeToponym(trimmed));
}
}
signal?.throwIfAborted();
@@ -415,9 +421,11 @@ export async function geocodeKeylessWithOutcome(
const head = normalizeToponym(trimmed.split(',')[0]);
feature =
selectQualifiedFeature(anywhere, trimmed) ||
nearbyNameMatch ||
selectPhotonFeature(anywhere, head, { allowContains: true }) ||
anywhere[0];
}
if (!feature) feature = nearbyNameMatch;
}
signal?.throwIfAborted();
+23
View File
@@ -560,3 +560,26 @@ test('"UK" names the United Kingdom', () => {
};
assert.equal(selectQualifiedFeature([ontario, london], 'London, UK'), london);
});
test('a nearby place whose own name has a comma still wins when nothing matches as place and region', async () => {
const store = (lon, lat, city) => ({
geometry: { type: 'Point', coordinates: [lon, lat] },
properties: {
osm_key: 'shop',
osm_value: 'houseware',
name: 'Bed, Bath & Beyond',
city,
countrycode: 'US',
},
});
const nearby = store(-104.94, 39.66, 'Denver');
const fetchImpl = photonPair([nearby], [store(-73.99, 40.74, 'New York')]);
const result = await geocodeKeyless('Bed, Bath & Beyond', {
bias: '39.60,-105.00|39.70,-104.90',
fetchImpl,
});
assert.match(result.label, /Denver/);
assert.equal(fetchImpl.urls.length, 2, 'the region checks ran first');
});