Commit Graph
69 Commits
Author SHA1 Message Date
SenrokaiandClaude Opus 5.5 321540ed91 Merge the solar-system branch, so the star catalogue lands on the sky it now shares
Both branches changed the system view's star, the body card's provenance line, the exoplanet
fetch and the ETL's validators. Resolved by keeping both sides:

- The system view's star is the catalogue's (its own radius and temperature, a limb-darkened
  surface in its colour) and turns like a planet when it is the Sun (the solar branch's IAU pole
  and 25.38-day turn), keyed on SUN_STAR_ID, since the catalogue branch dropped the scene's own
  SOL_STAR_ID. Framing takes the outermost thing drawn (an eccentric orbit's aphelion, from the
  solar branch) and the star's radius for a giant (from the catalogue). The solar branch's comment
  about a halo is dropped: there has been none since #33.
- The card's no-temperature sentence is the catalogue's (the host's luminosity or the orbit's size,
  not "not in the catalogue", which holds for 27 planets) and ends with the solar branch's reason
  why no image is used (a point of light for the 101 imaged planets, none for the rest).
- fetchExoplanets reads the composite table and the distance errors (catalogue) and the imaged
  list (solar); build.ts runs both branches' validators.

The data were regenerated by the full ETL on the merged code, from cache (nothing refetched):
stars.bin, stars-meta.bin, stars-index.json and deepsky.json come out byte for byte the catalogue
branch's, bodies.json the solar branch's, and exoplanets.json the catalogue branch's but for the
imaged flag on 101 planets, WASP-108 b not among them. Unit suite 977 passed, the two branches'
870 and 837 over their shared 730, so no test was lost.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 22:07:34 +02:00
SenrokaiandClaude Opus 5.5 cea4ff799f Bring the counts the comments and README quote back to the catalogue
Measured on the published catalogue at this commit, through starSurfaceOf and starReadouts:

- star-readouts.ts said 11 546 derived radii read "from its type": 10 702 giants with a colour and
  844 stars with none. That left out the 26 dwarfs whose colour is off the table, and the colour
  Gaia now gives 931 HYG-described stars moved the rest: 10 953 = 10 713 giants with a colour,
  214 stars with none (GJ 3655 among them) and those 26. 5 more read "from its temperature".
- stellar.ts said 821 dwarfs are placed at their type's row. Counted over every star that is not a
  giant and whose colour the table does not read: 224 with no colour and 36 with one off the table.
- The README still said the card marks every derived radius "from colour and brightness"; it now
  names the three bases the card gives.
- build.ts's survivor breakdown, after θ¹ Ori A left: 11 464 HYG stars without a Gaia counterpart,
  8 307 of them past 250 pc, 1 660 of those naked-eye.

Comments and documentation only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 21:48:40 +02:00
SenrokaiandClaude Opus 5.5 74913d844d Place a naked-eye star by SIMBAD's name only within a magnitude of its source, and hold HD 45951 to it
e7c420b placed two naked-eye HYG rows along the Gaia source SIMBAD names them as. One of them,
θ¹ Ori A (HD 37020, HYG 26155), came with HYG's V 4.98 and O7, which are Hipparcos's for it and a
companion together: SIMBAD has θ¹ Ori A at V 6.73 and B0V, and its source at G 6.63. At 378 pc the
map drew it at 2.7e4 L and 37 100 K, brighter than θ¹ Ori C beside it, and counted it naked-eye.
The lookup by position already refuses a source more than a magnitude off HYG's V (it refused
this one); the lookup by name now does too. At its own magnitude and 378 pc the map does not keep
the star, as it keeps none that faint past 250 pc: 455 519 -> 455 518 stars, naked-eye 8 899 ->
8 898, of them past 250 pc 1 664 -> 1 663. HD 45951 (V 6.20 against G 5.90) is placed as before.

Nothing checked where HD 45951 was placed, only that its name was there. Along HYG's direction,
31.7' out, every check passed with the star drawn twice: under its name, and as its bare Gaia
designation. validateStars now requires the star named HD 45951 to carry that source's
designation, and requires HYG 26155 to be absent. The MIN_NAKED_EYE_STARS comment gives the new
counts and says why θ¹ Ori A is left out.

ETL mutants, each in a throwaway worktree with a copy of the cache, reached validation and failed
with the expected message:
- HD 45951 placed along HYG's x/y/z: "HD 45951 is not on Gaia DR3 3369454521490604416, the source
  SIMBAD names it as"
- the magnitude check dropped from the lookup by name: "θ¹ Ori A is drawn in the V and type of
  Hipparcos's blend of it with a companion."

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 21:40:06 +02:00
SenrokaiandClaude Opus 5.5 e7c420b296 Fold a Gliese star into its Gaia source in Gaia's photometry, wherever HYG already put it, and place two naked-eye stars by SIMBAD's name for them
The Gliese fold (030447b) kept HYG's magnitude, band and colour over the Gaia entry's, putting
CNS3's V at Gaia's distance. Of the 49 folded, 15 lost a measured BP-RP and 6 their temperature and
radius (Gl 700.1C, Gl 632.2B, GJ 9800B, Gl 734B, Gl 323B, GJ 3605), and GJ 4285, V 11.45 where
SIMBAD has G 13.05, was drawn five times too luminous. A folded star now keeps the photometry of the
entry already there; HYG's name, id and type still come with the fold. Published catalogue, before
-> after: GJ 4285 V 11.45, 3 850 K, 0.491 R☉, 4.76e-2 L☉ -> G 13.05, BP-RP 2.74, 3 291 K, 0.297 R☉,
9.29e-3 L☉; GJ 3207 0.574 -> 0.278 R☉; Gl 700.1C no temperature, 4.54 L☉ -> 5 155 K, 1.214 R☉,
0.937 L☉; Gl 632.2B -> 9 044 K, 0.018 R☉; Gl 734B -> 3 360 K, 0.381 R☉.

The fold also looked its target up by name, so it saw only Gaia entries still bare. Where a
Hipparcos row of HYG's had already taken the source, the Gliese-only row of the same star stayed
beside it and the check counted none: Gl 251 at 5.76 pc beside HD 265866 (the host of GJ 251 b and
c) at 5.58, Gl 422 beside HD 304043. Gaia entries now carry their DR3 designation through the merge
(ETL only; the assets do not store it) and the fold looks it up; into an entry a HYG star already
describes it folds only where the two V agree within 0.5, so a companion SIMBAD gives its primary's
source stays. 14 more rows fold, 63 in all, each within 0.47 of the star it joins: Gl 251, Gl 422,
Gl 162, Gl 794, Gl 225.2C, Gl 905.2B, GJ 3232, GJ 4046, GJ 9490C, GJ 9608, 69 Tau Oph (Gl 700.1A)
and the second rows of HD 65277, HD 120237 and HD 336196. Stars within 10 pc 367 -> 366, within
25 pc 5 479 -> 5 468; distances without an error 346 -> 332; HYG survivors 11 478 -> 11 465.

validateMerge's count of Gliese rows beside their source took SIMBAD's map from the function the
fold takes it from, so a slip in the map turned both off: with it empty, GJ 2097 and GJ 4285 were
back inside 10 pc and the ETL passed. It now also asks for GJ 2097 and GJ 4285 beyond 20 pc and for
no Gl 251 or Gl 422 by name, and glieseGaiaDesignations refuses fewer than 3 200 HYG rows matched to
SIMBAD (3 352 of HYG's 3 801 measured).

4d47896 left 22 naked-eye HYG rows out as having no distance anywhere; two had one. HD 45951 (K0 III,
V 6.2) was on the map only as "Gaia DR3 3369454521490604416", HYG's declination being 31.7' out,
and θ¹ Ori A (HD 37020, HIP 26220) sits 0.1" from Gaia DR3 3017364132050194688, 2.643 ± 0.072 mas,
which the magnitude test refused because HYG gives V 4.98 against G 6.63. One cached SIMBAD query
now names the Gaia DR3 source of each naked-eye HYG row with no distance (199 of 206 HD numbers),
and a row nothing else places takes that source from the bright list, at its position: HD 45951 at
112.0 pc, under its name, and θ¹ Ori A at 378.4 pc. HD 45951 joins the required names. The twenty
still left out are named in build.ts; none has a bright source with a parallax five times its error
within a minute of arc nor under its SIMBAD name. Naked-eye stars 8 898 -> 8 899; 455 532 -> 455 519
stars.

The fold and the identity lookup are tested in star-merge.spec.ts. Guarded mutants (1 of 833
failed unless noted):
- the Gliese row's photometry kept: caught by "...in Gaia's photometry" (and the Hipparcos-row fold test, 2 failed)
- combine dropping the designation: caught by "folds one into a Gaia entry a HYG star of the same brightness..."
- folding whatever the brightness; tolerance 2 magnitudes: caught by "leaves a star with a Hipparcos error alone..."
- folding into bare entries only: caught by the Hipparcos-row fold test (and the leave-alone test, 2 failed)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 19:55:25 +02:00
SenrokaiandClaude Opus 5.5 c8d1bbb879 Hold st_lum's conversion to two hosts' luminosities, and mu2 Sco b to its host
8d59c72 checked only that every host luminosity was positive, which catches st_lum stored
unconverted and nothing else: converted as 10^-x, Proxima Cen b came out 662 L☉ and TRAPPIST-1 e
1 808, and as e^x Proxima 0.0595, 39 times too bright, and in both runs the ETL completed with
every check passing. The value is printed as measured on host cards and warms their planets.
validateExoplanets now asks two hosts for the luminosity their st_lum gives, within 10 %: Proxima
Cen b's, st_lum -2.821, 1.51e-3 L☉ (Ribas et al. 2017 measure 0.00151), and HD 97048 b's, st_lum
+1.602, 40.0, so a sign slip fails on both sides of the Sun. The published file has 1.5100e-3 and
40.000.

5fb0d45 placed mu2 Sco b's host by its parallax, the archive giving no sy_dist, and only the helper
was tested: with the parallax dropped at the call site the ETL still passed, 6 327 of 6 354 hosted
against a floor of 99.5 %. mu2 Sco b must now have a host.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 19:54:48 +02:00
SenrokaiandClaude Opus 5.5 69cada7914 Fail the ETL when re-rating a locked moon moves its pole or W off the kernel's at the present
lockedToOrbit re-rates a locked moon's W and node terms and moves their
constants so that on 2025-01-01, the date the IAU's elements were fitted
near, the pole and W are the kernel's own. Nothing checked it: with the
constants left where they were, the solar ETL passed and the suite passed,
though every re-rated moon moved (Rhea's pole 0.018 degrees, Triton 0.0054,
Miranda 0.0037, Europa 0.0027, Callisto 0.0021, Deimos 0.0016, Ganymede
0.0016, measured on the bodies.json it wrote; before the drawn node rates
were corrected, Mimas's W moved 0.21 and Miranda's pole 0.12).

lockedToOrbit now compares orientationAt at PRESENT_JD before and after,
Iapetus's pole round its orbit included, and throws past 1e-6 degrees.
Measured on the shipped catalogue: at most 4.7e-10 (Deimos's W, some 2.6
million degrees round), the pole exactly.

Guarded mutants, each through the solar ETL on the real catalogue:
- node terms' constants not moved: "Deimos's pole or W on 2460676.5 is
  1.60e-3 degrees from the IAU's".
- W's constant not moved: Deimos, 9.12e-2.
- the check disabled with the first: the ETL passes (control).
The unit suite does not see it: the check runs on the kernel, which only
the ETL reads. The ETL writes the same bodies.json as before. Unit suite
866 passed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 19:24:49 +02:00
SenrokaiandClaude Opus 5.5 24c7be1bae Draw four moons' nodes at JPL's current rates, which Horizons and the IAU's poles agree with
The archived satellite table the moons are read from gives older node
periods than JPL's current one for Miranda (17.727 years against URA182's
17.787), Ganymede (132.654 against 137.812), Callisto (338.82 against
577.264) and Titan (704.60 against 687.370), and 74ea1d6 turned the IAU's
poles after those older rates, taking them for the right ones. They were
not: fitted to Horizons' osculating elements on Uranus's equator over
1601-2399, Miranda's node turns 2023.97 degrees a century (rms 0.04),
against the current table's 2023.95, the IAU's U11 2024.22 and the row's
2030.80. That commit moved Miranda's axis from 0.38 to 2.36 degrees of
Horizons' orbit normal. Mimas's node, 0.986 years in both tables, now takes
the IAU's S3, 36505.5 degrees a century, 1.2 from a Horizons fit where
the row's is 4.5.

The ETL spec carries the node period (nodePeriodYears), and the periapsis
keeps the row's longitude rate: the row gives the longitude's rate (Callisto
68.7 degrees a century, the current table 67.2), so the argument takes up
the change. On the row's argument Callisto's periapsis moved 44 degrees by
2100 and it strayed 0.71 degrees from Horizons over 1950-2100.

Worst angle from Horizons' osculating orbit normal (ICRF), HEAD then now:
- Miranda, 1601-2399: drawn orbit 2.11 -> 0.12, axis 2.36 -> 0.34.
- Mimas, 1750-2249: orbit 0.33 -> 0.11, axis 0.65 -> 0.40.
- Ganymede, 1600-2199: orbit 0.17 -> 0.11, axis 0.13 -> 0.01.
- Callisto, 1600-2199: orbit 0.53 -> 0.20, axis 0.02 -> 0.03.
- Titan, 1750-2249: orbit 0.048 -> 0.052.
Against the 1950-2100 Horizons tracks the ETL checks: Callisto 0.19 -> 0.08,
Miranda 1.73 -> 1.62, Ganymede 0.30 -> 0.29, Mimas 7.43 -> 7.42, Titan 0.06.

lockedToOrbit now barely moves the IAU's node terms: Miranda's U11 to
-2023.95, Ganymede's J5 to 261.23 (262.1), Mimas's S3 not at all, and
Callisto's J6, 3.1 per cent from its new node rate, to 62.36 (64.3), which
takes Callisto's axis from 0.56 to 0.22 degrees of its drawn orbit.

With the drawn rates right, leaving every node term at the IAU's rate no
longer failed the ETL (Mimas used to), nor did a 1 per cent tolerance, the
node's angle without its harmonics, or the older node periods. The axis
ceiling is now 0.25 degrees for Europa (0.13 measured), Ganymede (0.16),
Callisto (0.22), Rhea (0.17), Miranda (0.23) and Triton (0.15), and
Callisto's track ceiling 0.15 (0.08). Guarded mutants, each through the
solar ETL on the real catalogue and then the suite on the bodies.json it
wrote:
- node terms left at the IAU's rates: ETL "europa's spin axis leans up to
  0.33"; suite fails only 'turns the poles of Europa, Ganymede, Callisto,
  Rhea, Miranda and Triton round with their drawn nodes'.
- tolerance 1 per cent: ETL, Callisto 0.33; the same test, alone.
- harmonics dropped: ETL, Triton 0.29 (the suite's three dates miss it).
- the archived node periods: ETL, Callisto's track 0.19; the suite fails
  that test and 'draws Miranda's orbit, and turns its axis, where Horizons
  has its orbit in 1601 and 2390' (orbit 2.02, axis 2.36 at 1601).
- the row's argument kept: ETL, Callisto's track 0.71.

The docs that called the IAU's rates the wrong ones are corrected
(lockedToOrbit, the axis ceiling in build.ts, whose Titan node now turns
in 687 years), and the README and BodyRecord doc no longer say every
locked moon's node terms are re-rated: only those within 5 per cent of a
multiple of the node's rate, never the Moon's or Phobos's, and not the
circles Ariel's, Umbriel's, Titania's and Oberon's poles go round on
(0.36 to 0.50 degrees off their orbits). The README also names the five
bodies the IAU's elements do not turn. Unit suite 866 passed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 19:22:57 +02:00
SenrokaiandClaude Opus 5.5 280159dcd2 Bring the figures the comments quote back to what the catalogue now holds
Later commits on this branch (0e9ab6f, ff744a0, 8c3a860, and this round's fold, positional lookup
and parallax fallback) changed counts that comments in build.ts, star-readouts.ts, star-catalog.ts
and fetchExoplanets.ts still quoted as "measured" or "today". Each is now the value measured on the
published catalogue after an ETL run from cache (decoded with decodeStarCatalog, or from the
validator log where it prints them):

- distances without a published error 439 -> 346, the Gliese ones 357 -> 264 (82 archive);
- parallax distances ranged 1 109 -> 1 116; HYG stars at Gaia's distance 8 129 -> 8 105, and the
  Gaia-placed stars HYG describes 62 002 -> 61 713 at Gaia's distance, 62 097 in all;
- HYG rows without a Gaia counterpart 11 554 -> 11 478: past 250 pc 8 307 (1 660 naked-eye), inside
  it 3 170 (1 204 brighter than V 8, 1 804 from 8 to 12, 162 fainter, 112 of them Gliese stars
  within 50 pc); the sentence also said those were every star past 250 pc, which the archive's
  hosts no longer let it be;
- planets with a host 6 327 -> 6 328, the 26 left having neither a distance nor a parallax;
- renamed hosts 575 -> 574; the composite table fills 100 of the 127 blank distances, not "the 100".

No ceiling or floor changes; comments only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 17:46:00 +02:00
SenrokaiandClaude Opus 5.5 f31ffe1425 Store a star's distance error in two bytes, so the card prints the error its catalogue published
a81dd49 kept the square root of the relative error in 255ths. A step was a few per cent of the
error itself, which moved the last digit the card prints: over the cached Gaia answers, 2 822 of
the 53 209 stars whose card prints an error printed another one than their published parallax
error gives (Gaia DR3 1415230383034813824 "112 +- 2 pc" for 3), and Rigel, 3.78 +- 0.34 mas in van
Leeuwen 2007, read "265 +- 23 pc" for 23.8.

The column is now a Uint16 in 65 535ths, placed before the photometry byte so its view stays
two-byte aligned whatever the star count; BYTES_PER_STAR_META goes from 16 to 17, the build.ts
round trip tolerance to half a 65 535th, and the README names the column. The same count gives 12,
each on a rounding half. In the running app Rigel reads "265 +- 24 pc".

The cost: stars-meta.bin goes from 7 288 512 to 7 744 044 bytes, and gzip -9 from 3 117 639 to
3 623 379, half a megabyte more to download, since the extra byte is noise-like. One reviewer
judged the one-byte figure within the errors' own accuracy; this takes the other two's view that
the card should print the published number.

Control: 255 steps again fails "keeps an error close enough that the card prints the published
one" alone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 17:43:54 +02:00
SenrokaiandClaude Opus 5.5 4d47896b4a Find the naked-eye stars Gaia's HIP cross-match lacks by position, and give two unnamed ones back their names
c64eea0 and ff744a0 left 34 of HYG's stars of V 6.5 or brighter off the map for want of a distance,
saying no survey gave them one. Gaia DR3 does, for twelve, above the ETL's own cut of five times
the parallax error: fetchStars looks Gaia up only by HIP number through hipparcos2_best_neighbour,
which lacks some of theirs (66 Ori's among them), and never looks up a HYG row with no HIP number.
HD 197770 is 1.102 +- 0.029 mas; HD 45291 and HD 124953 were on the map only as bare Gaia entries
a second of arc from where HYG has them, so searching their names found nothing.

fetchStars now fetches, once and cached, Gaia DR3's 35 910 sources brighter than G 7.5 with a
usable parallax, and for a naked-eye row nothing else places takes the nearest within 5" and a
magnitude of its V. At 15" theta-1 Ori (HIP 26220) took the source of theta-1 Ori C, 12.9" away and
already on the map; the twelve found are within 4.1". An ETL run from cache: 455 522 stars become
455 532, the naked-eye stars 8 886 become 8 898 (1 663 past 250 pc), with 66 Ori, HD 49567, HD 54309,
HD 74455, HD 114461, 10 Sge, HD 197770, HD 33948, HD 152249 and HD 162678 added, and HD 45291 and
HD 124953 folded into their Gaia entries under their names. 22 stay out, with no distance anywhere.
In the running app HD 197770 reads "907 +- 25 pc", 66 Ori "469 +- 61 pc", HD 45291 "108 pc" and
HD 124953 "46 pc". Four of the twelve have a RUWE above 3.7 in Gaia; the ETL has never filtered on it.

validateStars now also requires HD 197770 and HD 45291. Control: without the positional lookup,
the ETL fails with "HD 197770 is missing" (the naked-eye floor alone would not see twelve stars go),
and the baseline passes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 17:36:44 +02:00
SenrokaiandClaude Opus 5.5 030447b83c Fold a Gliese star into the Gaia source SIMBAD names it as, so none is drawn twice or inside 10 pc by mistake
HYG's Gliese-only rows, with no Hipparcos astrometry and no published error on their distance,
reach the merge with positions off by up to minutes of arc, photometric distances and sometimes
wrong proper motions, and isSameStar's geometry missed 49 of them beside their own Gaia entry. 43
lie within 25 pc and 27 are fainter than V 12, the layer the brief asked to merge without
duplicates. GJ 3478 is 16.3" from its Gaia entry, past the 15" tolerance; GJ 2097 moves 39 %
differently by HYG's motion; GJ 4285 is co-moving but 1.6 magnitudes brighter in HYG's V than
Gaia's G. Two of them were false stars inside 10 pc: GJ 2097 at 6.41 pc and GJ 4285 at 6.80, which
Gaia measures at 24.47 and 28.25. HYG also put Gl 94 31.6 degrees from where it is, and HD 23585
and HD 23713, Pleiades members at 135 pc, at 20.6 and 22.2. 0e9ab6f's "no Gliese row within 25 pc
has a co-moving bare Gaia entry 3-300" away" held only under its own motion rule.

fetchStars now asks SIMBAD once, in one cached TAP query, for the Gaia DR3 designation of every
object it knows by a GJ number (4 868), maps HYG's `gl` column onto it, and foldByIdentity folds
each Gliese-only row into the bare Gaia entry of that source: HYG's name, type and photometry,
Gaia's position and distance, as combine does for any other pair. An ETL run from cache folds 49:
455 571 stars become 455 522, the stars within 10 pc 369 become 367, within 25 pc 5 522 become
5 479, HYG rows without a Gaia counterpart 11 517 become 11 468, distances with no published error
395 become 346. exoplanets.json is unchanged. In the running app GJ 2097 reads "24 pc, HYG, Gaia
DR3 distance", GJ 4285 28 pc, Gl 94 17 pc, and 367 stars lie within 10 pc.

validateMerge now refuses any Gliese-only row beside the bare Gaia entry SIMBAD names as the same
star. Controls: folding with an empty identity map fails the ETL with "49 Gliese stars are drawn
beside the Gaia source SIMBAD names them as, starting with GJ 1033" (the baseline passed); in the
unit suite, folding a row with a Hipparcos error fails "leaves a star with a Hipparcos error, and
a Gaia entry already folded into, alone", and keeping the Gliese position fails "folds a Gliese
entry into the Gaia entry SIMBAD names it as, at Gaia's position and distance". HYG's V is kept
for a folded star, which for GJ 3207 is the wrong one (11.51 where SIMBAD has 13.75).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 17:20:32 +02:00
SenrokaiandClaude Opus 5.5 74ea1d655e Turn a locked moon's pole round with its drawn node, so its axis stays on its orbit at every date the clock reaches
The IAU carries a locked moon's pole round its orbit normal on a term of the node's angle, as a
moon in a Cassini state keeps it, but at the node rate the IAU's source had: Miranda's U11 at
-2024.22 degrees a century where the JPL table its orbit is drawn from has -2030.80, Mimas's S3 at
-36505.5 against -36511.16. Over AD 1-3000 that parted Miranda's drawn axis from its drawn orbit
normal by up to 7.89 degrees (AD 9), so Uranus swung 7.6 degrees north and south on its sky every
1.41 days, and Mimas's by 2.63. Only Iapetus's pole had been put on its orbit.

lockedToOrbit now sets every periodic term whose angle turns within 5 per cent of k times the
drawn node rate (k from 1 to 9, the most the report takes, Triton's) to exactly that multiple, and
moves its constant so the angle, and the pole and W with it, are unchanged on 2025-01-01 (the
2025 pole and W of every changed moon are identical to the 1e-14 degree). Measured: the largest
offset taken is Ganymede's J5, 3.4e-2, then Rhea's 1.2e-2; the nearest term that is not a node is
6.0e-2 out (a W-only term of Miranda's), and Umbriel's W has one 1.0e-2 from ten times its node,
which the k limit leaves. Ten moons change: Deimos, Io, Europa, Ganymede, Mimas, Tethys, Rhea,
Miranda, Triton and Proteus. The Moon and Phobos, whose W carries a quadratic, are left as before,
and so is Callisto's J6, 40 per cent from its node rate.

Worst angle between the spin axis and the drawn orbit normal over AD 1-3000, every 135 days,
before and after: Miranda 7.89 -> 0.42, Mimas 2.63 -> 0.47, Rhea 0.77 -> 0.17, Triton 0.51 ->
0.15, Europa 0.33 -> 0.13, Ganymede 0.50 -> 0.16. Faces: Miranda 2.75 -> 2.39, Mimas 8.94 ->
8.89, Deimos 2.14 -> 2.08, Triton 2.88 -> 2.81; none got worse.

build.ts now checks that angle for every locked moon over the same 8114 dates as the face check,
at most 1 degree (Tethys 0.97, whose IAU pole sits 0.69 from its orbit today; Titan 0.94, whose
IAU pole is still while its node turns in 705 years), with four named ceilings: the Moon 7.1 (its
real 6.7-degree tilt, 6.98 at worst), Phobos 2 and Deimos 2 (1.81 and 1.74) and Proteus 1.2
(1.09), whose IAU poles nod with Mars's and Neptune's precessing poles while the Laplace poles
their orbits are drawn round are fixed. The obliquity check at Horizons' epoch shares the new
axisFromOrbitDeg with it. Nothing checked the axis against the orbit before: an Iapetus pole left
on its Laplace pole, 8.30 degrees off at every date, passed the ETL and the suite.

Guarded mutants, each through the solar ETL and then the suite on the data it wrote:
- node terms left at the IAU rates: the ETL fails with "Moon mimas's spin axis leans up to 2.63
  degrees ... (at most 1 expected)", and the suite with only the new test failing;
- Iapetus's pole put on its Laplace pole, W re-phased so its face today is unchanged (worst face
  16.41, under its 16.5 ceiling): the ETL fails with "Moon iapetus's spin axis leans up to 8.30
  degrees", and the suite with only the new test failing.

Also: lockedToOrbit called the Iapetus normal's circle "8.3 degrees across"; 8.3 is its radius (the
row's i = 8.298 to the Laplace plane) and it is 16.6 across. The README credited every rotation to
pck00011 without saying that a locked moon's W and node terms are re-rated to its JPL mean elements
and Iapetus's pole carried round its orbit normal; both of its lines now say so, as the body
model's doc does.

Unit suite 858/858, etl:typecheck and tsc -p tsconfig.app.json clean, solar ETL passes on the
real data.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 17:17:54 +02:00
SenrokaiandClaude Opus 5.5 8d59c720b3 Hold the published catalogue to its naked-eye stars, its host luminosities and five other things no check saw
Seven properties of the catalogue could be lost by a one-line slip in the ETL with every validator
passing and the weekly job publishing the result. validateStars and validateExoplanets now refuse:

- fewer than 8 800 stars of V 6.5 or brighter (8 886 measured), or Rigel, Deneb or Alnilam gone;
  with no magnitude handed to placementDistancePc, 7 378 are left;
- a host luminosity that is not positive, or fewer than 90 % of planets carrying one (6 036 of
  6 354): st_lum is published as log10(L/L_sun), and stored unconverted 3 307 read <= 0 and
  Proxima's -2.82;
- fewer than 40 colours marked as read off a temperature (54 measured);
- an archive-placed star more than 1 mas from its planets' published position carried from
  J2015.5 to J2000 (6.6e-8 mas at most measured; not carried, 6 277.9);
- fewer than 300 HYG stars folded into Gaia keeping their more precise Hipparcos distance (384),
  or Tarazed and Eta Leo off theirs;
- more than 5 archive stars numbered other than their name hashes to (1 measured).

These come from an interrupted earlier attempt left uncommitted in this worktree; its other half,
asymmetric archive distance errors that nothing in the ETL wrote, and a placementDistancePc test
that failed, was discarded (saved in the scratchpad as uncommitted-at-start.patch). The naked-eye
check is new, and runs before the Hipparcos one, which the same slip also trips.

Controls, each an ETL run from cache in a throwaway worktree that reached "Validating output..."
and failed with the named check's own message: no magnitude to placementDistancePc (naked-eye
floor); `10 ** logLuminosity` -> `logLuminosity`; colorFromTemperature never set; the archive
epoch offset times 0; combine never taking the other entry's distance; archive ids in arrival
order. The unmutated baseline passed. star.model.ts's count of flagged hosts, 57, is now 54.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 17:08:31 +02:00
SenrokaiandClaude Opus 5.5 5fb0d45623 Place an archive host by its parallax where the archive gives no distance, so mu2 Sco b has its star
The archive leaves sy_dist blank for mu2 Sco and publishes sy_plx 6.31 +- 0.86 mas. The matcher
only reads the parallax as a second chance beside a finite sy_dist, and the archive-star fallback
needs sy_dist too, so mu2 Sco b had no host while Pipirima (HIP 82545, V 3.56, B2 IV) sat on the
map 0.4" from the archive's direction at 145.3 pc. The build.ts comment and the step report said
the 27 hostless planets had "no distance in either archive table"; mu2 Sco was the one whose row
has a parallax.

archiveDistancePc takes sy_dist, or 1000 / sy_plx where it is blank (158.5 pc here, within the
ratio test of Pipirima's 145.3). An ETL run from cache changes exoplanets.json alone: mu2 Sco b
now has host 82294, Pipirima, and 6 328 of 6 354 planets have a host (26 without, none of whose
rows has a distance or a parallax). hostDistancePc stays the archive's own blank.

Control: ignoring the parallax fails "takes the archive's parallax where it gives no distance,
and nothing from a parallax that is none" alone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 16:37:30 +02:00
SenrokaiandClaude Opus 5.5 734b048c9e Write the star assets once, after the archive's hosts are added, not before them as well
Since 494fb56 and 4c8e4a0, fetchStars wrote stars.bin, stars-meta.bin and stars-index.json, and
fetchExoplanets wrote them again with the 3 277 hosts it adds from the archive and the 574 Gaia
designations it renames, after the live Horizons and archive fetches in between. A run stopped
between the two writes, or fetchStars.ts run on its own as the README documented, left 452 294
stars on disk with no archive star and 574 hosts back to their designations, and the existing
exoplanets.json pointing 4 237 planets at stars that were not there. It happened on this branch:
the dev server served those files.

fetchStars now returns the stars and writes nothing; fetchExoplanets, which build.ts runs after
it, is the only writer. fetchStars.ts run on its own runs fetchExoplanets, which fetches the
stars itself. Checked from cache: `tsx tools/etl/fetchStars.ts` exits 0 and writes 455 571 stars,
the published files byte for byte; build.ts with fetchSolarSystem made to throw fails with
"simulated Horizons outage" and leaves every data file unchanged, where before it left the
452 294-star catalogue. The README's table now names fetchExoplanets.ts as what writes them.

The ETL has no unit harness; these two runs are the check.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 16:21:03 +02:00
SenrokaiandClaude Opus 5.5 a15a46c617 Correct what the ETL, the code and the textures README said of their own sources and figures
- The IAU day check said it compared W with the period Horizons states. That holds for the eight
  planets and Phoebe only. Pluto's and Ceres's periods are the IAU's own rate restated (8.5e-12 and
  3.3e-10: Horizons' Pluto period is 360 over its W, and the SBDB notes it derived Ceres's from the
  report's 952.1532 degrees a day), and the 22 locked moons' is their orbit's, from JPL's table, not
  from their Horizons pages ("Synchronous" on eighteen, nothing on Titan's or Proteus's), and now
  their W's own rate. The comment, the log line and the error message say which is which; the log
  shows 0.0e+0 for the twenty locked moons turned at their orbit's rate, 1.1e-8 and 3.1e-7 for the
  Moon and Phobos. BodyRecord.rotationPeriodHours says that where a source states no period, or
  one a later measurement overturns, it is the one the ETL spec carries (Nereid's, Eris's), where
  the previous commit had Eris among the bodies whose source states none.
- Phoebe's spec justified its period by a note in the satellite table, which is about another
  source (Jacobson 2000, Jupiter's outer moons) and says the table carries corrected values. The
  row's n is right as the table defines it, the rate of the mean longitude: n less twice the node's
  rate is 0.6541855 degrees a day, against 360 / 550.30391 = 0.6541840. What made Phoebe drift is
  that the propagator reads a retrograde moon's n as its sidereal rate, as Triton's row gives it.
  The comment now says so; the period, 550.30391 days, is kept.
- body-orientation.ts and its spec said the IAU's W for Earth, "taken at UT", left its face 2.3 and
  4.5 degrees off Horizons at AD 1000 and AD 1. The old code took it at UT + 69.184 s; those are
  that figure's, and at UT itself they are 2.0 and 4.2, as three reviewers measured through the
  code (4.25, 4.25 and 4.28 at AD 1).
- The renderer said the 28 maps entering the Sun's system are about 20 megapixels of JPEG. Read
  from their frame headers: 37.75, nine at 2048 by 1024 with the Sun's, Jupiter's at 3840 by 1920
  and eighteen smaller.
- The textures README gave Titan 0.02 per cent unmapped, counting only the source's zeros. Its
  largest gap is a flat grey of the source's own (147 and 148, its two commonest values), which
  NASA's caption for PIA19658 names as the gap in coverage: measured on titan.jpg, one region of
  1.09 per cent of the pixels, 0.87 of the sphere, at 48-68 N and 37 W to 25 E. The row says 1.1 per
  cent and where, and step 1 says how it is counted; commit 302fa96's "the rest under 0.2%" is
  therefore not true of Titan.

No behaviour changes but the ETL's log and error wording; the solar ETL passes with the new text.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 16:16:53 +02:00
SenrokaiandClaude Opus 5.5 dadae7b8ca Give Haumea's card its three semi-axes beside its mean radius
Haumea is triaxial, 1161 x 852 x 513 km (Ortiz et al. 2017, Nature 550, 219), and is drawn as the
sphere of its volume, 797.6 km. Its card listed "Radius 798 km" under Measured and said nothing of
its shape, which only a code comment and a commit message gave: its long semi-axis is 1.46 times
that radius and its short one 0.64.

BodyRecord takes semiAxesKm, set by the ETL from Haumea's spec, and the card then reads "Mean
radius 798 km" and "Semi-axes 1,161 x 852 x 513 km". Every other body keeps its one Radius row. The
ETL checks that a body's radius is the mean of its semi-axes, the radius of the sphere of the same
volume, to 0.1 per cent (797.6 against 797.62).

Measured on :4301, Haumea's page: "Mean radius 798 km, Semi-axes 1,161 x 852 x 513 km". Test: the
card of Haumea as shipped in bodies.json. Guarded mutants: the semi-axes dropped from the spec (run
through the solar ETL), the row, or the view model, or the label left as Radius, each fail it and
only it; a radius that is not their mean fails the ETL ("Haumea's radius, 1161 km, is not the mean
of its semi-axes").

Horizons gives triaxial radii for Phobos, Deimos, Miranda and Ariel too, which the page parser
already reads into their mean; they are not carried here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 16:12:30 +02:00
SenrokaiandClaude Opus 5.5 fc7677e715 Turn Nereid in the 11.594 hours Kepler measured, where it was drawn still
Nereid's Horizons page states no spin, and the ETL, finding none, left it still; the validator's
comment read that as "Nereid has no spin". Its rotation is measured: Kepler's K2 light curve gives
11.594 +/- 0.017 hours, confirming earlier ground-based periods (Kiss et al. 2016, MNRAS 457, 2908;
arXiv:1601.02395). Its spec now carries that day, as Eris's carries Bernstein et al.'s, and with no
known pole it turns about its orbit normal, as Eris, Haumea and Makemake do. The free-spinner check
accepts it (11.594 hours against a 360-day orbit).

A new validator: a moon without a lock must have a day unless it tumbles, and only Hyperion
("Rotational period = Chaotic") does. Nereid, left without one, fails it: "Moon nereid is drawn not
turning, and is not known to tumble". The renderer spec's example of a body left still was Titan,
said to have no period on Horizons, though it carries its orbit's; it is Hyperion now, and
BodyRecord.rotationPeriodHours says where each kind of period comes from.

Measured: the solar ETL passes; in bodies.json only Hyperion has no rotationPeriodHours; live on
:4301 Nereid's marker turns 60.000 degrees in a sixth of its day. Test: Nereid, as shipped, turns 60
degrees in 1.93 hours. Guarded mutant, the day removed from its spec and run through the solar
ETL: the validator fails, and the suite on the data it wrote fails that test and only it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 16:02:30 +02:00
SenrokaiandClaude Opus 5.5 e8e857ec25 Hold Io and Europa to their own track ceilings, and Hyperion's one-date ceiling to just above its offset
Io's and Europa's periapses turn backwards, held by the Laplace resonance (apsidesRegress), which
brings them to 0.07 and 0.23 degrees of Horizons from 1950 to 2100. Nothing guarded the flag: with it
dropped the ETL still passed, Io at 0.96 and Europa at 2.24 under the general 3-degree track
ceiling, their cards quietly rewriting themselves to "within 1.0" and "within 2.3". They now have
ceilings of 0.2 and 0.5, as Tethys has for the term it takes from its W. The comment on the
one-date check, which said it catches the periapsis run the wrong way, now says it does not
(0.904 against 2.5) and which check does.

Hyperion's one-date ceiling was 21 degrees, described as just above its offset on that date, where
it is 9.413: the 21 was its worst over twelve dates in an earlier check. It is now 10.

Measured on the real catalogue with the solar ETL: Io 0.07, Europa 0.23 at worst, Hyperion 9.413,
all passing. Guarded mutants, run through the solar ETL: apsidesRegress removed from both specs
fails with "Io's mean elements put it up to 0.96 degrees ... (at most 0.2 expected)"; Hyperion's row
misread by 6 degrees of node fails the one-date check at 15.41, which 21 let through.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 15:59:09 +02:00
SenrokaiandClaude Opus 5.5 3b4fd1af6c Turn each locked moon at its orbit's rate and Iapetus's pole round its orbit, so they face their planets at every date the clock reaches
The IAU gives a locked moon's W the mean motion of whichever orbit its authors had, and JPL's table
has another. Near the present the difference is nothing; over the clock's AD 1 to 3000 it turned
Proteus's far side to Neptune at AD 1 (146 degrees), Mimas 52 degrees from Saturn and Miranda 23.
Iapetus was worse for another reason: its IAU pole is a straight line, 3.9 degrees a century in
right ascension, through its orbit normal's 3 439-year circle round the Laplace pole, which by AD 1
has run past the celestial pole (Dec 97.9), 11 degrees off the orbit, with the face 87 degrees
from Saturn. Mimas and Iapetus carry mission maps, so a wrong hemisphere was drawn facing Saturn.
The ETL's lock check sampled only 1950-2100, so none of it failed.

tools/etl/lib/locked-spin.ts, lockedToOrbit, called for every locked moon:
- W's rate becomes the orbit's own mean motion, its constant moved so W is unchanged on
  2025-01-01; the pole and every periodic term stay the IAU's. A W with a quadratic is left
  (Phobos's orbit already takes it; the Moon's is its tidal slowing, 0.75 degrees at AD 1). The
  kernel's rate must be within 1e-5 of the orbit's first (at most 3.4e-6, Iapetus).
- Iapetus (poleFollowsOrbit): the pole follows its orbit normal, as a moon in a Cassini state does,
  in the IAU's own form: sines of the node's angle and four harmonics on right ascension, cosines
  on declination, fitted to the normal's circle and pinned to the IAU pole at the present; W takes
  sines of the same angles, fitted to hold the face where it is today.

build.ts samples the lock over AD 1 to 3000 (8 114 dates, every 135 days) instead of 1950-2100, and
subPlanetLongitudeDeg moved to the lib, shared by both. Measured on the real catalogue: at most
5.36 degrees (Titan) but the Moon 7.62 (its eccentricity, and W's quadratic at AD 1: a new named
ceiling of 8), Mimas 8.94 (ceiling 11 -> 9.5) and Iapetus 15.95 (19 -> 16.5, 9.4 of it its row's
lag); Proteus's own ceiling of 9 is gone, at 2.66. Iapetus's axis stays within 0.74 degrees of its
orbit normal (11.06 before) and its pole is the IAU's at the present to 1e-4 degrees.

Live on :4301, the longitude facing the planet at AD 1 / 1000 / 2025 / 2999: Proteus 2.6 / 2.6 /
2.6 / 2.6 (was -146.5 / -72.9 / 2.6 / 74.5), Iapetus -15.9 / -15.4 / -15.3 / -9.3 (-87.0 / -50.9 /
-15.3 / 22.8), Mimas 4.1 / 6.8 / 5.7 / 8.4 (48.6 / 29.3 / 5.7 / -13.0), Miranda -0.1 / 2.2 / 0.0 /
1.4 (-23.4 / -9.6 / 0.0 / 12.6); the present is unchanged.

The renderer spec now takes the rotational elements from bodies.json too, so no hand copy is left,
and a new test turns Proteus, Miranda, Mimas and Iapetus to their planets at AD 1 and AD 3000.
Guarded mutants, each run through the solar ETL and then the full suite on what it wrote:
lockedToOrbit bypassed (validator: Mimas 52.30, ceiling 9.5; the new test fails), Iapetus on the
IAU's straight pole (98.48), and its pole round the orbit without W's terms (73.13); each fails the
new test and only it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 15:58:04 +02:00
SenrokaiandClaude Opus 5.5 d449214309 Stop calling WASP-108 b imaged, and stop saying no map exists of an imaged exoplanet
48fd6fd took the archive's ima_flag as it stood, so WASP-108 b's card said it had been imaged as a
point of light beside its star. It is a transiting hot Jupiter (period 2.676 d, 0.04 AU out, 0.15 mas
at 258.8 pc). Its flag comes from Bohn et al. 2020 (A&A 635, A73), a VLT/SPHERE survey of transiting
planets' host stars, which imaged a 0.35 solar-mass companion 0.124" from WASP-108, not the planet.
The imaged query now also asks for tran_flag=0. The archive flags exactly one transiting planet as
imaged (queried today: WASP-108 b); with it left out the list has 101 names, the old 102 less that
one, and still above the validator's floor of 95. The new URL is cached under its own name, and
exoplanets.json, regenerated by the full ETL, changes by that one record's field and nothing else
(checked record by record against HEAD).

build.ts now fails if WASP-108 b is marked imaged. The count cannot see a false positive, and its
record carries neither a period nor an axis, so no separation check could. Control: the full ETL on
the old query (its cache still present) fails with "WASP-108 b is marked as imaged; it transits, and
only a companion star beside it was imaged (Bohn et al. 2020)."

The imaged sentence ended "and no map of it exists". Luhman 16 b, one of the 101 and a brown dwarf,
was mapped by Doppler imaging (Crossfield et al. 2014, Nature 505, 654). It now reads "and no map of
it is used here", which holds for all of them; the doc comment names Luhman 16 b. Control: the old
sentence fails "says a directly imaged exoplanet was seen as a point of light" only (1 failed, 843
passed of 844). Live on :4301: WASP-108 b and Kepler-22 b read "no image of this world exists";
Luhman 16 b and HR 8799 b read the new sentence.

48fd6fd missed a third copy of the claim it corrected: the body page's comment still said every
exoplanet gets a derived surface "since none has ever been imaged". It now says none has had its
surface imaged, as planet-appearance.ts and the README do.

A correction to 48fd6fd's message: HR 8799 b, c and d are Marois et al. 2008 (Science 322, 1348),
and e is Marois et al. 2010 (Nature 468, 1080), not "b to e (Marois et al. 2008)".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 23:23:11 +02:00
SenrokaiandClaude Opus 5.5 acc4b928f2 Say that Makemake's day is known only to a factor of two, citing both readings
f655a4c kept Makemake's SBDB period, 22.83 hours, saying "nothing later overturns it", a reading
its author had not checked. The SBDB flags that period as Eris's was ("may be wrong by 30 percent
or so"). Hromakina et al. 2019 give 22.8266 h as the double-peaked period a "possible lightcurve
asymmetry suggests", of a light curve that repeats every 11.4 h. Kiss et al. 2024 (arXiv:2410.22544),
with TESS and Gaia, find the 11.401 +/- 0.076 h single peak again, "cannot confirm that the
double-peaked 22.8 h is Makemake's true rotation period", and take 11.4 h as their default.

Nothing is changed in what is drawn: the literature does not settle which it is, and 22.83 stays as
the SBDB's. The Makemake spec now cites both papers and says the drawn day may be twice the real
one, and the renderer's comment no longer calls the three dwarf planets' periods known.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 21:50:29 +02:00
SenrokaiandClaude Opus 5.5 4cd08ee324 Credit the IAU W on the three moons whose orbits take terms from it, guard Tethys's, and say what Mimas's lock ceiling is
Since f8ee3ac, Mimas, Tethys and Phobos move by terms taken from their IAU W in NAIF's pck00011:
Mimas's -44.85 degree S5 term, Tethys's +2.23 on the same angle, and Phobos's tidal quadratic,
which also re-centred its M0 (91.059 to 94.239) and n. Their cards still credited only "JPL SSD
satellite mean elements". They now read, for Mimas, "JPL SSD satellite mean elements, epoch 2000
Jan 1, with the orbital terms of its IAU W (NAIF pck00011), within 7.5 degrees of Horizons from
1950 to 2100"; Tethys and Phobos likewise (0.3 and 1.3). build.ts requires any moon carrying such
terms to name the kernel. Control: the full ETL with the old card fails with "Phobos's orbit
carries terms taken from its IAU W, and its card ... credits only the table."

Tethys's half of the libration had no guard. Without its term it strays 2.09 degrees from Horizons
over 1950-2100 against 0.28 with it, under the general 3-degree ceiling, and its card rewrote
itself as "within 2.1"; no unit test loads bodies.json. Tethys now has its own track ceiling of
0.5 degrees. Control: the full ETL without Tethys's orbitFromW fails with "Tethys's mean elements
put it up to 2.09 degrees from Horizons ... (at most 0.5 expected)".

The lock ceiling's comment said Mimas's 10.15 degrees was "physical libration, which W carries and
Horizons shows as 5 to 9 degrees". Neither holds: Mimas's measured physical libration is 0.84
degrees (Tajeddine et al. 2014), W carries no such term, and Horizons, on the same W against its
integrated orbit, runs from -2.7 to +12.7 degrees over 1950-2100 (the review's scan every 20
days). The drawn face's 2.5 to 10.15 is the IAU's W and JPL's mean longitude disagreeing by about
6.3 degrees, W turning 6.0e-5 degrees a day faster than the row's n (381.9945550 against
381.9944948, 3.3 degrees over the span), and 2e = 2.3 degrees of eccentricity. The ceiling itself
is unchanged.

The baseline ETL from the cache passes and changes bodies.json on those three cards only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 21:50:21 +02:00
SenrokaiandClaude Opus 5.5 48fd6fd0e5 Stop telling the reader that the hundred directly imaged exoplanets were never imaged
Every exoplanet card without a map ended "Not an observation — no image of this world exists.",
and 395b613 wrote that rule into a comment ("Only an exoplanet has never been imaged") and a test.
The NASA Exoplanet Archive flags 102 planets as detected by imaging (ima_flag), all 102 of them in
exoplanets.json: HR 8799 b to e (Marois et al. 2008), bet Pic b, 51 Eri b, AF Lep b, and bet Pic c
and eps Ind A b, found by radial velocity and imaged since. The review read the sentence on the
live pages of HR 8799 b, 51 Eri b and bet Pic b.

The ETL now asks the archive for those names in a query of its own, cached apart from the main
table so the other 6 252 planets stay on the snapshot they were built from, and carries
`imaged: true` on the matching records. exoplanets.json changes by that field on 102 records and
nothing else (compared record by record). Their cards now end "Not an observation — it has been
imaged only as a point of light beside its star, and no map of it exists."; the rest keep "no
image of this world exists". The provenance comment and the texture catalogue's comment say which
is which.

Checked live on :4301: HR 8799 b and eps Ind A b carry the new sentence, Kepler-22 b the old one.

Tests: body-view-model.spec 'says a directly imaged exoplanet was seen as a point of light, not
that no image of it exists'; the old test is renamed 'says an exoplanet the archive does not flag
as imaged has no image'. Unit controls, each failing that test only (1 failed, 840 passed): the
provenance ignoring the flag; the view model dropping it. build.ts now requires at least 95
imaged planets (measured 102); control, the full ETL with the join made on the host's name
instead of the planet's, fails with "Only 0 exoplanets are marked as imaged".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 21:50:04 +02:00
SenrokaiandClaude Opus 5.5 ff744a00de Place a naked-eye star HYG gives no distance for by its Hipparcos parallax, where that is 2.5 times its error
c64eea0 left out 41 naked-eye stars "because neither survey gives them a distance". Hipparcos does:
HYG's distances are 1 000 over van Leeuwen's 2007 parallaxes, which the ETL already downloads for
their errors, but HYG writes its 100 000 pc placeholder for every parallax under 1 mas whatever its
error, while keeping far less certain ones above it (Alnilam at 1.65 ± 0.45 mas is drawn). 30 of
the 41 have a positive parallax in the new reduction and 7 have one at least 2.5 times its error:
HD 74180 at 0.67 ± 0.16 mas (4.2 σ), Mu Cep at 0.55 ± 0.20.

hipparcosDistancePc (star-merge.ts, with HYG's placeholder constant moved beside it) keeps HYG's
distance and, where it gives the placeholder, takes 1 000 over the parallax when that is 2.5 times
its error; fetchHipparcosParallaxErrors now returns the parallax with its error. From cache the ETL
keeps 73 563 HYG rows against 73 556 and publishes 455 571 stars; the seven are Alp Cam (1.4 to 3.0
kpc), Psi-1 Aur, HD 74180 (1.2 to 2.0 kpc), HD 86352, HD 96918, Mu Cep (1.3 to 2.9 kpc) and HD
217476, each printed as the range its parallax's error gives. The other 34 stay out: no parallax,
or one within 2.5 times its error of zero. Parallax distances printed as ranges go from 1 109 to
1 116; the validators hold.

Controls, each failing its named test: placeholder rows given no distance, and any parallax 1.25
times its error placing a star (1 of 807 each).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 21:45:12 +02:00
SenrokaiandClaude Opus 5.5 8c3a86097c Place a star at whichever of its two distances is the more precise, not at Gaia's regardless
placementDistancePc took Gaia's distance wherever the cross-match gave a usable one, and its
docstring and c64eea0 called that "the better measurement", adding that Gaia saturates on the
brightest stars "so those sit at their Hipparcos distance". For 273 of the 88 781 HYG stars with
both, Gaia's relative error is the larger, 257 of them naked-eye and 38 by more than twice: Eta Leo
was drawn at Gaia's 556.6 pc ±17 % against Hipparcos's 389 pc ±6.2 %, Schedar and Tarazed at
Gaia's though both have Gaia G of about 2.

placementDistancePc now takes both relative errors and picks the smaller, Gaia's as before when
either is missing; fetchStars gives the placed star the error and the Gaia-distance flag of the
distance it took. The merge's combine keeps the Gaia entry's direction, and now takes the other
entry's distance with its error where that is the more precise, so a bright star Gaia's main query
also holds lands at its Hipparcos distance too. Gaia still wins for the rest, whose parallaxes are
some fifty times more precise.

From cache: 424 stars move, 386 of them naked-eye; HYG rows at Gaia's distance 58 379 -> 58 109 and
HYG stars flagged so 8 129 -> 8 095. Eta Leo 556.6 -> 389.1 pc, Tarazed 178.9 -> 121.1, Imai 139.5 ->
105.8, Schedar 71.0 -> 70.0, Alphecca 23.7 -> 23.0, each now "±" its Hipparcos error. Where the two
disagree by more than 5 σ (21 stars, Iot Gem 11 σ), one of the formal errors is wrong, and this
takes the smaller one at its word. The validators pass unchanged.

Controls, each failing its named test: the placement ignoring the errors, the merge keeping Gaia's
distance whatever the errors, and taking the distance but not its error (1 of 805 each).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 21:37:35 +02:00
SenrokaiandClaude Opus 5.5 23547defe0 Read an archive host's colour off the dwarf sequence at its temperature, and say it was not measured
For an archive-placed host with a temperature and no B magnitude, fetchExoplanets took B−V from
Ballesteros' blackbody fit, which runs 0.1 to 0.2 redder than Pecaut & Mamajek's dwarf sequence
below 3 800 K, and the luminosity then read its correction off that sequence at that colour: 3 500 K
came back as 3 102 K with a correction 1.15 magnitudes too large, anything under about 3 170 K was
clamped to B−V 2.00, and the card printed it as a measured "Colour B−V 2.00". CFBDSIR
J145829+101343, a 580 K brown dwarf, read "Spectral type ~M6, from colour".

temperatureToColorIndex now reads the table itself backwards, interpolating B−V between the two
types the temperature falls between, so the temperature and correction read back off the colour
are the table's at that temperature; it has no answer outside 2 420 to 31 400 K. The colour is
flagged colorFromTemperature, a fifth bit in the photometry byte (the format, README and the ETL's
round-trip check follow), and the card prints it "B−V 1.66, from its temperature", marked derived.

From cache: 57 archive stars change colour; 54 carry the flag and 3, CFBDSIR J145829+101343 among
them, now have none. For the 47 of them the archive gives a luminosity, the one derived from
magnitude and colour moves from a median 0.228 dex off it to 0.124; Kepler-445 (3 157 K) from
0.0282 L☉ to 0.0080 against the archive's 0.0079. Its colour goes from 2.00 to 1.67. The card shows
the archive's luminosity where it has one since earlier on this branch, so this is the figure used
for the rest and for their radii.

Controls, each failing its named test: the nearest hotter row taken without interpolating (2 of
803 failed), no refusal outside the table, the flag not encoded, and the card calling the colour
measured (1 of 803 each).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 21:29:09 +02:00
SenrokaiandClaude Opus 5.5 f82b5e1c74 Hold the published catalogue to what its host radii, distance errors and Gaia-distance flags come to
Three things the branch added could vanish from the data with every check passing, as the review
showed with guarded ETL mutants: dropping st_rad or st_teff from each planet left 0 of 6 354
carrying their host's radius or temperature, storing Gaia's parallax_error in milliarcseconds
rather than over the parallax changed 431 464 distance readouts, and dropping the flag fetchStars
sets relabelled 8 129 HYG stars placed at Gaia's distance "HYG". The round trip compares decoded
with encoded, and the counts of missing bands and errors do not look at what the values are.

validateExoplanets now requires 90 % of planets to carry their host's radius and temperature
(measured 6 030 and 6 054 of 6 354). validateStars requires the median relative error of the
distances at Gaia's to be under 1 % (measured 0.33 %), at most 1 % of stars to have a parallax
distance with an error of a fifth or more (measured 1 109, 0.24 %; the archive's, which are on the
distance and never ranged, are left out), and at least 6 000 HYG stars flagged at Gaia's distance
(measured 8 129). Figures from an ETL run from cache on this branch.

Each proved by a guarded mutant in a scratch copy of the ETL, run from the cache, failing with its
own message: host radius dropped ("Only 0 of 6354 exoplanets carry their host's radius and 6054 its
temperature"), host temperature dropped ("6030 ... and 0"), the Gaia error left in mas ("The median
error of Gaia's distances is 1.92 %"), the same with the median check waived ("17689 parallax
distances have an error of a fifth or more"), and the flag dropped ("Only 0 HYG stars are flagged
at Gaia's distance"); a no-op edit completed. No ceiling is loosened.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 21:20:38 +02:00
SenrokaiandClaude Opus 5.5 6d81c45f45 Carry the archive's positions back from Gaia DR2's J2015.5, where it publishes them, not J2016
fetchExoplanets placed each star it adds from the Exoplanet Archive by carrying the archive's
position back sixteen years, and 4c8e4a0 said the archive publishes at Gaia's J2016. It does not:
its positions are Gaia DR2's at J2015.5 although it names the DR3 source. Barnard's star in the
archive, 269.4486144, 4.7379808, equals DR2 4472832130942575872 at J2015.5 to 1e-7°, and sits 5.2″
from DR3's J2016 place; the review found 66 of the 67 archive-placed stars moving over 100 mas a
year within 0.21 mas of their DR2 position and none within 1 mas of DR3's. The matcher's comment
made the same claim of HD 133131 and TOI-2459, whose positions are DR2's too.

host-star-matching.ts now exports CATALOGUE_EPOCH and ARCHIVE_EPOCH = 2015.5, the matcher carries a
query back by their difference, and fetchExoplanets uses the same two, so the epoch is written
once. From cache: only the 3 277 archive-placed stars move, 2 287 of them by more than a
milliarcsecond, 74 by more than 50 and TOI-2406 most, by 203 mas, half a year of its 405 mas/yr;
no planet changes host. Invisible at map scale; the point is that the constant and its comments
now say what the archive does.

Control: ARCHIVE_EPOCH back to 2016.0 fails "carries Barnard's star from the archive's position to
where Gaia DR3's goes, to a few milliarcseconds" (1 of 802), which puts the two 5.2″ apart. The
GJ 15 A matching fixture is now built at J2015.5 too. fetchExoplanets' use of the constant has no
test of its own; the ETL has no test harness.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 21:20:26 +02:00
SenrokaiandClaude Opus 5.5 62f81f2c43 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>
2026-09-29 21:12:00 +02:00
SenrokaiandClaude Opus 5.5 d93bb1ee2c Say that Pluto's tilt is checked against its own IAU pole, not against Horizons
The ETL's obliquity check, its failure message and the renderer spec's test name all compared
Pluto's drawn tilt with "the obliquity Horizons gives", as 1c86584 and cdf474b said too. Horizons'
Pluto page states none (grep -i obliq finds only the page's IAU76 frame note); the 119.6 degrees is
hand-entered in fetchSolarSystem.ts from the IAU WGCCRE 2015 pole (RA 132.993, Dec -6.163), which
with Pluto's orbit gives 119.609. So for Pluto the check confirms that the kernel's pole and the
sense of W were read as written, which it would still catch misread, but not the pole against a
second source.

The build.ts comment says so, its message names Pluto's reference as its IAU pole, and the spec's
test name and comment no longer attribute Pluto's tilt to Horizons. Labels only; no behaviour
changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 19:58:33 +02:00
SenrokaiandClaude Opus 5.5 a281f22f34 Measure every moon and dwarf planet against Horizons from 1950 to 2100, and say on its card how far it strays
The clock reaches AD 1 to AD 3000, but only the planets' cards named a span their elements hold
over; the 25 moons and the four SBDB dwarf planets gave a source and an epoch, though
BodyRecord.orbitSource is documented as "the span they hold over". And the worst offsets the ETL
stated came from twelve New Year's Days: Nereid's year is 360 days, so all twelve fell far from
its periapsis, where a mean ellipse is furthest out. The one date the ETL checked, 2025-01-01, saw
Nereid at 2.6 degrees; it reaches 11.19.

For each moon and each SBDB dwarf planet the ETL now fetches Horizons' ICRF vectors from 1950 to
2100, every other day (daily for Nereid, at an eccentricity of 0.75, and Hyperion, whose row's
eccentricity is a quarter of its real one: every other day gave it 22.14, daily 22.23), and
measures how far the mean elements stray, at the same TDB dates. The card appends it: "JPL SBDB
osculating elements, epoch 2026 Jun 9, within 7.2 degrees of Horizons from 1950 to 2100". Worst
offsets on the real catalogue: the Moon 2.62 (2010 March 27), Phoebe 2.58 (1969, where a comment
claimed "within 2.0"), Phobos 1.26, Mimas 7.43, Iapetus 10.34, Nereid 11.19 (2039 Nov 1),
Hyperion 22.23 (2055 Feb 26), Ceres 7.12 (1953); Io 0.07, Titan 0.06, Eris 0.06.

build.ts recomputes each from the same Horizons positions and fails if an orbit other than
Standish's names no span, if a card states less than it strays, or if a body passes its ceiling:
3 degrees, and Hyperion 23, Nereid 12, Iapetus 11, Mimas 8 and Ceres 8, each explained. The
2025-01-01 check stays for reading errors, its comment no longer passing one date's offsets off as
worst ones. The Sun's note says the moons' and those four's elements were checked from 1950 to
2100, and the date field's description that each card says how far its orbit strays over that span.
In the running app Ceres's, Phobos's and Nereid's cards end "within 7.2", "1.3" and "11.2 degrees
of Horizons from 1950 to 2100".

The CLOCK_WINDOW comment also had the calendars the wrong way at AD 1: proleptic Gregorian dates
are two days behind the Julian calendar there, level from AD 200 to 300, and ten days ahead by
1582. It now says so, and names Ceres's drift where it named Phobos's, which its orbit now carries.

Controls: the ETL measuring nothing fails ("Ceres's orbit ... names no span it holds over"),
rounding the stated figure down fails on Ceres (7.1 against 7.12), and Nereid held to the general
ceiling fails at 11.19; the note and the date field without the span fail their named tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 19:57:16 +02:00
SenrokaiandClaude Opus 5.5 97b8dd9dc8 Turn the Sun about its IAU pole, once in 25.38 days, as every planet already is
Every body with IAU elements was turned by its pole and W, but the Sun, which is the system's star
marker and no BodyRecord, was built with an identity rotation and never touched: its pole pointed
at RA 90, Dec 0, 115.03 degrees from the WGCCRE 2015 solar pole (RA 286.13, Dec 63.87), and it
stood still where its W turns 14.1844 degrees a day.

SUN_ROTATIONAL_ELEMENTS carries NAIF body 10 from pck00011.tpc, and the ETL fails if they are not
the kernel's. The scene turns the star marker by bodyOrientation each tick when the star is the
Sun, as the renderer turns the planets. In the running app the Sun's drawn pole lies on the IAU's
(0.00 degrees) and its map turns 14.1844 degrees between 2026-01-01 and 01-02. The map's longitudes
are Solar System Scope's, not Carrington's, so the phase of W is not the Sun's own; the pole and
the rate are.

Controls: leaving the marker unturned fails "turns the Sun about its IAU pole, once in 25.38 days";
the app's elements off the kernel's (W rate 14.18) fails the ETL.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 19:21:15 +02:00
SenrokaiandClaude Opus 5.5 8e3a494fe9 Print Hyperion's eccentricity as JPL measures it now, 0.105, not the archived row's 0.023
The card listed Hyperion's eccentricity under "Measured" as 0.023: the archived JPL satellite row
the orbit is drawn from gives 0.0232. JPL's current table (SAT441) gives 0.105, and Horizons'
osculating orbit ranges 0.074 to 0.132 from 1980 to 2100 (0.1099 on 2025-01-01). The row stays
the orbit: with 0.105 put into it, Hyperion is further from Horizons, not nearer (median 9.6
degrees against 7.8 over 1980-2100, as a reviewer measured), so only the card changes.

BodyRecord.measuredEccentricity carries the figure the card prints where it is not the orbit's
own; the ETL sets it for Hyperion, and buildBodyViewModel prints it. build.ts now checks every
card's eccentricity against Horizons' osculating one on 2025-01-01, within 0.03: measured at most
0.0151 (Phoebe, and the Moon, whose eccentricity swings) once Hyperion prints 0.105, where the
row put it 0.0867 out. The live Hyperion page reads "ECCENTRICITY 0.105".

Controls: the ETL with Hyperion on its row's figure fails ("Hyperion's card gives an eccentricity of
0.0232, where Horizons' osculating orbit has 0.1099"); the view model ignoring the field fails
"prints the eccentricity measured for a moon whose orbit keeps an older one".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 19:17:06 +02:00
SenrokaiandClaude Opus 5.5 f655a4c0f7 Turn Eris once in 15.77 days, locked to Dysnomia, not in the 25.9 hours the SBDB flags as unreliable
Eris took its day from the SBDB's rot_per, 25.9 hours, whose own note reads "Result based on less
than full coverage, so that the period may be wrong by 30 percent or so" (Roe et al. 2008). Eris
is locked to Dysnomia: its light curve repeats every 15.771 +/- 0.008 days (Bernstein et al. 2023,
PSJ 4, 115), Dysnomia's 15.78590-day orbit (Holler et al. 2021; Szakáts et al. 2023, A&A 669, L3).
It was drawn turning 14.6 times too fast.

Eris's BodySpec now carries that day, 378.504 hours, cited as its radius already cites Sicardy et
al., and a spec's measured day comes before its source's. build.ts checks that Eris's day is
Dysnomia's orbit within 0.2 per cent. In the running app Eris turns 5.707 degrees in six hours, as
15.771 days gives; on 25.9 hours it turned 83.4.

Makemake's SBDB period, 22.83 hours, carries the same flag; it is Hromakina et al. 2019's own
result and nothing later overturns it, so it is kept.

Control: Eris on the SBDB's period fails the ETL: "Eris turns once in 1.079 days".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 19:14:20 +02:00
SenrokaiandClaude Opus 5.5 f8ee3ac3ab Move Mimas, Tethys and Phobos along their orbits by the terms their IAU W already carried
The IAU W of a locked moon follows its mean longitude, so a term of W that is the moon running
ahead of and behind its mean motion is its orbit's too. Two were in bodies.json's W and in no
orbit: the 71-year libration of the Mimas-Tethys 4:2 resonance, -44.85 degrees on Mimas and
+2.23 on Tethys on the angle S5 = 316.45 + 506.2 T of pck00011.tpc, and Phobos's tidal
quadratic, 9.536e-9 degrees a day squared about J2000. JPL's satellite table has a column for
neither. orbitalTermsOfPrimeMeridian now turns each into the row's meanAnomalyTerms about the
row's own epoch (Phobos's 1950 row gets the quadratic re-centred, which adds to its mean motion
and mean anomaly at the epoch), and the ETL takes them for the three moons named in their specs.

Against Horizons: Mimas on 2026 May 27, near the libration's extreme, 2.24 degrees instead of
43.3; Tethys the same day 0.18 instead of 2.05; Phobos in 2100 1.25 instead of 11.1. On the
ETL's 2025-01-01 check Mimas is 1.56 degrees, so its named 46-degree ceiling is gone. The renderer
spec freezes the Mimas and Phobos vectors.

The day-equals-orbit check checked a number that turns no locked moon: since cdf474b every one is
turned by its IAU W. build.ts now checks what is drawn instead: the east longitude of the planet
on the moon's IAU body-fixed frame, from where the mean elements put it, every 135 days from 1950
to 2100. Measured: at most 6.70 degrees (the Moon's own eccentricity swing), with Mimas 10.15
(its physical libration, which Horizons shows too), Iapetus 18.33 (its row sits 9.4 degrees
behind Horizons) and Proteus 8.18 under their own ceilings. The lock holds only over that span:
Proteus's W turns 6.3e-7 of its rate slower than its orbit, which drifts its face 74 degrees by
AD 3000, and Mimas's W runs 6e-5 degrees a day ahead of the table's mean motion. Without the new
terms the check fails: Phobos's face turned 13.78 degrees from Mars by 2100, and Mimas's 54.5.

The comments that promised the lock "however long the clock runs" now say what the check covers.
The ceilings comment in build.ts gives Hyperion's and Nereid's worst offsets sampled daily (22.2
and 11.2 degrees, where twelve New Year's Days gave 20.2 and 2.6).

Controls: dropping the libration's cosine term, the quadratic, the quadratic's re-centring or
swapping sine and cosine each fails its named test; the ETL without Mimas's term fails at 44.68
degrees and without Phobos's at 13.78.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 18:37:58 +02:00
SenrokaiandClaude Opus 5.5 70cbdae306 Drop the "..." Hipparcos leaves on a spectral type, which read as the app cutting it short
2 127 stars, Sirius among them, read "Spectral type A0m...", in search rows, route options and
the star card. The mark is Hipparcos's own: every one of the 3 803 HYG rows ending in it has a HIP
number, and the catalogue ends a classification it does not print in full with it. The app
truncated nothing, but the text reads as if it had.

fetchStars now trims a trailing "..." from HYG's spectral types. The dictionary in
stars-index.json goes from 3 056 distinct types to 2 883, and from 598 dotted ones to none. The
names, sources and source indices are unchanged, and so is every other column of stars-meta.bin
bar the type indices. gzip -9 of the index goes from 4 015 865 to 4 015 205 bytes.

build.ts validateStars now fails a catalogue with any type ending in "...". Run with the trim
removed, the ETL failed on 2 127 such types. Two ETL runs from cache wrote identical
stars-meta.bin and stars-index.json.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 23:44:41 +02:00
SenrokaiandClaude Opus 5.5 5333be615e Estimate a spectral type from each star's colour where no catalogue gives one, and say so
383 695 of the 455 608 stars read "Spectral type Unknown", every Gaia star among them, although
380 884 of them carry a colour. The card now gives those the type of the dwarf whose colour is
nearest, in the colour's own system, marked as an estimate: TRAPPIST-1, BP-RP 4.90, reads
"Spectral type ~M8, from colour", which is how it was classified (M8 V). A star with neither a
type nor a colour gets no subtitle rather than the literal "Unknown".

The colours are Pecaut & Mamajek's mean dwarf sequence (2013, ApJS 208, 9, table 5), as Mamajek
maintains it online (version 2022.04.16, which carries Gaia BP-RP), from B0 to M8.5. B-V cannot
tell O types apart (the whole sequence spans 0.03 of it), and BP-RP turns back past M8.5 and is
tabulated only from B9. A colour outside the table gets no estimate: 186 BP-RP and 41 B-V colours,
among them the blue Gaia DR3 5612323414549657984 at BP-RP -0.15.

380 657 stars get an estimate: F 97 840, G 144 327, K 105 984, M 29 142, A 3 272, B 92. Checked
against catalogued types:
- 19 433 HYG dwarfs with a B-V: 74.3 % within two subclasses, 95.5 % within five.
- 146 Gaia exoplanet hosts the archive types as dwarfs, from BP-RP: 88.4 % within two
  subclasses, 98.6 % within five.
The estimate assumes a dwarf, so a giant reads later than it is (Pollux, K0 III at B-V 0.99,
reads K3). It also ignores reddening. The comment says both.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 23:28:29 +02:00
SenrokaiandClaude Opus 5.5 a81dd491ad Say which band each star was measured in, whose catalogue it is, and how sure its distance is
The readout named Hipparcos, Yale and Gliese while 378 775 of the 455 608 stars are described by
Gaia DR3, printed one "Magnitude" for G and V alike, and gave every distance to the parsec. The
band cannot be read off the star's source, which records whose position it has: 62 002 stars Gaia
places keep HYG's V and B-V, and the 575 hosts renamed after their planets are Gaia's, in G.

stars-meta.bin gains two byte columns, 14 to 16 bytes a star (6 378 512 to 7 289 728 bytes; gzip
-9 2 804 049 to 3 110 991). One holds the magnitude's band (V 76 555 stars, G 378 744, none 309,
whose magnitude is a stand-in), which colour the colour index is (B-V 75 203, BP-RP 376 703), and
whether the distance is Gaia's parallax. The other holds the distance's relative error as its
square root in 255ths: a step is 0.08 % of distance at 1 %, 0.35 % at 20 %, and 100 % is the top.
encode, decode, BYTES_PER_STAR_META and the build.ts round trip cover both; no workflow reads the
format.

Where the errors come from:
- Gaia rows keep the parallax_error their query already fetched: median 0.3 %, 90th percentile
  1.2 %, at most 20 %, the query's own cut.
- A HYG star at Gaia's distance takes the cross-match's parallax_over_error, and a star merged
  into a Gaia entry keeps that entry's error with its position.
- The 3 067 Hipparcos stars that keep their Hipparcos distance, Rigel, Deneb and Alnilam among
  them, take e_plx from van Leeuwen's 2007 reduction: a new cached query of
  public.hipparcos_newreduction on the ESA archive, whose 117 955 rows HYG's distances invert.
- The archive's stars take sy_disterr1/2 from pscomppars, in a query and cache file of their own
  so the composite rows already cached were not refetched.
- 439 distances have no published error: 357 Gliese rows and 82 archive hosts.

Of the errors, 392 786 are 1 % or less and are not printed; 61 156 print as "117 ± 12 pc" to the
distance's own digits; 1 196 between 20 and 100 %, and 30 past it, print as the range the
parallax gives, since a symmetric error in parallax is a lopsided one in distance.

The star card (measured on the dev server) now reads, for example:
- Rigel: 265 ± 23 pc, V 0.18, B-V -0.03, source HYG.
- Deneb: 433 ± 60 pc.
- Alnilam: "476 pc to 833 pc" (Hipparcos 1.65 ± 0.45 mas).
- Gaia DR3 5612323414549657984: 111 ± 2 pc, G 4.63, BP-RP -0.15, source Gaia DR3.
- Proxima Centauri: 1.30 pc, V 11.01, source "HYG, Gaia DR3 distance".
- TRAPPIST-1: G 15.62, BP-RP 4.90, source Gaia DR3.
- Kepler-186: V 15.14, source NASA Exoplanet Archive.
The neighbourhood's subtitle reads "Gaia DR3 378,775 · HYG 73,556 · NASA Exoplanet Archive
3,277", counted by the catalogue describing each star.

build.ts validateStars now fails a catalogue with more than 1 000 stars without a band (309
today) or without a distance error (439). Dropping G from the Gaia rows gave 379 040 without a
band, and dropping their parallax_error gave 441 216 without an error; both runs failed.

Decoding the catalogue in Node took a median 29 ms before and 24 ms after (nine runs each, within
noise). In the app, five cold boots gave a 654-786 ms long task after the data landed and the
HUD at 1.83-2.07 s.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 23:26:27 +02:00
SenrokaiandClaude Opus 5.5 1c86584642 Carry every body's IAU rotational elements, read from NAIF's kernel of the 2015 report
bodies.json now holds, for 33 of the 38 bodies, the pole right ascension and declination and the
prime meridian W of the IAU WGCCRE 2015 report (Archinal et al. 2018), with their rates and the
periodic terms. They are read from NAIF's pck00011.tpc, which carries the report in a form a
program can read, periodic terms and their angles included. Hyperion (chaotic), Nereid, Eris,
Haumea and Makemake have no model in the report.

The parser, src/app/shared/astro/rotational-elements.ts, sits beside the other source readers so
the unit suite covers it. It reads data blocks only where \begindata stands alone on a line, as
the kernel's own prose mentions the token mid-sentence. It reads the Fortran exponent (the Moon's
-1.4D-12 d² term) and the degree-2 angles of the Mars system, where Phobos's tidal acceleration
lives. NAIF numbers a small body 2 000 000 past its catalogue number, so Ceres is 2000001.

Periodic terms under 0.01 degrees are left out. 0.01 degrees moves a point by 0.11 px on the
largest body ever drawn (Jupiter at 641 px of radius). That drops 32 terms:
- Mercury: 4 (0.0011 degrees and less)
- the Moon: 8 of 13 (0.0072 and less)
- Mars: 13 (0.00024 and less); its three 0.42-1.59 degree long-period terms stay
- Phobos: 1 (0.0063)
- Jupiter: 5 (0.0022 and less)
- Europa: 1 (0.009)
Kept, among others: Mimas's 44.85-degree libration, Triton's 32-degree precession, Miranda's 4.4
and Phobos's 1.14-degree libration.

build.ts now checks the elements against Horizons on the real catalogue:
- Every body but those five carries elements, and they do not.
- The IAU day, 360 over W's rate, is within 1e-4 of Horizons' period. Measured: at most 1.8e-5
  (Jupiter). Neptune gets a 0.01 ceiling: 0.89 per cent, because the report takes Karkoschka's
  15.9663 h where Horizons keeps Voyager's 16.11.
- The spin axis, the pole turned end for end where W runs backwards, is within 0.1 degrees of
  Horizons' obliquity. Measured: at most 0.058 (Venus, 177.358 against 177.3); Uranus 97.771,
  Pluto 119.610, Earth 23.435.
Full npm run etl passes. Three mutants each fail it on the named check:
- W's sign dropped: "Venus's IAU spin axis is 2.642 degrees".
- Ceres looked up by catalogue number: "Body ceres has no IAU rotational elements".
- W's rate read per century: "Mercury's IAU day ... 3.65e+4".

Nothing is drawn from these yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 22:46:14 +02:00
SenrokaiandClaude Opus 5.5 4c8e4a02f3 Give every planet with a distance a star, from the archive where the catalogue has none
After matching, 4 237 planets still had no star: their hosts are too faint for either Gaia
query (fainter than G 12 past 50 pc) or too far (past 250 pc), Kepler-186 at 177.6 pc among
them. fetchExoplanets now adds one star per such host from the archive's own figures, 3 277
of them, whenever the archive gives a position and a distance:

- position carried back from J2016, where the archive publishes it (741 of the 746 matched
  hosts moving over 100 mas/yr sit nearer their star carried back, a median 0.11" against 3.47"
  as published), and placed at sy_dist;
- magnitude in V (2 999 hosts), else Gaia G (13), the band the catalogue's Gaia stars are
  already in; 265 have neither, 128 KMT, 95 OGLE and 32 MOA microlensing hosts at a median
  6.2 kpc among them, and take the ETL's faint stand-in of 15;
- colour as B-V from the archive's B and V, else from st_teff through a new
  temperatureToColorIndex (Ballesteros 2012, inverted; the Sun's 5 772 K gives 0.65), else
  left to st_spectype;
- ids from 1 070 000 000, past Gaia's two ranges and under the 2^30 validateStars enforces;
  source "exoplanet-archive".

Hosts past 250 pc are included: 399 of the 3 277 are within 250 pc, 1 962 between 250 pc and
1 kpc, 916 beyond. The drawn budget still chooses what is drawn (70 000 of 455 608).

Planets with a star: 2 090 -> 6 327 of 6 354. The other 27 have no distance in either table
(Luhman 16 A, mu2 Sco, PSR B1620-26 among them). Systems in the Solar Neighbourhood readout:
1 450 -> 4 736. validateExoplanets now refuses a catalogue where fewer than 99.5 % of planets
have a host (measured 99.58 %); dropping the added stars fails it at 2 090, and dropping the
composite fill at 6 227. No added star sits within an arcsecond of a catalogue star
(validateMerge's twins stay at 23); 5 of the 399 within 250 pc have one within a minute of arc,
VHS J125601.92-125723.9 (archive 12.7 pc) 5.8" from a Gaia entry at 21.2 pc the likeliest
duplicate.

In the app, searching TRAPPIST-1 or Kepler-186 and picking the star enters a system with its
seven and five planets drawn. gzip -9: stars.bin 5 030 741 -> 5 067 864 B, stars-meta.bin 2 784 614 -> 2 804 064,
stars-index.json 4 003 584 -> 4 015 882, exoplanets.json 342 467 -> 446 532 (host parameters,
both commits).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 22:09:16 +02:00
SenrokaiandClaude Opus 5.5 494fb5616b Find the hosts the catalogue already holds, and name them after their planets' star
The archive's default-parameter rows leave sy_dist blank for 100 planets, TRAPPIST-1's seven
among them, so the matcher could not place a host the catalogue had drawn since the Gaia
nearby query (Gaia DR3 2635476908753563008, 12.47 pc). fetchExoplanets now also reads the
Planetary Systems Composite table (pscomppars) and fills a default row's blank host cells from
it. Only host columns: a composite row takes each column from its own reference, so orbits
still come from the default row alone, one fit per planet. Where both tables give a distance or
a position they agree on all 6 225 and 6 352 rows.

Three hosts the catalogue holds by name failed the distance ratio test because the archive's
sy_dist, from TICv8, contradicts its own parallax: Lalande 21185 (GJ 411) 5.68 pc against
392 mas, Luyten's Star (GJ 273) 5.92 against 263 mas, Struve 2398 B (Gl 725 B) 6.84 against
285 mas. resolveHostStarId now takes the archive's parallax (sy_plx) as a second distance the
ratio test accepts. It is a second chance, not a replacement: 47 of 5 959 systems disagree past
the tolerance, and for faint far hosts the inverse parallax is the worse figure (K2-238: 538 pc
by sy_dist, 6 779 by parallax).

Planets on a catalogue star: 2 071 -> 2 090 of 6 354. The 19 gained are TRAPPIST-1 (7),
GJ 273 (2), GJ 411 (2), Gl 725 B, HD 62509 (Pollux), K2-65, TOI-2267 A and B, and two
brown-dwarf hosts, 2MASS J02192210-3925225 and DENIS-P J082303.1-491201. No planet lost or
changed its host.

A matched host whose catalogue name is a bare Gaia designation now takes the archive's host
name, so search finds TRAPPIST-1, Teegarden's Star, TOI-700, LP 791-18 and K2-18: 575 stars
renamed. validateExoplanets refuses a host that is still only a designation, and the star
assets are rewritten after the exoplanets for that reason; stars.bin and stars-meta.bin are
unchanged. TOI-2267 A and B both land on one Gaia entry, which takes the name TOI-2267 A.

Each planet also carries its host's radius, effective temperature and luminosity (10^st_lum),
and a mass for 6 344 planets instead of 5 474, from the default row where it gives one and the
composite table otherwise, for the star-physics step.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 22:02:56 +02:00
SenrokaiandClaude Opus 5.5 1d42be2ad5 Add Charon, the moons of Uranus, Saturn's other large moons and the four dwarf planets past Pluto's table
The solar system stopped at 18 bodies: Pluto without Charon, Uranus without a moon, Saturn with
Titan alone, no dwarf planet but Pluto (audit #22). bodies.json now holds 38: the eight planets,
the five IAU dwarf planets, and every moon in JPL's mean-element table more than 100 km in mean
radius. New: Ceres, Eris, Haumea, Makemake; Mimas, Enceladus, Tethys, Dione, Rhea, Hyperion,
Iapetus, Phoebe; Miranda, Ariel, Umbriel, Titania, Oberon; Nereid, Proteus; Charon. Search finds
each by name (it indexes bodies.json), each has a body page, and the Sun's system draws them.

Where they come from
- Moons: the same archived JPL satellite table as the others. Uranus's and Pluto's are given
  against the planet's equator, with the IAU WGCCRE 2015 poles: Pluto's as the IAU gives it
  (132.993, -6.163), Uranus's at the end the table measures inclinations from (77.311, 15.175)
  with its nodes counted 180 degrees on, from the IAU pole's crossing; read without that offset
  every Uranian moon was 180 degrees from Horizons at every date from 1980 to 2100.
- Two rows are corrected where they disagree with JPL's own ephemeris and the reason is known.
  Pluto's section prints epoch 2000 Jan 1.0; JPL's current table gives Charon's as 2000-01-01.5,
  and at 1.0 Charon was 27.8-28.2 degrees from Horizons at every date, half a day of its motion.
  Phoebe's mean motion gives 548.02 days where its Horizons page and the current table give
  550.30 (the table's own note says its source misstated retrograde moons' mean motions); on the
  row's figure Phoebe was 24.6 degrees out by 2025 and 100 by 2075.
- Dwarf planets: JPL SBDB osculating heliocentric elements with their epoch (2026 Jun 9), carried
  at their own n. Against Horizons (heliocentric, 1950-2300; the clock only runs forward from now):
  Ceres 0.02 degrees in 2025, 1.9 in 2050, 4.0 in 2075, 5.3 in 2100, 11.6 in 2200 (Jupiter pulls
  on it and nothing here carries that); Eris within 0.06 to 2100 and 0.5 to 2300; Haumea within
  0.35 to 2100; Makemake within 0.25 to 2100 and 1.7 by 2200.
- Size and spin: Horizons pages for the moons (Charon 606 km, Miranda 235.7 as the mean of its
  three axes). The SBDB for Ceres (469.7 km, 9.074 h) and for the other three's spins (Eris 25.9 h,
  Haumea 3.915 h, Makemake 22.83 h). Neither source nor the WGCCRE 2015 report has a radius for
  Eris, Haumea or Makemake, so each carries its stellar-occultation measurement: Eris 1163 km
  (Sicardy et al. 2011), Makemake 715 (Brown 2013, the mean of 1434 x 1434 x 1422 km), and
  Haumea 797.6, the radius of a sphere of its volume: it is triaxial, 1161 x 852 x 513 km
  (Ortiz et al. 2017), and is drawn as that sphere.
- Rotation uses the branch's model. Every moon is locked except three: Hyperion's page says
  "Chaotic" and Nereid's gives no spin, so both are left still; Phoebe turns in 9.274 h.
- Charon carries massRatio 0.12205, the GM ratio of the two Horizons pages (106.10 / 869.326), so
  it and Pluto are drawn round their barycentre 2 131 km from Pluto's centre.

Validators (tools/etl/build.ts, on the real catalogue; full npm run etl passes)
- Offsets from Horizons on 2025-01-01, new bodies: dwarf planets at most 0.016 degrees (Ceres),
  under the 0.25 ceiling; moons Dione 0.009, Ariel 0.058, Rhea 0.070, Charon 0.111, Oberon 0.142,
  Titania 0.185, Umbriel 0.219, Proteus 0.245, Enceladus 0.309, Phoebe 0.984, Miranda 1.162,
  Tethys 2.042, under the 2.5 ceiling, which is unchanged.
- Four moons get their own ceiling, each just above its worst offset at twelve dates from 1980
  to 2100 and each named with its reason: Mimas 46 (measured up to 44.7: its resonance with
  Tethys swings its longitude 44 degrees either way over 70.8 years, which the table has no
  column for), Hyperion 21 (20.2; held in resonance by Titan, and the row's eccentricity 0.0232
  is under a quarter of the current table's 0.105), Iapetus 11 (10.1; the row sits 9.4 degrees
  behind Horizons at its own epoch and keeps that, with its plane within 0.07 degrees and its
  period within 0.001 per cent), Nereid 3 (2.6 in 2025; eccentricity 0.75).
- New checks: every body has a radius over 0 (Charon's would have been 0 before the page
  parser learnt its form); a freely spinning moon is not locked; a moon with a mass ratio puts
  the barycentre outside its planet; there are 5 dwarf planets.
- Negative controls, each a full npm run etl on the real catalogue refused with the named
  message: Uranus's node offset removed (Miranda 172.50 degrees), Charon at the printed epoch
  (28.08), Phoebe on the row's mean motion (24.61), Charon's radius unread (no radius),
  free spinners locked (Hyperion), mass ratio inverted (barycentre 17 460 km out).

Measured in the running app (port 4311): the Sun's system has 38 members ("13 + 25 moons");
Charon comes back to within 0.0004 degrees of where it started after 6.38723 days and is 179.98
degrees round after half that; Pluto is 2 130.6 km from the barycentre and Charon 17 456.8,
exactly opposite; Saturn's moons in order of distance now: Mimas 185 617 km, Enceladus 238 042,
Tethys 294 648, Dione 376 805, Rhea 526 964, Titan 1 231 389, Hyperion 1 470 453, Iapetus
3 637 059, Phoebe 11 740 900. At the arrival framing the dwarf planets are held at the 3 px
floor and the moons at 1.5 px, half their planet's drawn radius, the scene's existing rule.
Searching Charon, Enceladus, Ceres, Titania, Makemake and Phoebe each finds the body; the body
pages show Charon 6.39 d and 606 km, Titania 8.71 d, Ceres 4.6 yr and 470 km, Haumea 283 yr and
798 km, Hyperion 21.3 d, each with its orbit source. Long tasks on entering: see the previous
commit.

The Sun's note now says the four dwarf planets are on the SBDB's osculating elements. Holding
Eris's orbit, the arrival framing widens: 192 AU of range on a 1600 x 1000 window, under the
200 AU ceiling.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 21:54:56 +02:00
SenrokaiandClaude Opus 5.5 b0d7989c6f Read moons given against their planet's equator, and dwarf planets from the Small-Body Database
Two sources the missing bodies need, read and tested before any body uses them.

JPL's satellite table gives Uranus's and Pluto's moons against the planet's equator ("Mean
equatorial orbital elements") rather than a Laplace plane, and does not print that equator's
pole. parseSatelliteMeanElements now takes the pole from its caller for such a section and reads
the row against it exactly as against a Laplace plane's; it throws if a section is equatorial and
no pole was given, or a pole was given for a section that is not. Read as ecliptic elements, which
is what the old code would have done, Titania is 88 degrees from Horizons on 2025-01-01. The
section's plane is now the nearest heading above the row, with the ecliptic as before where there
is none.

Ceres, Eris, Haumea and Makemake are in none of Standish's tables. parseSmallBodyElements reads a
JPL SBDB answer (sbdb.api?sstr=...&phys-par=1&full-prec=1): the osculating heliocentric elements
against the J2000 ecliptic, carried round at their own n with nothing turning, and half the
published diameter and the rotation period where the answer has them. full-prec matters: without
it SBDB rounds to three figures, Ceres's n to 0.214 degrees a day for 0.2143045, 1.1 degrees out
within a decade. The fetcher, tools/etl/lib/mean-elements.ts, caches the answer like the others.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 21:47:55 +02:00
SenrokaiandClaude Opus 5.5 c01d3ec2bc Read OpenNGC's addendum, so the Pleiades and the Large Magellanic Cloud are on the map
OpenNGC keeps the objects no NGC or IC number covers in a second file, addendum.csv, with the
same 32 semicolon-separated columns as NGC.csv. The ETL only ever fetched NGC.csv, so the
brightest deep-sky object in the sky, the Large Magellanic Cloud (V 0.29), was missing while
the Small one was drawn, and so were the Pleiades (M45), the Hyades, the Horsehead and the
Coalsack. fetchDeepSky now fetches the addendum beside NGC.csv, caches it as
openngc-addendum.csv, and runs its rows through the same loop.

Of its 64 rows, 27 pass the existing filters: all 22 named or Messier rows except M40, which
OpenNGC types as a double star, and M102, typed as a duplicate of M101; plus seven anonymous
open clusters brighter than V 9 (H05, H20, H21, Mel071, Mel101, Mel105, MWSC3171). deepsky.json
goes from 463 to 490 objects (galaxies 73 -> 85, clusters 294 -> 306, nebulae 96 -> 99), with
no existing record changed. Messier coverage goes from 106 to 107 of 110. 340 of the 490 have
a distance: the Pleiades 135.8 pc and the Coma Star Cluster 85.9 pc from their parallaxes;
the Hyades and the Local Group dwarfs honestly have none.

validateDeepSky now requires the Andromeda Galaxy and the Small Magellanic Cloud from NGC.csv,
the Large Magellanic Cloud and the Pleiades from the addendum, and at least 107 Messier
objects. Both checks were run against the real catalogue with the addendum removed: the ETL
fails on "Deep-sky object ESO056-115 is missing", and with the required list emptied, on
"Only 106 Messier objects were produced".

In the app, on the dev server: 490 sprites. The Pleiades sprite lies 0.00182 deg from Alcyone
(0.00183 deg from the published coordinates); the LMC 18.4209 deg from Canopus and 26.8215 deg
from Achernar (18.4209 and 26.8215 published); the Hyades 2.2591 deg from Aldebaran (2.2591).
The twelve labelled deep-sky objects now open with the Large Magellanic Cloud and the
Pleiades and include Brocchi's Cluster, in place of h Persei, chi Persei and NGC 2516.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 20:59:39 +02:00
SenrokaiandClaude Opus 5.5 cdc0cf4678 Read the Horizons pages the missing moons are written in, and give triaxial bodies their mean radius
The pages of the moons this branch is about to add state their size and spin in forms the ETL
did not read. Charon's gives "Radius (km, IAU2015) = 606", which none of the radius patterns
matched, so it would have come out at radius 0. Phoebe's gives "Rotational period = 9h 16.438 m",
which the hours-or-days pattern read as 9 hours flat instead of 9.274. Pluto's and the moons' GMs
are now read too ("GM (planet) km^3/s^2 = 869.326" on Pluto's page, "GM (km^3/s^2) = 106.10" on
Charon's), for placing a pair's barycentre.

Miranda and Ariel, like Phobos and Deimos already, give three semi-axes, "240x234.2x232.9". The
first figure was taken as the radius, which is the longest axis. A triaxial body now gets the
radius of the sphere of its volume, the cube root of the product, which is how the IAU states a
mean radius. That changes two bodies already shipped: Phobos 13.1 -> 11.06 km (IAU 11.08) and
Deimos 7.8 -> 6.20 km (IAU 6.2). Nothing else in bodies.json moves.

The page parsers move from tools/etl/lib/horizons.ts to src/app/shared/astro/horizons-page.ts,
as the mean-element parsers did, so the unit suite runs their tests; the ETL imports them. A
small body's command ("1;" for Ceres) is now URL-encoded: sent raw, the semicolon made Horizons
refuse the request ("one or more query parameter was not recognized").

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 20:41:22 +02:00
SenrokaiandClaude Opus 5.5 74b93a0428 Fill in the Sun's faint neighbours from Gaia, and fold the Gliese entries they repeat
Gaia's G < 12 cut took a quarter of what lies within 10 pc: the red,
brown and white dwarfs most of the neighbourhood is made of, which the
map only had where Gliese happened to list them. Teegarden's Star was
missing, and with it its three planets' host.

A second query fetches the complement out to 50 pc: G >= 12 or no G,
parallax > 20 mas, with pmra/pmdec so the J2016 -> J2000 propagation
applies. The quality filter was chosen by counting. Parallax over error
> 5 keeps 39 751 of the 39 764 sources that pass the floor, but the Gaia
Catalogue of Nearby Stars (GCNS; Gaia Collaboration, Smart et al. 2021)
rejects 11 752 of them as spurious: median G 20.2, astrometric excess
noise 5.4 mas against 0.15 for the ones it keeps, 6 933 toward the
Galactic centre. So the query joins the GCNS main table (EDR3 astrometry
and source ids, which DR3 carries unchanged) and keeps 28 012 rows; the
error cut stays and costs no GCNS source, brown dwarfs included. The
query has its own row-count floor (28 012) and the row-limit cap, and is
ordered by (phot_g_mean_mag, source_id); a second ETL run reproduced
stars.bin, stars-meta.bin and stars-index.json byte for byte. Its ids
start at 1 050 000 000, clear of the main query's and under 2^30, which
V8 keeps unboxed: numbered from 2 000 000 000 they made the app's boot
task 230 ms longer (medians of five interleaved runs, 1.41 s against
1.18). validateStars now refuses an id outside 0 to 2^30.

The Gliese entries these stars duplicate were not folded: HYG carries
them with positions off by up to a minute of arc and photometric
distances, so they missed the 15" tolerance or failed the distance test.
Their proper motions, which Gliese measured well, give them away:
isSameStar now takes two entries moving within 20 % of each other as one
star up to 60" apart, whatever their distances, brightness still
permitting. Of the 602 Gliese-only rows left without a counterpart, 253
have such a Gaia entry; with every entry shifted a quarter degree, none
does. fetchStars passes HYG's motions only for rows without Hipparcos
astrometry: given them too, 15 Hipparcos stars took a co-moving
companion's Gaia entry and the cross-catalogue pairs under an arcsecond
went from 23 to 35. Of HYG's 1 200 stars fainter than V 12 within 25 pc,
1 024 now sit on a Gaia position (325 before); of the 176 left alone, 43
still have a Gaia entry 3-60" away (218 without the motion rule), some of
them real companions.

Measured on the rebuilt catalogue, against the GCNS (sources with
parallax > 100, 40 and 20 mas):
  within 10 pc  336 -> 372  (GCNS 312; the map adds 60 HYG-only stars)
  within 25 pc  3 652 -> 5 560  (GCNS 5 111)
  within 50 pc  13 702 -> 40 916  (GCNS 40 231)
452 331 stars (+27 214). Proxima, Barnard's Star, Wolf 359, Rigel, Deneb
and Alnilam are all present by name; Teegarden's Star is Gaia DR3
35227046884571776 at 3.83 pc and hosts its three planets. Luhman 16 is
not in Gaia DR3 with a parallax (5353626573555863424 has a two-parameter
solution) and stays absent. 94 more exoplanets find a host (2 071), none
changes host. TRAPPIST-1 is now drawn (Gaia DR3 2635476908753563008,
12.47 pc) but its planets are not yet matched to it.

Merge gate, ceilings unchanged: HYG rows without a Gaia counterpart
12 352 -> 11 554 (ceiling 15 000; 10 886 before the naked-eye stars),
cross-catalogue pairs under an arcsecond 23 -> 23 (ceiling 100). The
gate's comment now accounts for the survivors by magnitude.

gzip -9 sizes against the catalogue before both changes: stars.bin
4 711 922 -> 5 030 741 B, stars-meta.bin 2 576 213 -> 2 784 614 B,
stars-index.json 3 724 855 -> 4 003 584 B (+806 KB, 7.3 %). Boot on the
dev server, five interleaved cold runs: the task that indexes the
catalogue after the data lands, median 1 072 -> 1 182 ms; HUD shown,
median 2 622 -> 2 716 ms. This machine measured 0.82-1.30 s for the
same baseline task today, above audit #25's 627-843 ms. The drawn-star
budget is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 20:35:21 +02:00
SenrokaiandClaude Opus 5.5 48319c3fe2 Move the solar system on JPL's mean elements, so it stays right as the clock runs
Every body carried one set of osculating elements from Horizons at 2025-01-01, run forward by
Kepler with a GM from a table of mass ratios. That set is exact at its instant and drifts from
then on, and the clock now runs a month a second: the Moon, with Earth's mass ratio lacking its
own and the osculating axis, went round in 27.70 days instead of 27.32, 66 degrees out after a
year, and its locked face was spun at the same wrong rate.

Planets and Pluto now take Standish's Table 2a/2b ("Keplerian Elements for Approximate
Positions of the Major Planets"): elements against the J2000 ecliptic, their rates per century,
and the b, c, s, f terms of Jupiter to Pluto, fit for 3000 BC to AD 3000. Table 1 is closer near
the present (Saturn 0.23 degrees at worst 1950-2100, against 0.32 here) but is only fit for
1800-2050, and by AD 3000 has Saturn 4.3 degrees out where Table 2 holds every planet within 0.3.
The moons take JPL SSD's satellite mean elements: sidereal mean motion n to ten figures, the
periods of their node and periapsis, and each one's local Laplace plane by its pole. They
propagate with n itself, never a GM: gmForParent and its mass table are gone. Horizons still
gives size, spin and obliquity.

Both tables are read from the Internet Archive's copy of JPL's pages, pinned to one capture: the
live approx_pos page has dropped Pluto, and the live sats/elem page has dropped n and rounds the
period to four or five figures (Phobos 0.3187 d, a revolution out within a decade).

What the tables leave implicit, measured against Horizons before it was accepted:
- The precession periods are magnitudes. A node regresses on a prograde orbit and advances on a
  retrograde one; a periapsis advances except where a resonance forces the eccentricity. Io's
  and Europa's follow their conjunction line backwards at 2 n(Europa) - n(Io) = 0.74 degrees a
  day, which is exactly the 1.625- and 1.394-year periods in the table. Read as advancing, Io
  was 0.9 degrees out and Europa 2.1.
- On a retrograde orbit the node's turning is added back to the mean anomaly. Taken off, Triton
  drifted a degree a year, 105 degrees by 2100.
- The Laplace frame's x axis is where the plane rises through the ICRF equator, RA of the pole
  plus 90. Read against the ecliptic, Io was 2.8 degrees out, Phobos 54 and Titan 127.

Orbit lines are now drawn in their own plane and turned by a quaternion each tick, so a turning
node carries the line with the body: fixed at one date, the Moon's line would be up to 69 000 km
off it nine years on. The Earth row is the Earth-Moon barycentre, 4 700 km from Earth, 0.002
degrees from the Sun. A tidally locked moon's day is now 360 / n, its sidereal period (the Moon
27.321662 d), so it stays locked to the orbit it is drawn on.

Angular error against Horizons VECTORS (ICRF, TDB; heliocentric for planets, planet-centred for
moons), degrees, read from the live renderer's markers in the running app:

body       1950-01-01 1975-01-01 1987-07-23 2000-01-01 2025-01-01 2037-03-06 2050-01-01 2075-01-01 2100-01-01   max
mercury         0.004      0.002      0.003      0.002      0.002      0.001      0.000      0.002      0.000  0.004
venus           0.003      0.007      0.003      0.004      0.004      0.004      0.003      0.004      0.004  0.007
earth           0.003      0.008      0.002      0.005      0.004      0.009      0.003      0.002      0.003  0.009
mars            0.009      0.010      0.008      0.024      0.009      0.012      0.009      0.011      0.028  0.028
jupiter         0.063      0.030      0.171      0.135      0.013      0.020      0.056      0.041      0.075  0.171
saturn          0.080      0.064      0.018      0.320      0.066      0.114      0.044      0.164      0.177  0.320
uranus          0.018      0.169      0.068      0.050      0.101      0.015      0.141      0.017      0.114  0.169
neptune         0.070      0.028      0.004      0.021      0.036      0.037      0.013      0.029      0.072  0.072
pluto           0.045      0.054      0.041      0.033      0.019      0.020      0.023      0.027      0.026  0.054
moon            0.486      1.928      0.127      0.631      1.407      1.086      0.720      0.339      1.180  1.928
phobos          2.068      0.294      0.881      1.113      0.313      0.636      2.089      5.862     11.099 11.099
deimos          0.077      0.043      0.310      0.066      0.164      0.068      0.034      0.468      0.044  0.468
io              0.021      0.015      0.010      0.019      0.009      0.035      0.006      0.011      0.022  0.035
europa          0.036      0.039      0.053      0.064      0.078      0.032      0.006      0.034      0.044  0.078
ganymede        0.132      0.103      0.018      0.007      0.023      0.054      0.091      0.118      0.044  0.132
callisto        0.040      0.019      0.023      0.019      0.038      0.008      0.060      0.119      0.056  0.119
titan           0.003      0.019      0.023      0.023      0.027      0.028      0.048      0.008      0.014  0.048
triton          0.051      0.029      0.009      0.021      0.052      0.048      0.063      0.089      0.137  0.137

Three miss what was hoped for, and why:
- Jupiter 0.17, Saturn 0.32, Uranus 0.17 against the 0.1 hoped for: short-period perturbations
  of the giants by one another, which no Keplerian fit carries. Standish states his own Table 2
  errors as 600, 1 000 and 2 000 arcseconds (0.17, 0.28, 0.56 degrees). Out to AD 3000, measured
  at 1800, 2200, 2400, 2600 and 3000, every planet stays within 0.3.
- The Moon, 1.9: evection (1.27) and variation (0.66), which a mean ellipse leaves out.
- Phobos, 2.1 until 2050, then 5.9 in 2075 and 11.1 in 2100, growing as the square of the time:
  its tidal acceleration, which the table has no column for. Its elements are MAR080's, epoch
  1950. The map's dates are also UTC where the elements are TDB, 69 s today,
  which is 0.9 degrees of Phobos and nothing for anything else.

Held in place by:
- build.ts: each body's mean elements against Horizons' own osculating elements on the ETL's
  2025-01-01, at most 0.25 degrees for a planet and 2.5 for a moon (measured: Uranus 0.101, the
  Moon 1.407; a regressing Triton node reads 10.24 and fails), and every moon's day equal to its
  sidereal period (a 1% error fails).
- Unit tests freezing nine Horizons vectors (Earth 2100, Jupiter 1950, Saturn 2075, Pluto 1975,
  the Moon 2050, Io and Europa 1950, Titan and Triton 2100) through SystemOrbitsRenderer, the
  Moon kept on its own turning line, the retrograde rule, the Standish terms, the Laplace frame,
  and both table parsers. Nine mutants each fail the test named for them, and the two
  validators each refuse a mutated build of the real catalogue.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 20:18:57 +02:00
SenrokaiandClaude Opus 5.5 c64eea0803 Keep every star the naked eye sees, Rigel, Deneb and Alnilam among them
The 250 pc cutoff took 1 543 of HYG's 8 920 stars of V 6.5 or brighter:
1 339 that both surveys put past it and 204 HYG has no distance for. Five
of the fifty brightest stars in the sky were gone (Rigel, Deneb, Alnilam,
gamma-2 Vel, Wezen), and Naos, Sadr, Aludra and Arneb with them, while
11th-magnitude Gaia stars at the same distance were drawn. The cutoff
bounds a download, not what the sky shows.

placementDistancePc now keeps a star of V 6.5 or brighter at any distance,
at the better of its two distances as before: Gaia's where the archive's
Hipparcos cross-match has a usable parallax, Hipparcos's otherwise. Gaia
saturates on the brightest, so Rigel (264.6 pc), Deneb (432.9), Alnilam
(606.1), Wezen (492.6), Naos, Sadr, Aludra and Arneb sit at their
Hipparcos distance. 1 502 HYG rows come back, 165 of the 206 without a
Hipparcos distance among them because Gaia measured them; 36 fold into a
Gaia entry. 41 naked-eye stars stay out because neither survey gives them
a distance: beta Phe, Polis, Mu Cep, Rho Cas, Eta Car, Alp Cam, Phi Cas,
Chi Aur, Psi-1 Aur, theta-1 Ori, Omi-1 Cen, 66 Ori, 16 Sgr, 10 Sge and 27
HD stars.

Measured on the rebuilt catalogue: 425 117 stars (+1 466), 8 301 of them
past 250 pc (+1 466), the same 336 within 10 pc and 3 652 within 25 pc.
Merge gate: 12 352 HYG rows without a Gaia counterpart (was 10 886; the
ceiling of 15 000 is unchanged, and its comment now counts the naked-eye
stars among the survivors) and the same 23 cross-catalogue pairs under an
arcsecond. Five more exoplanets find their host: HD 81817 b and c,
HD 158996 b, HD 208527 b, HD 220074 b. gzip -9 sizes: stars.bin
4 711 922 -> 4 728 315 B, stars-meta.bin 2 576 213 -> 2 587 977 B,
stars-index.json 3 724 855 -> 3 731 763 B.

The brief behind this also asked to cut once on the best distance, which
would drop the 6 835 stars Hipparcos puts inside 250 pc and Gaia outside.
Those already sit at Gaia's distance (4eb61ff), so nothing is misplaced,
and they stay.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 19:36:34 +02:00
SenrokaiandClaude Opus 5.5 c38a42cbcb Fix what the review of this branch found, starting with the pick rule it only claimed
The off-screen rule for clicks was described in 3f0abf8 and in the pull request, but only its
comment was committed: pickAt still let the slop reach past the frame. The mutant that was said
to catch it matched nothing, and an unrelated flaky test failed instead. The frame test is now in
pickAt, before the slop, and its test fails without it (star at NDC 1.01, click at 0.995).

Venus, Uranus and Pluto turned forwards: Horizons states a retrograde spin twice, by a negative
rate and by an obliquity over 90 degrees, and both were applied. The period's sign is now used
only when no obliquity is known. Measured on the live markers, spin axis against orbit normal is
cos(obliquity) for each: Venus -0.999, Uranus -0.135, Pluto -0.494, Earth 0.917.

Moons listed as rates rather than "Synchronous" drifted about 5 degrees an orbit and Titan did not
turn: every moon is now locked at its Kepler period. Pluto's obliquity comes from IAU WGCCRE 2015,
Horizons gives none.

Also:
- the star's light is white at pi, not a warm 2.2 that left the photographs dim;
- procedural textures are 128x64, not 512x256 that froze the main thread ~60 ms a body;
- Io, Pluto, Titan and Deimos lose their "maps", which were disc photographs with black sky;
- an exoplanet with only a mass gets a radius from it (M^0.55, capped at Jupiter), not Earth's;
- the clock knows when it has left the present even once back at real time, so the date and
  "Back to now" stay up.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 18:50:07 +02:00