tighten remaining voice outline review items

- join street pieces at up to 3 m again (inclusive), as before the shared stitcher
- share one default outline tile source across outline rung instances
- cover Japanese and Thai street names that differ only by a mark
- restore main's text for formatting-only CURRENT-STATE hunks
This commit is contained in:
manjunath committed 2026-10-30 21:27:53 +05:30
1 parent a71443a0ef
commit e6ad7fe34f
6 files changed
+96 -9

No files matched your search

+5 -2
View File
@@ -3812,7 +3812,7 @@ Shipped locales: **en** (source and fallback), **de**, **es**, **fr**, **it**, *
[`docs/TRANSLATORS.md`](./TRANSLATORS.md). [`docs/TRANSLATORS.md`](./TRANSLATORS.md).
- **Keys are the English text.** `t('Save keys')`, `tn(count, '{count} camera', - **Keys are the English text.** `t('Save keys')`, `tn(count, '{count} camera',
'{count} cameras')`, and `msg('Live Flights')` for text stored in data and '{count} cameras')`, and `msg('Live Flights')` for text stored in data and
translated later. Markup opts in with `data-i18n` (element text) and translated later. Markup opts in with `data-i18n` (element text) and
`data-i18n-title` / `-aria-label` / `-placeholder` (that attribute's English `data-i18n-title` / `-aria-label` / `-placeholder` (that attribute's English
value). English has no catalog; every other locale is value). English has no catalog; every other locale is
@@ -3924,6 +3924,7 @@ MLAT-positioned GPS loss, derived-field exclusions and the NIC 0 exception.
anchors, recovery, keyboard and mobile states; emergency repainting is covered anchors, recovery, keyboard and mobile states; emergency repainting is covered
by `scripts/qa-emergency-squawk.mjs`. Both accept `--timeout-ms` for slow boot. by `scripts/qa-emergency-squawk.mjs`. Both accept `--timeout-ms` for slow boot.
Fire Perimeters uses capped, timed server reads with stale-on-error caching and a per-client limit. A stale snapshot is served for at most 24 hours; the layer row then reads STALE, dated by that snapshot's fetch, and `get_fire_perimeters` returns `stale` and `retrieved_at` with "(data may be stale)" in its summary. Unchanged snapshots retain geometry; link checks cancel on disable or selection change, and the row legend shows reported containment. Fire Perimeters uses capped, timed server reads with stale-on-error caching and a per-client limit. A stale snapshot is served for at most 24 hours; the layer row then reads STALE, dated by that snapshot's fetch, and `get_fire_perimeters` returns `stale` and `retrieved_at` with "(data may be stale)" in its summary. Unchanged snapshots retain geometry; link checks cancel on disable or selection change, and the row legend shows reported containment.
Street Level is a docked, collapsible right-rail panel (`#street-level-panel`, Street Level is a docked, collapsible right-rail panel (`#street-level-panel`,
@@ -4089,7 +4090,8 @@ that does not answer in 20 s is asked once more, and one that is not a line
list is not cached. A click on a line reaches list is not cached. A click on a line reaches
`handlePick(id, {groundPoint})`, and the provider asks the core `handlePick(id, {groundPoint})`, and the provider asks the core
(`actions.openNearest`) for its nearest showable photo within 50 m, without (`actions.openNearest`) for its nearest showable photo within 50 m, without
framing: many photos are archived (their file answers 409, while a HEAD says 200) or have no file, so the six nearest are probed at once with a GET cut framing: many photos are archived (their file answers 409, while a HEAD says
200) or have no file, so the six nearest are probed at once with a GET cut
off at the headers, and where all are gone the panel says KartaView's photos off at the headers, and where all are gone the panel says KartaView's photos
there are archived. Only a definite answer (403/404/409/410, or 200) is there are archived. Only a definite answer (403/404/409/410, or 200) is
remembered; a storage timeout or 5xx is asked again. The open photo's remembered; a storage timeout or 5xx is asked again. The open photo's
@@ -5590,6 +5592,7 @@ Vite's development filesystem deny list excludes local `.gev-logs/` and
dependency `dist/` assets. Checkout glob characters are escaped. This does not dependency `dist/` assets. Checkout glob characters are escaped. This does not
apply to `public/` assets or built-preview serving. apply to `public/` assets or built-preview serving.
- Recommended launcher: `./scripts/dev-fresh.sh` (also: `dev-secure.sh` for stricter bindings, `dev-cctv.sh` for CCTV source-pack tuning) - Recommended launcher: `./scripts/dev-fresh.sh` (also: `dev-secure.sh` for stricter bindings, `dev-cctv.sh` for CCTV source-pack tuning)
- A successful Pinokio install writes the owner-only `pinokio/.installed` - A successful Pinokio install writes the owner-only `pinokio/.installed`
marker. The nested launcher menu resolves that marker from its own directory: marker. The nested launcher menu resolves that marker from its own directory:
+7 -1
View File
@@ -163,8 +163,14 @@ export function streetFootprint(street) {
}; };
} }
// Rungs built without their own tiles share one outline source, so a second
// resolver instance cannot add another outline cache to the tile budget.
let defaultOutlineTiles = null;
const sharedOutlineTiles = () =>
(defaultOutlineTiles ??= createOpenFreeMapOutlineSource());
export function createOutlineRungs({ export function createOutlineRungs({
tiles = createOpenFreeMapOutlineSource(), tiles = sharedOutlineTiles(),
nominatim = createNominatimOutlineClient(), nominatim = createNominatimOutlineClient(),
} = {}) { } = {}) {
/** Decoded tiles around a point, or null when the tiles cannot be read. */ /** Decoded tiles around a point, or null when the tiles cannot be read. */
+50
View File
@@ -154,6 +154,56 @@ test('a street comes from tiles before the configured ladder, as merged ribbons'
assert.equal(nominatim.asks.length, 0, 'streets never reach Nominatim'); assert.equal(nominatim.asks.length, 0, 'streets never reach Nominatim');
}); });
test('rungs built without their own tiles share one outline tile cache', async (t) => {
const tileRequests = [];
const bytes = (y) =>
readFileSync(
new URL(
`../data/fixtures/ofm-outlines-austin-14-3743-${y}.pbf`,
import.meta.url,
),
);
t.mock.method(globalThis, 'fetch', async (url) => {
const href = String(url);
if (href.endsWith('/planet'))
return Response.json({
tiles: [
'https://tiles.openfreemap.org/planet/shared-test/{z}/{x}/{y}.pbf',
],
});
tileRequests.push(href);
const y = href.match(/\/(\d+)\.pbf$/)?.[1];
return new Response(y === '6746' ? bytes(6746) : bytes(6745));
});
const ask = () =>
ctx({
scope: 'street',
target: 'Congress Avenue',
matchName: 'Congress Avenue',
});
const first = await createOutlineRungs({
nominatim: fakeNominatim(null),
}).resolve(ask(), ladder(UNAVAILABLE));
assert.ok(first.ring.length > 6);
const fetched = tileRequests.length;
assert.ok(fetched > 0);
const second = await createOutlineRungs({
nominatim: fakeNominatim(null),
}).resolve(ask(), ladder(UNAVAILABLE));
assert.ok(second.ring.length > 6);
assert.equal(
tileRequests.length,
fetched,
'a second rung set reuses the shared outline tiles',
);
const own = fixtureTiles();
await createOutlineRungs({
tiles: own,
nominatim: fakeNominatim(null),
}).resolve(ask(), ladder(UNAVAILABLE));
assert.equal(own.asked.length, 1, 'explicit tiles are still used');
});
test('a street the tiles do not name falls through to the ladder', async () => { test('a street the tiles do not name falls through to the ladder', async () => {
const run = ladder(UNAVAILABLE); const run = ladder(UNAVAILABLE);
const result = await createOutlineRungs({ const result = await createOutlineRungs({
+8 -5
View File
@@ -15,15 +15,18 @@ export function ringAreaM2(ring) {
} }
/** /**
* Join line pieces whose ends meet (within `toleranceM`) into as few chains as * Join line pieces whose ends meet (closer than `toleranceM`, or at most it
* possible. Each chain grows greedily from the first unused piece. * when `inclusive`) into as few chains as possible. Each chain grows greedily
* from the first unused piece.
*/ */
export function stitchLines( export function stitchLines(
segments, segments,
{ toleranceM = 2, maxChains = Infinity } = {}, { toleranceM = 2, inclusive = false, maxChains = Infinity } = {},
) { ) {
const same = (a, b) => const same = (a, b) => {
approximateDistanceM(a[1], a[0], b[1], b[0]) < toleranceM; const d = approximateDistanceM(a[1], a[0], b[1], b[0]);
return inclusive ? d <= toleranceM : d < toleranceM;
};
const remaining = segments.map((s) => s.slice()); const remaining = segments.map((s) => s.slice());
const chains = []; const chains = [];
while (remaining.length && chains.length < maxChains) { while (remaining.length && chains.length < maxChains) {
+1 -1
View File
@@ -383,7 +383,7 @@ export function streetFromTiles(
if (!pieces.length) return null; if (!pieces.length) return null;
const chains = stitchLines( const chains = stitchLines(
pieces.filter((piece) => piece.length >= 2), pieces.filter((piece) => piece.length >= 2),
{ toleranceM: JOIN_TOLERANCE_M }, { toleranceM: JOIN_TOLERANCE_M, inclusive: true },
) )
.map((line) => ({ line, length: lengthM(line) })) .map((line) => ({ line, length: lengthM(line) }))
.filter((entry) => entry.length >= STREET_MIN_CHAIN_M) .filter((entry) => entry.length >= STREET_MIN_CHAIN_M)
+25
View File
@@ -61,6 +61,14 @@ test('street names compare with abbreviations and a leading direction only', ()
assert.ok(!streetNameMatches('कुल मार्ग', 'काली मार्ग')); assert.ok(!streetNameMatches('कुल मार्ग', 'काली मार्ग'));
assert.ok(streetNameMatches('काली मार्ग', 'काली मार्ग')); assert.ok(streetNameMatches('काली मार्ग', 'काली मार्ग'));
assert.ok(streetNameMatches('Champs-Élysées', 'Champs Elysees')); assert.ok(streetNameMatches('Champs-Élysées', 'Champs Elysees'));
// Japanese: dakuten and handakuten are kept, so these stay distinct.
assert.ok(!streetNameMatches('ハシ通り', 'バシ通り'));
assert.ok(!streetNameMatches('ハシ通り', 'パシ通り'));
assert.ok(streetNameMatches('表参道', '表参道'));
// Thai: vowel and tone marks are kept.
assert.ok(!streetNameMatches('ถนนสุขุมวิท', 'ถนนสุขมวท'));
assert.ok(!streetNameMatches('ถนนข้าวสาร', 'ถนนขาวสาร'));
assert.ok(streetNameMatches('ถนนสุขุมวิท', 'ถนนสุขุมวิท'));
}); });
test('same-name segments merge into polylines around the point (Congress Avenue)', () => { test('same-name segments merge into polylines around the point (Congress Avenue)', () => {
@@ -112,6 +120,23 @@ test('merge joins reversed and out-of-order pieces and keeps gaps apart', () =>
[0.011, 0], [0.011, 0],
]; // separate ]; // separate
const chains = stitchLines([b, c, a], { toleranceM: 3 }); const chains = stitchLines([b, c, a], { toleranceM: 3 });
test('stitchLines joins at exactly the tolerance only when inclusive', () => {
const a = [
[0, 0],
[0.001, 0],
];
const b = [
[0.00102, 0],
[0.002, 0],
];
const gap = approximateDistanceM(0, 0.001, 0, 0.00102);
assert.equal(
stitchLines([a, b], { toleranceM: gap, inclusive: true }).length,
1,
);
assert.equal(stitchLines([a, b], { toleranceM: gap }).length, 2);
});
assert.equal(chains.length, 2); assert.equal(chains.length, 2);
assert.equal(chains.find((ch) => ch.length === 3).length, 3); assert.equal(chains.find((ch) => ch.length === 3).length, 3);
}); });