docs: tighten the display-text notes

Name routeId among the canonical analyst IDs in CURRENT-STATE, say what the
changelog entry changes for users, and drop the comment that repeated the
canonical-field doc.
This commit is contained in:
German Khokhlov committed 2026-11-10 15:34:32 +04:00
1 parent 3521c96172
commit 12a5630991
4 files changed
+15 -18

No files matched your search

+3 -1
View File
@@ -1 +1,3 @@
- Bound untrusted display text at output boundaries (asturksever, #1280).
- Keep outside text in voice and MCP tool results to one line of 180
characters: ALPR tags, station names and other display fields (asturksever,
#1280).
+7 -10
View File
@@ -137,16 +137,13 @@ Stale fallback runs per response after the reservation is released, and disk
writes finish asynchronously. Settled and rejected reservations are removed
only while they still own their map entry.
External ALPR tags, surveillance-tool display fields, voice context text and
compact analyst strings collapse controls and whitespace before a final
180-character cap (scene labels retain their 120-character cap). Empty ALPR
values remain null and Unicode text is preserved without splitting a surrogate
pair. Only display fields are normalized: canonical analyst identifiers
(`id`, `layerKey`, `icao24`, `mmsi`, `noradId`, `registration`, `callsign`)
pass through unchanged, because bikeshare uses the raw station name as its ID
and numbered voice references resolve by that key. These fields remain
untrusted source data in structured tool output; text normalization does not
establish trust or eliminate prompt injection.
External ALPR tags, surveillance-tool fields, voice context text and compact
analyst strings become one line of at most 180 characters (scene labels: 120).
Empty ALPR values stay null, and the cap never splits a surrogate pair.
Canonical analyst identifiers such as `id` and `routeId` stay unchanged, because
voice follow-ups match on them and bikeshare uses the raw station name as its
ID. The text is still untrusted: normalization does not prevent prompt
injection.
Terrain height requests accept at most 64 points, matching the browser service's
existing batch size and one bounded upstream chunk. Larger requests return HTTP
+1 -1
View File
@@ -1,4 +1,4 @@
/** Bounded, single-line external display text; it remains untrusted source data. */
/** One-line text capped at `maxLength` without splitting a surrogate pair. Still untrusted. */
export function normalizeDisplayText(value, maxLength = 180) {
if (value == null || typeof value === 'object' || typeof value === 'function')
return '';
+4 -6
View File
@@ -5353,9 +5353,9 @@ const ANALYST_IDENTITY_FIELDS = Object.freeze([
]);
/**
* Analyst item keys that identify a record rather than describe it: the
* referent registry, track_entity and locateLayerEntity match on them, so
* display-text normalization must leave them byte-for-byte unchanged.
* Keys that identify an analyst record. The referent registry, track_entity,
* locateLayerEntity and follow-up filters match on them, so they skip
* display-text normalization.
*/
const ANALYST_CANONICAL_FIELDS = new Set([
'layerKey',
@@ -5405,9 +5405,7 @@ function compactAnalystItem(r) {
} else compact[key] = r[key];
}
if (present(r.ageHours)) compact.ageHours = r.ageHours;
// Display text only: canonical keys are lookup identities (bikeshare uses
// the raw station name as its id), so the referent registry and
// locateLayerEntity must see them exactly as the layer reports them.
// Canonical keys stay raw: bikeshare's id is the raw station name.
for (const key of Object.keys(compact)) {
if (typeof compact[key] === 'string' && !ANALYST_CANONICAL_FIELDS.has(key))
compact[key] = normalizeDisplayText(compact[key]);