The sky
Sun altitude, moon altitude, azimuth and phase, computed from the frame's own time and place. Shown the moon's position once, the model stopped arguing for moonrise.
A vision model looks at a frame only after satellite heat earns the look. It is handed the sky as computed fact, asked for the signal that sky makes possible, and believed only when a second, independent check agrees.
In daylight a fire scatters light and reads as a smoke column. After dark it emits, and reads as a glow. Asking for a smoke column at night returned “likely moon or light glare” on a frame with open flame in it, so the prompt now asks for what can physically be seen.
The model’s doubts are only useful when it can resolve them. Whether the bright thing could be the moon is arithmetic, so the arithmetic is done first and handed over.
Sun altitude, moon altitude, azimuth and phase, computed from the frame's own time and place. Shown the moon's position once, the model stopped arguing for moonrise.
Every settlement over about 500 people in view, by name, bearing, range and population. A glow with no town on its bearing has one less innocent explanation.
Where in the frame the thermal bearing lands, so the model looks where the heat is instead of describing the whole horizon.
The settlement list stops near 500 people. An isolated mine, a lit yard or a vehicle is not in it, and the record says so instead of implying the check was exhaustive.
The model must claim a signal, and the bearing implied by its plume-base pixel must agree with the bearing from that camera to the thermal footprint. Either alone is not enough.
A night frame publishes only when every innocent explanation the system can compute has been ruled out, server-side, against the bearing the pixels actually produced.
The saved record then says what happened in plain terms: seen after dark as glow, moon below the horizon, no populated place in view. A night observation is never written back as a smoke measurement, and never as a heat measurement.
The rules on this page live in the vision route, sky.ts, night-lights.ts, bearing-alignment.ts and night-corroboration.ts. Where the page and the code disagree, the code is right.