# Defect: Windows scan timestamps lose their UTC offset ## Status Open and reproducible in the accepted Windows worker package validated on 2026-09-25. The live validation did not modify product code so that the tested package remained identical to the accepted artifact. ## Symptom Windows `scan.result_error` diagnostics can be stored with `occurred_at` about the machine's local UTC offset in the future. In the validation environment the offset was approximately three hours. The same naive timestamps also populate Windows `target_scans.started_at` and `target_scans.ended_at`. This can misorder diagnostics, distort time-window filters, and make the admin panel show a scan event later than the server receipt that contains it. ## Live evidence The accepted Windows package ran with a fresh state directory and one slot. In the expanded live cohort, all 45 Windows `scan.result_error` diagnostics had an `occurred_at` to server `received_at` delta between approximately 10,816 and 10,819 seconds. All 135 normal Windows scan-result rows used naive local start and end timestamps with the same approximately three-hour displacement when treated as UTC. The four Windows timeout-path rows and all 102 Linux rows had normal small timing deltas. The retained raw scanner material contained an explicit `+03:00` timestamp. The persisted diagnostic retained the same wall-clock digits but labeled them as UTC with `Z`. Monotonic scan durations and worker progress transport timestamps remained correct. Sensitive raw targets, scanner output, and credentials are retained only in the restricted live evidence file and are intentionally not reproduced here. ## Root cause `app/scanner.py` creates scan timestamps with naive local datetimes: - `scan_target_result()` uses `datetime.now().isoformat()` for `scan_started_at` and `timestamp` near lines 16339 and 16416. - fallback result construction in `scan_single_target()` does the same near lines 16844, 16863, and 16877. Diagnostic construction parses those values and, when no timezone is present, uses `occurred.replace(tzinfo=timezone.utc)` near line 16581. That operation relabels local wall-clock time as UTC instead of converting it. The error is visible on non-UTC hosts and is hidden on UTC Linux hosts. ## Expected behavior All persisted protocol timestamps must identify a real UTC instant. Scanner result timestamps should be emitted as timezone-aware UTC values, and legacy naive values must not be silently reinterpreted as known UTC instants. ## Suggested correction and regression coverage Emit `datetime.now(timezone.utc).isoformat()` at every result-construction site and preserve the offset through serialization. Add a non-UTC-host regression test that verifies: - scanner start/end timestamps identify the actual UTC instant; - diagnostic `occurred_at` precedes or closely tracks server `received_at`; - Windows and Linux admin time-window filters return the same logical events; - monotonic duration fields remain unchanged. ## Validation artifact The expanded unrestricted evidence is retained at `build/live-trace-20260925/raw-evidence-expanded.json`. It contains sensitive raw internals and must not be published as a general operator report.