fix(hud): state word first, layer names last; CJK cap by locale

Follow-up review fixes:

- The HUD line is STATE | text | LAYERS for the AI summary and the
  fallback line, so the narrow minimal and cyber layouts show both the
  warning and the summary. get_hud_caption builds its caption the same
  way. The unused "{state} {layers}" key is pruned from the catalogs.
- The 20-character cap applies only when the request locale is Japanese
  or Chinese; other languages keep five words around a Han place name.
- enabledLayers names are localized too, and the instructions name layers
  only from enabledLayerLabels, never from feedProvenance or its note.
- The keyless test restores GEV_RATELIMIT_OPENAI_PER_MIN again; comments
  and docs updated.
This commit is contained in:
German Khokhlov committed 2026-10-30 14:27:59 +04:00
1 parent f967218a04
commit 7b223d7d7b
17 files changed
+80 -51

No files matched your search

+30 -3
View File
@@ -164,6 +164,9 @@ test('the installed keyless HUD route stays successful after the voice quota is
} finally {
if (previousKey === undefined) delete process.env.OPENAI_API_KEY;
else process.env.OPENAI_API_KEY = previousKey;
if (previousLimit === undefined)
delete process.env.GEV_RATELIMIT_OPENAI_PER_MIN;
else process.env.GEV_RATELIMIT_OPENAI_PER_MIN = previousLimit;
}
});
@@ -263,10 +266,20 @@ test('the HUD sends its UI locale inside the context it signs for dedupe', () =>
);
});
test('the state tag leads the one-line summary so clipping cannot hide it', () => {
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, /tag \? `\$\{tag\} \| \$\{data\.summary\}`/);
assert.match(hud, /provenance \? `\$\{provenance\} \| \$\{line\}`/);
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', () => {
@@ -370,6 +383,20 @@ test('a Japanese summary is capped in characters, not words', async () => {
);
});
for (const [locale, summary] of [
['en', 'Shibuya 渋谷 live flights overhead'],
['es', 'Vuelos sobre 東京駅 datos antiguos'],
['ru', 'Башня Тайбэй 101 台北101 рейсы'],
]) {
test(`a ${locale} summary with a Han place name keeps its five words`, async () => {
const { response } = await postHudSummary(
{ locale, feedProvenance: { overall: 'stale' } },
JSON.stringify({ summary, feedState: 'stale' }),
);
assert.equal(response.body.summary, summary);
});
}
test('a reply that skips the format carries no summary and no state', async () => {
const { response } = await postHudSummary(
{ locale: 'ru', feedProvenance: { overall: 'stale' } },