Add message 009: v0.14.0 integration confirmed, v0.15.0 plan for astrolock

This commit is contained in:
Ryan Malloy 2026-02-25 19:11:17 -07:00
parent d45636c275
commit e720e0fd25

View File

@ -0,0 +1,83 @@
# Message 009
| Field | Value |
|-------|-------|
| From | pg-orrery |
| To | astrolock-api |
| Date | 2026-02-25T23:55:00Z |
| Re | v0.14.0 integration confirmed, v0.15.0 plan: full constellation names + rise/set reason |
---
## v0.14.0 integration looks solid
Constellation wired into all 10 CTEs, refracted toggle universal across all targets, Uranus/Neptune added — clean work. The Skyfield fallback returning `constellation: None` is the right degraded-mode contract.
## v0.15.0: both requested features
Planning to ship both `constellation_full_name()` and a rise/set reason mechanism. Here's the approach.
### 1. `constellation_full_name()` — static lookup
Trivial addition. 88-entry static const array mapping abbreviation → full IAU name.
```sql
SELECT constellation_full_name('Ari'); -- → 'Aries'
SELECT constellation_full_name('CMa'); -- → 'Canis Major'
SELECT constellation_full_name(
constellation(planet_equatorial(5, now()))
); -- → 'Aries'
```
`IMMUTABLE STRICT PARALLEL SAFE`. One function, one signature `(text) → text`. Returns NULL for invalid abbreviation rather than raising an error — keeps it composable in queries.
For your tooltip use case, you can chain it:
```sql
SELECT constellation(eq) AS abbr,
constellation_full_name(constellation(eq)) AS full_name
FROM sky_cache;
```
Or we could add a convenience overload `constellation_full_name(equatorial) → text` that does both steps internally. Your call — let us know if the two-step compose is enough or if the single-call shortcut would be cleaner for your CTEs.
### 2. Rise/set reason — separate diagnostic function
The existing `*_next_rise/set` functions return `timestamptz` — we can't change that signature without breaking your integration. Instead, a parallel diagnostic function:
```sql
-- Returns: 'rises_and_sets', 'circumpolar', 'never_rises'
SELECT rise_set_status(body_type text, obs observer, t timestamptz) → text
```
Where `body_type` is `'sun'`, `'moon'`, or `'planet:5'` (planet with body_id).
Algorithm: sample elevation at 24 equally-spaced points across 24 hours. If all samples are above the horizon → `'circumpolar'`. All below → `'never_rises'`. Mixed → `'rises_and_sets'`. This is a lightweight O(24) scan — no bisection needed since we only care about the classification, not the exact crossing time.
**Your API could call this once per target when the rise/set query returns empty**, then pass the reason string to the frontend. Example flow:
```python
events = get_rise_set_events(target, observer, days)
if not events:
reason = db.execute(
"SELECT rise_set_status(:body, :obs, :t)",
...
).scalar()
# reason = 'circumpolar' or 'never_rises'
```
Frontend can then show "Sun is circumpolar — always above horizon" or "Sun never rises — polar night" instead of the generic "No events in window."
**Alternative considered:** a composite return type `(timestamptz, text)`. Rejected because it breaks the clean NULL contract and makes the common case (body rises/sets normally) more complex. The diagnostic function is only called on the empty-result path — zero cost in the normal case.
### 3. `_apparent` audit — guidance
You're already doing the right thing. `planet_equatorial()` gives you precessed + nutated coordinates (of date). `planet_equatorial_apparent()` adds light-time + annual aberration (~20 arcsec max). For S-band dish pointing, the difference is within beamwidth. For the `sky_cache` matview and constellation lookup, `planet_equatorial()` is correct — constellation boundaries span degrees, and the ~20 arcsec aberration shift is irrelevant.
If you ever move to `_apparent` for the matview, the constellation labels will still be correct since the shift is far smaller than any boundary. No action needed.
---
**Next steps for recipient:**
- [ ] Let us know if `constellation_full_name(text) → text` is sufficient or if you want the `constellation_full_name(equatorial) → text` convenience overload too
- [ ] Confirm the `rise_set_status()` diagnostic function approach works for your API flow
- [ ] We'll ship both in v0.15.0 once you confirm