Files
gods-eye-view/src/layers/cctv/headingConfidence.test.mjs
T
bassem chagra 5f27f6edf4 fix(cctv): surface heading confidence — estimated bearings are now visible
Every pack sets headingConfidence on each camera, but nothing consumed it:
a bearing synthesized by fallbackHeadingFromId (a hash of the id string,
no geographic input) rendered exactly like a surveyed one — 2,827 of 3,997
cameras in a default catalog. Fixes #639.

Two consumers, plus a passthrough:

- HUD: the heading token is tagged when the bearing is synthetic —
  `HDG 194° (ESTIMATED)` — so a hash never reads as a measured facing.
- Wireframe: a low-confidence camera draws its coverage frustum with dashed
  polylines instead of solid ones. Colors, widths, and the active/idle
  emphasis are unchanged; the dash is the only signal.
- Public camera state gains `headingConfidence` (the raw pack flag) and
  `headingEstimated` (the derived bit) so UI consumers never re-derive it.

A human-vouched pose always wins over the pack flag: a manually saved
calibration (calSource:'manual') or a curated catalog entry
(poseSource:'curated') is never presented as estimated, mirroring the CAL
badge states in calibration.js.

- src/layers/cctv/headingConfidence.js: pure helpers (isHeadingEstimated,
  headingHudToken)
- src/layers/cctv/headingConfidence.test.mjs: confidence normalization,
  calibration/curation overrides, HUD token formatting
- src/layers/cctv/presentation.js: HUD token + public-state passthrough
- src/layers/cctv/rendering.js: dashed materials for estimated bearings
2026-09-17 10:20:26 +02:00

61 lines
2.0 KiB
JavaScript

// src/layers/cctv/headingConfidence.test.mjs
// Bearing-provenance consumers (#639): a pack's headingConfidence:'low'
// (a hashed synthetic bearing) must present as estimated — unless a human
// vouched for the pose via manual calibration or a curated catalog entry.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { isHeadingEstimated, headingHudToken } from './headingConfidence.js';
test('low confidence marks the bearing estimated', () => {
assert.equal(isHeadingEstimated({ headingConfidence: 'low' }), true);
});
test('confidence matching is trimmed and case-insensitive', () => {
assert.equal(isHeadingEstimated({ headingConfidence: ' LOW ' }), true);
assert.equal(isHeadingEstimated({ headingConfidence: 'Low' }), true);
});
test('medium, high, missing, and absent cameras are not estimated', () => {
assert.equal(isHeadingEstimated({ headingConfidence: 'medium' }), false);
assert.equal(isHeadingEstimated({ headingConfidence: 'high' }), false);
assert.equal(isHeadingEstimated({}), false);
assert.equal(isHeadingEstimated(null), false);
assert.equal(isHeadingEstimated(undefined), false);
});
test('a manually saved calibration overrides a low pack flag', () => {
assert.equal(
isHeadingEstimated({ headingConfidence: 'low', calSource: 'manual' }),
false,
);
});
test('a curated catalog entry overrides a low pack flag', () => {
assert.equal(
isHeadingEstimated({ headingConfidence: 'low', poseSource: 'curated' }),
false,
);
});
test('HUD token tags a synthetic bearing and rounds the degrees', () => {
assert.equal(
headingHudToken({ headingDeg: 194.4, headingConfidence: 'low' }),
'HDG 194° (ESTIMATED)',
);
});
test('HUD token stays untagged for surveyed and calibrated bearings', () => {
assert.equal(
headingHudToken({ headingDeg: 67.5, headingConfidence: 'high' }),
'HDG 68°',
);
assert.equal(
headingHudToken({
headingDeg: 225,
headingConfidence: 'low',
calSource: 'manual',
}),
'HDG 225°',
);
});