Number the stars the archive places after their host's name, so a refresh keeps each one's id

4c8e4a0 numbered each star it adds from the Exoplanet Archive by its place among the unmatched
hosts, in pl_name order, and the refresh workflow re-queries the archive every Monday. One host
added or dropped ahead of another renumbers it: in the review, removing a single planet row
renamed 3 276 of the 3 277 ids, and a bookmark kept on Kepler-186 (1070001620) opened Kepler-1860
under Kepler-186's stored name. HYG's and Gaia's ids do not move between refreshes; the merge's own
comment says ids are meant to hold.

archiveStarId (host-star-matching.ts, beside the matcher the ETL already imports from there) hashes
the host name with FNV-1a into the 3.7 million ids between 1 070 000 000 and 2^30, and moves a name
whose id is taken to the next free one. The added stars are sorted by id before they are appended,
so the published list stays in id order. Measured: all 4 237 archive-hosted planets change host id
once (Kepler-186 is now 1073671518), none of the others; one of the 3 277 names was probed past a
collision, and one new id falls in the old 1070000000-1070003276 range, so a bookmark saved on that
old id would open the wrong star once. Dropping the same row from a copy of the cached answer and
rerunning the exoplanet step in a scratch copy of the ETL now leaves 3 276 of 3 276 ids unchanged.
The validators pass: no duplicate id, all under 2^30.

Controls, each failing its named test: the id taken from the order of arrival, and no probing past
a taken id (1 of 801 each).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-29 21:12:00 +02:00
co-authored by Claude Opus 5.5
parent 1a8e734651
commit 62f81f2c43
7 changed files with 53 additions and 13 deletions
@@ -171,3 +171,30 @@ export function resolveHostStarId(
return best ? best.id : null;
}
/**
* Where the ids of the stars only the archive places begin: past Gaia's two ranges, and under
* the 2^30 `validateStars` holds every id to — which leaves 3.7 million.
*/
export const ARCHIVE_ID_BASE = 1_070_000_000;
const ARCHIVE_ID_RANGE = 2 ** 30 - ARCHIVE_ID_BASE;
/**
* The id of a star the ETL places from the archive, from its host's name rather than from its
* place in the answer. Numbered in pl_name order, a refresh that added or dropped one host
* renumbered every host after it — one row dropped renamed 3 276 of 3 277 ids, and a bookmark kept
* on Kepler-186 opened Kepler-1860 — while HYG's and Gaia's ids hold. FNV-1a over the name, into
* the range above; a name whose id is taken takes the next free one, the one case a refresh can
* still move, and only between the two names that collided.
*/
export function archiveStarId(hostname: string, taken: ReadonlySet<number>): number {
let hash = 0x811c9dc5;
for (let i = 0; i < hostname.length; i++) {
hash = Math.imul(hash ^ hostname.charCodeAt(i), 0x01000193) >>> 0;
}
let offset = hash % ARCHIVE_ID_RANGE;
while (taken.has(ARCHIVE_ID_BASE + offset)) {
offset = (offset + 1) % ARCHIVE_ID_RANGE;
}
return ARCHIVE_ID_BASE + offset;
}