Answer the review: direction settles distance, brightness is one-sided, and a lost id stops the scene

Three findings from the adversarial review of the merge, all reproduced.

The distance test was hiding 1 489 stars that sit under an arcsecond from
their Gaia entry with a Hipparcos parallax off by half — thirty of them at a
false few parsecs from the Sun (HIP 82724 at 3.7 pc, where Gaia has it at
62.8) — and the first audit did not see them because it counted residual
doubles through the same 50 % filter. Under three arcseconds the distances
are now not consulted: a coincidence of direction that close is never chance
at this depth (the quarter-degree shift finds none), and the parallax is the
thing to fix. Brightness keeps its say at any separation, and is now
one-sided: a folded entry may be five magnitudes fainter (a red dwarf in V
against G) but not one brighter, because an entry a magnitude brighter than
what is already at that spot is a primary Gaia does not carry — Almach,
Alfirk and Ashlesha had all been folded into their companions' entries,
93 in all. The sky grid wraps at 0h.

The Gaia query orders by source_id after G, so the row order — and the ids
assigned from it — is a function of the archive's content rather than of the
server's plan for 20 064 ties; the cache key is a hash of the query.

And a bookmark to a star id the catalogue no longer holds — 56 000 Gaia ids
change with this — sent the scene through reconcileSelection, enterSystem,
its decline, finishTransition and reconcileSelection again until the stack
overflowed. The selection is cleared instead, at the one place every path
goes through.

Regenerated: 423 641 stars, 57 512 HYG identities on Gaia positions, no HYG
id or name lost, no star within 20 pc left with an unclaimed Gaia entry under
an arcsecond. 403 HYG survivors still have an unclaimed Gaia entry within
60": 13 under an arcsecond, where the brightness guard does not trust HYG's
magnitude, and the rest components 3" to 60" from their counterpart.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QL6F9Bgfh8SgAiAAcPB9Hw
This commit is contained in:
2026-08-28 21:20:45 +02:00
co-authored by Claude Fable 5
parent 08534279fb
commit dc2ce08694
10 changed files with 116 additions and 31 deletions
+10 -5
View File
@@ -1,3 +1,5 @@
import { createHash } from 'node:crypto';
import { propagateProperMotion, raDegDecDistanceToXyz } from '../../../src/app/shared/astro/coordinates';
import { StarRecord } from '../../../src/app/shared/models/star.model';
import { parseCsvObjects, parseOptionalNumber } from '../lib/csv';
@@ -59,7 +61,9 @@ function buildQuery(): string {
`where parallax > ${parallaxFloorMas(DISTANCE_CUTOFF_PC).toFixed(6)}`,
`and parallax_over_error > ${(1 / MAX_PARALLAX_ERROR_RATIO).toFixed(1)}`,
`and phot_g_mean_mag < ${MAGNITUDE_LIMIT}`,
'order by phot_g_mean_mag asc'
// source_id breaks the ties — 20 064 groups share a G at the published precision — so the
// row order, and with it the ids assigned below, is a pure function of the archive's content.
'order by phot_g_mean_mag asc, source_id asc'
].join(' ');
}
@@ -79,12 +83,13 @@ const UNKNOWN_SPECTRAL_TYPE = 'Unknown';
const GAIA_ID_BASE = 1_000_000_000;
export async function fetchGaiaStars(): Promise<StarRecord[]> {
const url = `${GAIA_TAP_URL}?REQUEST=doQuery&LANG=ADQL&FORMAT=csv&QUERY=${encodeURIComponent(buildQuery())}`;
const query = buildQuery();
const url = `${GAIA_TAP_URL}?REQUEST=doQuery&LANG=ADQL&FORMAT=csv&QUERY=${encodeURIComponent(query)}`;
console.log(`Fetching Gaia DR3 (within ${DISTANCE_CUTOFF_PC} pc, G < ${MAGNITUDE_LIMIT}, at most ${ROW_LIMIT} rows)...`);
// The cache key names the columns, so a response cached before proper motions were asked for
// cannot be mistaken for one that has them.
const csv = await fetchTextCached(url, 'gaia-dr3-pm.csv');
// Keyed by the query itself, so a response cached for other columns or another order can
// never be mistaken for this one.
const csv = await fetchTextCached(url, `gaia-dr3-${createHash('sha1').update(query).digest('hex').slice(0, 8)}.csv`);
const rows = parseCsvObjects(csv);
const stars: StarRecord[] = [];