Skip to content

feat: Milliquas bin v5 + ΛCDM distances + observable-universe horizon shell#186

Open
rulkens wants to merge 23 commits into
mainfrom
worktree-milliquas-bin-class-byte
Open

feat: Milliquas bin v5 + ΛCDM distances + observable-universe horizon shell#186
rulkens wants to merge 23 commits into
mainfrom
worktree-milliquas-bin-class-byte

Conversation

@rulkens
Copy link
Copy Markdown
Owner

@rulkens rulkens commented May 20, 2026

Summary

Bundles three pieces of work on top of the Milliquas bin-v5 change. Merged with main (#182#185 SOURCE_REGISTRY + unified selection refactors).

1. Milliquas bin v5 (AGN class + parent survey)

  • Bump on-disk galaxy-catalog format v4 → v5 with two new per-record bytes (classByte + parentSurveyByte) carved from the existing tail padding; the 64-byte stride is unchanged.
  • Populate the bytes for Milliquas in the parser (AGN class Q/A/B/K/N/S → 1..6; parent survey SDSS/2MASX/GAIA/WISEA/NVSS/FIRST/6dFGS → 1..7).
  • Reconstruct the historical "<PARENT> J<RA><Dec>" Milliquas display name in the InfoCard purely from the bin via a shared iauRaDecSuffix(ra, dec) helper; add agnClass? to GalaxyInfo.
  • Delete the Milliquas _names.json sidecar pipeline end-to-end (fetcher, slot, payload type, engine wiring, R2 ALLOW entry).

2. ΛCDM comoving distances

  • Replace the linear-Hubble redshift↔distance approximation with a proper flat-ΛCDM comoving-distance integral (Planck-2018 Ωm=0.315), Simpson-integrated forward and LUT-accelerated bisection inverse.
  • Behind a build-time USE_LCDM_DISTANCES flag for quick A/B toggling against the old linear variant.
  • Far clip + camera zoom envelope bumped (FAR_CLIP_MPC 6000→50000, MAX_DISTANCE_MPC 5000→30000) so the full observable volume — high-z quasars + horizon shell — stays in frustum.
  • Hot paths that discard redshift now use a lighter cartesianToRaDec to avoid the inverse-LUT cost per galaxy.

3. Observable-universe horizon shell

  • Translucent Fresnel-rim sphere at the comoving particle horizon (~14.3 Gpc), drawn as an analytic ray-marched sphere (fullscreen quad, per-pixel ray-sphere intersection in Gpc units to dodge fp32 precision dropouts at that radius).
  • Distance-faded: ramps in as the camera pulls back to cosmological scale (5%..40% of the shell radius), the mirror image of the Milky-Way impostor's near-volume fade; both now share a single smoothstep primitive. Gated in the pass's enabled() so a faded-out shell skips its full-screen pass and GPU-timings slot.

File-format impact

encodeGalaxyCatalog writes version=5. Existing v4 .bin files fail loudly with unsupported version: 4 — please regenerate via "npm run build-tiers". Do NOT merge before running npm run sync-r2 against a freshly-rebuilt public/data/ (the R2 sync also deletes the orphaned milliquas-*_names.json keys).

Regenerated data sizes (v5 + ΛCDM positions)

File Size
sdss-medium.bin ~9.5 MB
sdss-large.bin ~30 MB
glade-small.bin ~16 MB
glade-medium.bin ~24 MB
glade-large.bin ~122 MB
milliquas-medium.bin ~12 MB
milliquas-large.bin ~58 MB
2mrs.bin ~2.4 MB
famous.bin ~4.8 KB
Total (all variants) ~274 MB

(Dropping the milliquas-*_names.json sidecars saves ~34 MB of per-session network transfer.)

Test plan

  • npm run typecheck passes (both src and tools tsconfigs).
  • npm test passes — 1697/1697 across 270 files.
  • npm run build-tiers regenerates every public/data/*.bin and emits no _names.json files.
  • Merge with main (refactor(sources): SOURCE_REGISTRY as the single registry of every data source #182refactor(volumes): close VolumeFieldId set + unify volumes under SOURCE_REGISTRY #185) resolved; SOURCE_REGISTRY + unified galaxy/POI selection adopted, this PR's deltas (v5 bytes, ΛCDM, horizon shell) ported on top.
  • npm run sync-r2 uploads new v5 bins and deletes the milliquas-*_names.json keys. Deferred — run before merging.
  • Manual smoke: hover a Milliquas point with a known parent survey → InfoCard headline shows "SDSS J…" (not the "MQ J…" IAU fallback); known class letter Q → AGN class row shows "Quasar".
  • Manual smoke: zoom out past ~1 Gpc → horizon shell smoothsteps in, full by ~5.7 Gpc, gone at galaxy scale.

🤖 Generated with Claude Code

rulkens and others added 19 commits May 20, 2026 16:30
Factor the J<RA><Dec> coord-suffix builder out of iauName so any
consumer that needs to glue a non-survey prefix onto an IAU coord
string can share one byte-identical emitter.  Pins the historical
output via a regression test against iauName.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The case comment named parentSurveyByte / OTHER sentinel / galaxyInfoBuilder
machinery that doesn't yet exist at this commit.  Trim to a forward-neutral
note about the upstream catalogue convention so this commit stands on its
own under bisect.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two new per-record uint8 typed-array fields, ready to be threaded
through the binary format (Task 3) and the build pipeline (Task 4).
Standalone type-only commit so the format bump that follows is a
focused diff.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…y bytes

Two new per-record uint8 slots at offset 52/53, carved from the v4
tail padding without changing the 64-byte stride.  v4 files are now
rejected with the documented "regenerate via npm run build-tiers"
error.  classByte carries the per-source class enum (Milliquas
class letter today); parentSurveyByte carries the Milliquas
parent-survey enum so the InfoCard can reconstruct the historical
"<PARENT> J<RA><Dec>" display name without the JSON sidecar.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
makeCloud / makeOrientCloud and the four inline GalaxyCatalog literals now
carry zero-filled classByte + parentSurveyByte so the v5 type is satisfied.
The cross-version rejection list extends from {v1, v2, v3} to {v1, v2, v3,
v4}, and the regenerate-message assertion follows the docstring's
"build-tiers" wording.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces "v3-specific" / "v4-specific" / "v4 (orientation round-trip)"
describe titles with timeless, behaviour-focused names (orientation
round-trip; diameterKpc + stride + rejection).  The tests themselves
already work against the current v5 encoder, so the rename is purely
documentation hygiene.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…sToCloud

Defaults are 0 across the board; the next task wires up each
parser to populate the new fields (zero for everyone except
Milliquas, which carries the AGN class + parent-survey prefix).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…n-Milliquas sources

Adds the two new bytes (zero-defaulted) at every non-Milliquas
GalaxyCatalog construction site: the three ParsedRecord-building
parsers (sdssCsv, twoMrs, glade), the Famous compiler (buildFamous
constructs GalaxyCatalog directly, not via ParsedRecord), the
runtime synthetic-cloud generator, and the Worker-transfer clone.
Future per-survey class signals (e.g. GLADE morphology) can
override these defaults locally without touching the pipeline.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…kups

sourceClassLabel(source, byte) maps the bin's classByte slot to a
human string (Milliquas Q/A/B/K/N/S today; null for every other
source).  milliquasParentSurveyPrefix(byte) maps the
parentSurveyByte to a display string (SDSS/2MASX/GAIA/…) for the
InfoCard's display-name reconstruction.  Constants are reused by
the Milliquas parser.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drop the parallel names/classes sidecar return shape in favour of
per-record uint8 bytes that round-trip through the v5 .bin format.
The InfoCard reconstructs "<PARENT> J<RA><Dec>" at hover time from
the parentSurveyByte + iauRaDecSuffix(ra, dec), with the IAU
"MQ J<RA><Dec>" fallback for literature designations.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per-record classByte + parentSurveyByte now ride on the .bin (Task
6), so the build no longer emits the parallel JSON sidecar.
subsampleByAbsMag's value-returning variant preserves the bytes
through the brightest-N subset; the indices-returning variant
becomes dead code and its import goes too.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reconciles buildAllBins.milliquas smoke test with the v5 byte fields
landing in Task 6/7: the parser no longer returns `names`, so the
"sidecar invariant" assertion is replaced with a per-record class +
parent-survey byte round-trip through recordsToCloud and
encode/decode.  Other pipeline coverage (NaN-able photometry,
morphology fallbacks, diameterKpc default) is preserved.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The v5 .bin format carries the Milliquas display-name ingredients
(class byte + parent-survey byte) per record, so the JSON sidecar
+ fetcher + slot + EngineSourceState fields + companion-asset
registry row are all dead weight.  Drop them, leaving the
buildGalaxyInfo signature one parameter shorter — that parameter
is replaced by the byte-driven reconstruction in the next task.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drop the milliquasNames runtime parameter; instead, read the v5
.bin's per-record classByte (for the InfoCard's AGN class row) and
parentSurveyByte (for "<PARENT> J<RA><Dec>" display-name
reconstruction).  GalaxyInfo grows an optional `agnClass` field
for the AGN class row.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…veat

GalaxyInfo's agnClass JSDoc now describes the absent-row consumer
contract as an expectation rather than asserting current InfoCard
code; the consumer gate (`info.agnClass && (…)`) is the intended
pattern, not a present-day claim.

galaxyInfoBuilder's milliquasDisplayName comment now notes that the
J-suffix is recomputed from the row's stored coords and may differ
in least-significant digits from the upstream catalogue's Name
column, heading off "why doesn't this match Milliquas v8 byte-for-
byte?" investigations.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the milliquasNames-arg assertions with classByte +
parentSurveyByte assertions that exercise the full v5 byte
vocabulary (six class letters, seven parent-survey prefixes, the
OTHER fallback, and the non-Milliquas no-op).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…xtures

Sweep across every test that constructs a GalaxyCatalog or ParsedRecord
literal directly, defaulting the two new v5 bytes to zero (or to the
distinguishing fill values used by the cloneGalaxyCatalogForTransfer
test).  Also extends the transfer-list count assertion from 10 to 12,
flips the galaxyCatalogFetcher mock header from v4 to v5, and adds a
classByte/parentSurveyByte default to the subsampleByAbsMag test rec
factory.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The v5 .bin format carries the Milliquas class + parent-survey
metadata per record, so the JSON sidecar is dead.  Drop it from
the ALLOW filter and add an idempotent delete step that removes
any leftover small/medium/large names.json keys from R2 on every
sync.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
famous.bin is a 75-row curated catalogue checked into git (the bulk
survey bins are gitignored).  The v4→v5 format bump invalidates the
old bytes — re-encoded via `npm run build-famous` against the freshly
rebuilt 2mrs.bin and glade-large.bin.  Same 4816-byte stride; only the
version byte at offset 4 and the new classByte/parentSurveyByte slots
(zero-filled for Famous) changed.  famous_xrefs.json picks up a few
cross-match shifts from the new GLADE row order.  Also commits the
implementation plan doc that drove this branch.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 20, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
skymap f09ea31 Commit Preview URL

Branch Preview URL
May 21 2026, 02:56 PM

rulkens and others added 4 commits May 21, 2026 16:19
…rvable volume

Replace the linear-Hubble redshift→distance approximation with a flat-ΛCDM
Simpson integral (and a LUT-backed bisection inverse), gated behind
USE_LCDM_DISTANCES so the linear mode stays one edit away. Positions past
z≈0.3 were off by tens of percent; the Milliquas quasar tail now sits at its
correct ~9 Gpc instead of ~30 Gpc.

Split cartesianToRaDec out of cartesianToRaDecZ so the per-galaxy bake hot
paths skip the (now non-trivial) redshift inverse they always discarded.

Bump FAR_CLIP_MPC and the zoom envelope so the camera can reach and render
the full volume.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a translucent shell marking the comoving particle-horizon radius
(~14.3 Gpc), drawn as an analytic ray-marched sphere: a fullscreen quad
plus per-pixel ray-sphere intersection in the fragment, with Fresnel-rim
shading. Rays are built from the camera basis + FOV (no view-projection
inverse, which is unstable at the shell's huge near:far ratio) and the
intersection runs in Gpc units so the quadratic stays inside fp32's
precise range — eliminating the per-triangle dropouts and size jitter a
rasterised mesh suffered at these scales.

Wire it as an HDR pass after volume-upsample, with its own GPU-timing
slot (20/21).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The observable-universe shell now ramps in as the camera retreats
instead of drawing every frame. The fade band is a fraction of the
shell radius (5%..40%), the mirror image of the Milky-Way impostor's
near-volume fade, and both share a new smoothstep primitive. Gating
lives in the pass's enabled() so a faded-out shell skips its
full-screen ray-march pass and its GPU-timings slot entirely.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…n-class-byte

# Conflicts:
#	src/@types/engine/state/EngineAssetSlots.d.ts
#	src/@types/engine/subsystems/CreateSelectionSubsystemInput.d.ts
#	src/data/colourIndex.ts
#	src/data/galaxyCatalogFormat.ts
#	src/services/engine/camera/resolveFocusTarget.ts
#	src/services/engine/engine.ts
#	src/services/engine/helpers/galaxyInfoBuilder.ts
#	src/services/engine/subsystems/selectionSubsystem.ts
#	src/utils/math/iauName.ts
#	tests/@types/engineState.test.ts
#	tests/services/engine/subsystems/selectionSubsystem.test.ts
@rulkens rulkens changed the title feat(milliquas): fold AGN class + parent-survey into bin v5; drop names sidecar feat: Milliquas bin v5 + ΛCDM distances + observable-universe horizon shell May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant