From c0ed91dcf97938d41da5b790f5b77e522d1138a3 Mon Sep 17 00:00:00 2001 From: Senrokai Date: Wed, 30 Sep 2026 19:42:37 +0200 Subject: [PATCH] Pin three rules the suite passed without: the first planet's temperature, the one-step error floor, and G carried to V by type publishedTemperaturesK keeps each host's first st_teff so the star field tints it as starSurfaceOf draws its disc; the only test used Proxima, with one planet, and letting the last row win passed all 828 tests while 189 hosts in the catalogue would be tinted apart from their disc (193 hosts give their planets differing st_teff, 30 by more than 200 K). The new test gives one host three rows, none, 4 094 and 3 640 K, and asks both functions for the same 4 094. The error column's at-least-one-step floor was tested with an error of 1e-6, which at 255 steps rounded to none but at f31ffe1's 65 535 rounds to 66, so dropping the floor passed. The fixture is now 1e-12, 0.07 of a step. 206e88a carries a G magnitude to V at the type's G-V where a star has no colour, and no test held it: the only type-only case was in V. The new case measures GJ 3655 in G, 3.11 brighter at M8, and asks for the V case's luminosity; taken as V it came out 17 times as luminous. Oph 11 (M9, G 18.91) is the one published star on that path. Guarded mutants, each caught by its named test alone (1 of 831 failed): - "hostStarTemperatureK && !temperatures.has(hostStarId)" -> "hostStarTemperatureK" - the Math.max(1, ...) floor removed - "(sequence?.gMinusV ?? 0)" -> "(sequenceAtColour(star)?.gMinusV ?? 0)" Co-Authored-By: Claude Opus 5.5 (1M context) --- .../features/body-detail/body-view-model.spec.ts | 15 ++++++++++++++- src/app/shared/astro/stellar.spec.ts | 10 ++++++++++ src/app/shared/models/star-catalog.spec.ts | 5 +++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/app/features/body-detail/body-view-model.spec.ts b/src/app/features/body-detail/body-view-model.spec.ts index 797df68..5a22777 100644 --- a/src/app/features/body-detail/body-view-model.spec.ts +++ b/src/app/features/body-detail/body-view-model.spec.ts @@ -3,7 +3,7 @@ import { describe, expect, it } from 'vitest'; import { BodyRecord, OrbitalElements } from '../../shared/models/body.model'; import { ExoplanetRecord } from '../../shared/models/exoplanet.model'; import { StarRecord, SUN_STAR_ID } from '../../shared/models/star.model'; -import { buildBodyViewModel, heliocentricPeriodDays, luminosityOf, starSurfaceOf } from './body-view-model'; +import { buildBodyViewModel, heliocentricPeriodDays, luminosityOf, publishedTemperaturesK, starSurfaceOf } from './body-view-model'; const orbit = (overrides: Partial = {}): OrbitalElements => ({ semiMajorAxisAu: 1, @@ -163,6 +163,19 @@ describe('starSurfaceOf', () => { expect(buildBodyViewModel('proxima-cen-d', catalogues)?.appearance.equilibriumTemperatureK).toBeCloseTo(296, 0); }); + it("gives the star field the temperature the disc is drawn at, where a host's planets give it different ones", () => { + // 193 hosts do: host 1070876212's three rows give 4 094, 4 094 and 3 640 K. The field is tinted + // from one map of every host and the disc from the host's own planets, so both must take the same row. + const rows = [ + { ...proximaB, id: 'd', hostStarTemperatureK: undefined }, + { ...proximaB, id: 'b', hostStarTemperatureK: 4094 }, + { ...proximaB, id: 'c', hostStarTemperatureK: 3640 }, + ]; + const other = { ...proximaB, id: 'other', hostStarId: 1, hostStarTemperatureK: 5000 }; + expect(starSurfaceOf(proxima, rows).temperatureK).toBe(4094); + expect(publishedTemperaturesK([...rows, other]).get(proxima.id)).toBe(starSurfaceOf(proxima, rows).temperatureK); + }); + it('derives both otherwise, and says the radius is derived', () => { const surface = starSurfaceOf(proxima, [proximaB]); expect(surface.radiusDerived).toBe(true); diff --git a/src/app/shared/astro/stellar.spec.ts b/src/app/shared/astro/stellar.spec.ts index 09e24e5..b2bbf89 100644 --- a/src/app/shared/astro/stellar.spec.ts +++ b/src/app/shared/astro/stellar.spec.ts @@ -11,6 +11,7 @@ import { SOLAR_BOLOMETRIC_MAGNITUDE, SOLAR_EFFECTIVE_TEMPERATURE_K } from './stellar'; +import { dwarfSequenceAtType } from './spectral'; /** Real catalogue rows, with the published luminosity each one should reproduce. */ const SIRIUS = { magnitude: -1.44, distancePc: 2.6371, spectralType: 'A0m...', publishedLuminosity: 25.4 }; @@ -214,6 +215,15 @@ describe('a dwarf with a type and no colour', () => { expect(radius / 0.114).toBeGreaterThan(1 / 1.2); expect(radius / 0.114).toBeLessThan(1.2); }); + + it("carries a G magnitude to V at its type's G−V", () => { + // The same star measured in G, which for an M8 dwarf reads 3.11 magnitudes brighter than V: taken + // as V, it came out 17 times as luminous. One published star takes this path, Oph 11 (M9, G 18.91). + const inV = { magnitude: 19.57, distancePc: 14.35, spectralType: 'M8', magnitudeBand: 'V', colorIndex: null } as const; + const inG = { ...inV, magnitude: 19.57 + dwarfSequenceAtType('M8')!.gMinusV!, magnitudeBand: 'G' } as const; + expect(dwarfSequenceAtType('M8')!.gMinusV).toBeLessThan(-3); + expect(luminositySolar(inG)!).toBeCloseTo(luminositySolar(inV)!, 12); + }); }); describe('radiusFromLuminositySolar', () => { diff --git a/src/app/shared/models/star-catalog.spec.ts b/src/app/shared/models/star-catalog.spec.ts index a788dc0..2d85b37 100644 --- a/src/app/shared/models/star-catalog.spec.ts +++ b/src/app/shared/models/star-catalog.spec.ts @@ -103,7 +103,7 @@ describe('the photometry and distance error columns', () => { { id: 1, name: 'Sirius', x: 1, y: 0, z: 0, magnitude: -1.44, magnitudeBand: 'V', spectralType: 'A0m', colorIndex: 0.009, colorSystem: 'B-V', distanceError: 0.0036, source: 'hyg' }, { id: 2, name: 'Gaia DR3 2', x: 0, y: 117, z: 0, magnitude: 11.2, magnitudeBand: 'G', spectralType: 'Unknown', colorIndex: 1.43, colorSystem: 'BP-RP', distanceError: 0.199, distanceFromGaia: true, source: 'gaia' }, // A HYG star at Gaia's distance, and one no survey gave a magnitude, a colour or an error. - { id: 3, name: 'HD 3', x: 0, y: 0, z: 300, magnitude: 7, magnitudeBand: 'V', spectralType: 'K0', colorIndex: 1.0, colorSystem: 'B-V', distanceError: 0.000001, distanceFromGaia: true, source: 'hyg' }, + { id: 3, name: 'HD 3', x: 0, y: 0, z: 300, magnitude: 7, magnitudeBand: 'V', spectralType: 'K0', colorIndex: 1.0, colorSystem: 'B-V', distanceError: 1e-12, distanceFromGaia: true, source: 'hyg' }, { id: 4, name: 'Gaia DR3 4', x: 5, y: 5, z: 0, magnitude: 12, spectralType: 'Unknown', colorIndex: null, distanceFromGaia: true, source: 'gaia' }, // A Hipparcos parallax smaller than its own error. { id: 5, name: 'HIP 5', x: 0, y: 200, z: 0, magnitude: 6, magnitudeBand: 'V', spectralType: 'B8', colorIndex: -0.1, colorSystem: 'B-V', distanceError: 1.4, source: 'hyg' }, @@ -124,7 +124,8 @@ describe('the photometry and distance error columns', () => { // A step is 0.05 % of distance at Sirius's 0.36 %, and 0.35 % at the 20 % Gaia's cut allows. expect(Math.abs(decoded[0].distanceError! - 0.0036)).toBeLessThan(0.0003); expect(Math.abs(decoded[1].distanceError! - 0.199)).toBeLessThan(0.002); - // Too small to round to a step, but published, so not read back as unpublished. + // Too small to round to a step — √(10⁻¹²) is 0.07 of one in 65 535 — but published, so not read + // back as unpublished. 10⁻⁶ was, at 255 steps; at 65 535 it rounds to 66 and never needed the floor. expect(decoded[2].distanceError).toBeGreaterThan(0); expect(decoded[3].distanceError).toBeUndefined(); // Past the parallax itself there is no upper bound on the distance, which is what 100 % says.