fix(hud): keep English out of localized summaries, cap ja/zh by characters only

Second follow-up review fixes:

- Japanese and Chinese summaries are capped at 20 characters only, without
  the five-token cut first, and the cap steps back to a space instead of
  splitting a Latin word.
- The HUD request sends localized layer names in feedProvenance too and
  leaves the English narration note out outside English. A non-English reply
  that still echoes a feed-state id or a translated English layer name falls
  back to the deterministic line.
- A camera move during typing shows the deterministic line, not a fragment.
- A view with no place labels and no enabled layer does not ask the model.
- Behaviour tests on IntelHUD replace the regex checks of hud.js; docs and
  the instruction wording updated.
This commit is contained in:
German Khokhlov committed 2026-10-30 16:28:56 +04:00
1 parent 7b223d7d7b
commit 7713fb8ae8
8 files changed
+328 -60

No files matched your search

+11 -27
View File
@@ -255,33 +255,6 @@ test('the instructions name the UI language, with English as the fallback', () =
assert.equal(hudSummaryLocale(42), 'en');
});
test('the HUD sends its UI locale inside the context it signs for dedupe', () => {
const hud = readFileSync(new URL('./hud.js', import.meta.url), 'utf8');
assert.match(hud, /locale: getLocale\(\),\s+placeLabels:/);
assert.match(hud, /const signature = JSON\.stringify\(context\);/);
// The model gets the layer names the user sees.
assert.match(
hud,
/enabledLayerLabels:\s+layerContext\.enabledLayerLabels\.map\(localizeLayerName\)/,
);
});
test('the state word leads and the layer names trail the one-line summary', () => {
const hud = readFileSync(new URL('./hud.js', import.meta.url), 'utf8');
assert.match(
hud,
/return \[state, text, layers\]\.filter\(Boolean\)\.join\(' \| '\);/,
);
assert.match(hud, /withProvenance\(\s*data\.summary,/);
assert.match(hud, /return withProvenance\(line, provenance\);/);
// The model sees only the layer names the user sees.
assert.match(hud, /name: localizeLayerName\(layer\.name\)/);
assert.match(
HUD_SUMMARY_INSTRUCTIONS,
/Name layers only as in enabledLayerLabels/,
);
});
test('shipped catalogs get their exact language, and CJK a character limit', () => {
assert.match(hudSummaryInstructions('pt'), /in Brazilian Portuguese \(pt\)/);
assert.match(
@@ -397,6 +370,17 @@ for (const [locale, summary] of [
});
}
test('a ja cap steps back to a space instead of cutting a Latin word', async () => {
const { response } = await postHudSummary(
{ locale: 'ja', feedProvenance: { overall: 'stale' } },
JSON.stringify({
summary: 'San Francisco Bay Area flights',
feedState: 'stale',
}),
);
assert.equal(response.body.summary, 'San Francisco Bay');
});
test('a reply that skips the format carries no summary and no state', async () => {
const { response } = await postHudSummary(
{ locale: 'ru', feedProvenance: { overall: 'stale' } },