Files
gods-eye-view/src/data/detectionCohort.js
T
Sameh Khamis 73e789489b chore: drop exports nothing imports
Knip, configured with the application, package exports, scripts, QA
harnesses, workers, tools and tests as entry points, reports exports
that no module imports. Each was checked by hand against string-based
and namespace imports.

- Symbols that are still used inside their own module lose only the
  `export` keyword (176 constants and helpers).
- Unused re-exports are removed from barrel modules (flight, military,
  vessel, CCTV, directions, transit history, local ADS-B and street-level
  policy modules).
- Declarations that nothing uses at all are deleted, among them
  AIS_WATCHDOG_STATUSES, applyFilter, isRadioCountryCode, compactText,
  DENSITY_STOPS, the unused CCTV endpoint constants, and the SDR band
  constants.
- Default exports that nothing imports are removed. The ones in
  src/data/earthquakes.js, src/data/telegeographySubmarineCables.js,
  src/data/wind.js and src/data/bhoteKoshiLocator.js each constructed a
  layer instance at import time that nothing used; those instances are
  no longer created.

Every export of a package.json entry stays, as does TOMTOM_CREDIT,
which the traffic layer reads from the credits namespace it is given.
2026-10-22 19:00:40 -07:00

126 lines
3.6 KiB
JavaScript

const DEFAULT_MAX_COHORT = 256;
/** Resolve the review-mandated bounded materialization cap for a layer quota. */
export function cohortCapForQuota(quota) {
const normalized = Math.max(0, Math.floor(Number(quota) || 0));
return Math.min(DEFAULT_MAX_COHORT, Math.max(64, normalized * 4));
}
/** Stable FNV-1a identity hash used only on solve ticks. */
export function stableIdentityHash(layerId, sourceId) {
const text = `${String(layerId)}\u0000${String(sourceId)}`;
let hash = 2166136261;
for (let i = 0; i < text.length; i++) {
hash ^= text.charCodeAt(i);
hash = Math.imul(hash, 16777619);
}
return hash >>> 0;
}
/** Negative means a is a better deterministic contender than b. */
function compareCohortContenders(a, b) {
const priorityDelta =
(Number(b?._cohortPriority) || 0) - (Number(a?._cohortPriority) || 0);
if (priorityDelta) return priorityDelta;
const bandDelta =
(Number(b?._cohortBand) || 0) - (Number(a?._cohortBand) || 0);
if (bandDelta) return bandDelta;
const hashDelta =
(Number(a?._cohortHash) >>> 0) - (Number(b?._cohortHash) >>> 0);
if (hashDelta) return hashDelta;
return String(a?._cohortSourceId).localeCompare(String(b?._cohortSourceId));
}
function isWorse(a, b) {
return compareCohortContenders(a, b) > 0;
}
/**
* Streaming deterministic contender reservoir. The heap retains at most 256
* non-incumbents per layer, so a 12k-object scan never creates or sorts a full
* rich-candidate population.
*/
export class BoundedCohort {
constructor(maxSize = DEFAULT_MAX_COHORT, hardMax = DEFAULT_MAX_COHORT) {
const ceiling = Math.max(
1,
Math.floor(Number(hardMax) || DEFAULT_MAX_COHORT),
);
this.maxSize = Math.max(
1,
Math.min(ceiling, Math.floor(Number(maxSize) || DEFAULT_MAX_COHORT)),
);
this.incumbents = [];
this.heap = [];
}
consider(observation, incumbent = false) {
if (!observation) return;
if (incumbent) {
this.incumbents.push(observation);
return;
}
if (this.heap.length < this.maxSize) {
this.heap.push(observation);
this._bubbleUp(this.heap.length - 1);
return;
}
if (compareCohortContenders(observation, this.heap[0]) >= 0) return;
this.heap[0] = observation;
this._siftDown(0);
}
values(limit = this.maxSize) {
const cap = Math.max(
0,
Math.min(this.maxSize, Math.floor(Number(limit) || 0)),
);
const incumbents = this.incumbents
.slice()
.sort(compareCohortContenders)
.slice(0, cap);
const remaining = Math.max(0, cap - incumbents.length);
if (remaining === 0) return incumbents;
const contenders = this.heap
.slice()
.sort(compareCohortContenders)
.slice(0, remaining);
return incumbents.concat(contenders);
}
_bubbleUp(index) {
let current = index;
while (current > 0) {
const parent = Math.floor((current - 1) / 2);
if (!isWorse(this.heap[current], this.heap[parent])) break;
[this.heap[current], this.heap[parent]] = [
this.heap[parent],
this.heap[current],
];
current = parent;
}
}
_siftDown(index) {
let current = index;
while (true) {
const left = current * 2 + 1;
const right = left + 1;
let worst = current;
if (left < this.heap.length && isWorse(this.heap[left], this.heap[worst]))
worst = left;
if (
right < this.heap.length &&
isWorse(this.heap[right], this.heap[worst])
)
worst = right;
if (worst === current) return;
[this.heap[current], this.heap[worst]] = [
this.heap[worst],
this.heap[current],
];
current = worst;
}
}
}