mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
Merge upstream/main into PR #1042
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
commit
25f5812e10
4 files changed
+60
-6
No files matched your search
+1
-1
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
- Recent Imagery continues past malformed records in full catalog pages, respects the requested record limit, and reports results as truncated when that limit drops valid records.
|
- Recent Imagery continues past malformed records in full catalog pages, respects the requested record limit, and reports results as truncated when that limit drops valid records.
|
||||||
|
|
||||||
- Reject impossible FIRMS acquisition calendar days in the CSV parser before trailing-24-hour filtering.
|
- Regional articles retain unknown publication times when compact source dates do not identify a real calendar instant.
|
||||||
|
|
||||||
- Treat explicitly current, complete empty vessel coverage as a successful update,
|
- Treat explicitly current, complete empty vessel coverage as a successful update,
|
||||||
clearing obsolete contacts while retaining stale or incomplete snapshots.
|
clearing obsolete contacts while retaining stale or incomplete snapshots.
|
||||||
|
|||||||
@@ -1177,7 +1177,9 @@ stalled downloads are cancelled. Development and preview use the same handler.
|
|||||||
Overpass query validation, geometry simplification, disk caching and upstream
|
Overpass query validation, geometry simplification, disk caching and upstream
|
||||||
transport now have separate modules; military-installation search reuses that
|
transport now have separate modules; military-installation search reuses that
|
||||||
transport. Regional briefing combines separate place, news and weather sources,
|
transport. Regional briefing combines separate place, news and weather sources,
|
||||||
while weather effects uses only the weather source. Existing process-scoped
|
while weather effects uses only the weather source.
|
||||||
|
GDELT compact dates that do not name a real calendar instant keep the article
|
||||||
|
with an unknown publication time. Existing process-scoped
|
||||||
caches, rate limits, stale fallbacks and route ordering are preserved.
|
caches, rate limits, stale fallbacks and route ordering are preserved.
|
||||||
|
|
||||||
Local voice has separate HUD-summary, debug-log and Realtime-token handlers,
|
Local voice has separate HUD-summary, debug-log and Realtime-token handlers,
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import test from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { normalizeRegionalArticles } from './regionalModel.js';
|
||||||
|
test('compact source dates must denote an actual calendar instant', () => {
|
||||||
|
for (const date of [
|
||||||
|
'20260230T120000Z',
|
||||||
|
'20260431T120000Z',
|
||||||
|
'20261301T120000Z',
|
||||||
|
'20260716T240000Z',
|
||||||
|
'20260716T126000Z',
|
||||||
|
'20260716T120060Z',
|
||||||
|
]) {
|
||||||
|
const [article] = normalizeRegionalArticles({
|
||||||
|
articles: [
|
||||||
|
{
|
||||||
|
title: 'Fixture',
|
||||||
|
url: 'https://fixture.example/news',
|
||||||
|
seendate: date,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
assert.equal(article.publishedAt, null, date);
|
||||||
|
assert.equal(article.title, 'Fixture');
|
||||||
|
}
|
||||||
|
for (const [input, expected] of [
|
||||||
|
['20240229T004500Z', '2024-02-29T00:45:00Z'],
|
||||||
|
['20260716T000000Z', '2026-07-16T00:00:00Z'],
|
||||||
|
['2026-07-16T12:00:00Z', '2026-07-16T12:00:00.000Z'],
|
||||||
|
]) {
|
||||||
|
assert.equal(
|
||||||
|
normalizeRegionalArticles({
|
||||||
|
articles: [
|
||||||
|
{
|
||||||
|
title: 'Fixture',
|
||||||
|
url: 'https://fixture.example/news',
|
||||||
|
seendate: input,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})[0].publishedAt,
|
||||||
|
expected,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -67,11 +67,20 @@ export function normalizeRegionalArticles(payload, limit = MAX_ARTICLES) {
|
|||||||
seen.add(signature);
|
seen.add(signature);
|
||||||
const rawDate = cleanText(row?.seendate, 32);
|
const rawDate = cleanText(row?.seendate, 32);
|
||||||
const compactDate = /^(\d{8})T(\d{6})Z$/.exec(rawDate);
|
const compactDate = /^(\d{8})T(\d{6})Z$/.exec(rawDate);
|
||||||
const publishedAt = compactDate
|
const candidateDate = compactDate
|
||||||
? `${compactDate[1].slice(0, 4)}-${compactDate[1].slice(4, 6)}-${compactDate[1].slice(6, 8)}T${compactDate[2].slice(0, 2)}:${compactDate[2].slice(2, 4)}:${compactDate[2].slice(4, 6)}Z`
|
? `${compactDate[1].slice(0, 4)}-${compactDate[1].slice(4, 6)}-${compactDate[1].slice(6, 8)}T${compactDate[2].slice(0, 2)}:${compactDate[2].slice(2, 4)}:${compactDate[2].slice(4, 6)}Z`
|
||||||
: Number.isNaN(Date.parse(rawDate))
|
: rawDate;
|
||||||
? null
|
const parsedMs = Date.parse(candidateDate);
|
||||||
: new Date(rawDate).toISOString();
|
const validDate =
|
||||||
|
Number.isFinite(parsedMs) &&
|
||||||
|
(!compactDate ||
|
||||||
|
new Date(parsedMs).toISOString().slice(0, 19) ===
|
||||||
|
candidateDate.slice(0, 19));
|
||||||
|
const publishedAt = validDate
|
||||||
|
? compactDate
|
||||||
|
? candidateDate
|
||||||
|
: new Date(parsedMs).toISOString()
|
||||||
|
: null;
|
||||||
articles.push({
|
articles.push({
|
||||||
title,
|
title,
|
||||||
url,
|
url,
|
||||||
|
|||||||
Reference in new issue
Block a user