heliacal_visibility_implementation_roadmap - TheDaniel166/moira GitHub Wiki
Heliacal / Visibility Implementation Roadmap
Status:
- roadmap
Purpose:
- define the implementation sequence for Moira's generalized heliacal and visibility subsystem
- preserve the distinction between astronomical substrate, visibility model, observer environment, and event semantics
- make room for light-pollution-aware visibility policy without collapsing the engine into a loose workflow surface
This roadmap assumes the current baseline:
- concrete planetary heliacal/acronychal event functions already exist
moira.heliacalalready definesHeliacalEventKind,VisibilityModel, andHeliacalPolicy- many physical ingredients already exist elsewhere in the engine
What remains open is not basic event computation.
What remains open is the generalized visibility doctrine:
- configurable visibility criteria
- observer-environment policy
- light pollution
- generalized event family semantics
- summit-grade validation
1. Governing Decision
Moira should not implement a Swiss-style visibility flag matrix.
The subsystem must instead preserve four distinct strata:
- astronomical substrate
- observer environment
- visibility model / contrast doctrine
- event semantics and search logic
Only after those strata are explicit should Moira expose a generalized public visibility surface.
2. Existing Baseline
Already present in the engine:
- topocentric geometry
- rise/set doctrine
- twilight structure
- atmospheric refraction helpers
- brightness-related planetary quantities in existing result surfaces
- concrete heliacal/acronychal planetary event functions
- typed heliacal doctrine vessels in
moira.heliacal
Therefore the missing work is compositional, not foundational.
3. Core Law
Moira must keep these categories distinct:
- exact astronomical state
- visibility-model policy
- observer-environment policy
- event-search policy
Light pollution belongs to observer-environment policy.
It must not be smuggled in as:
- a loose keyword on event functions
- an undocumented limiting-magnitude tweak
- a hidden convenience adjustment
If visibility depends on the observer's site conditions, that dependency must be visible in a typed policy object.
4. Layer Model
4.1 Astronomical substrate
This layer answers:
- where is the body?
- where is the Sun?
- how bright is the body geometrically/apparently?
- what is the twilight state?
- what is the topocentric horizon geometry?
This layer should remain in the owning astronomical modules.
4.2 Observer environment
This layer answers:
- what sky quality does the observer have?
- what local horizon obstruction exists?
- what effective dark-sky limit applies?
- what observing aid is being used?
This is where light pollution belongs.
4.3 Visibility doctrine
This layer answers:
- what contrast or threshold law defines "visible"?
- how is extinction applied?
- how is twilight brightness treated?
- what relationship between body brightness and sky background is required?
4.4 Event semantics
This layer answers:
- what event kind is being searched?
- what counts as first visibility vs last visibility?
- what search horizon is admissible?
- what transition criterion closes the event?
5. Phase V0 — Constitutional Cleanup
Goal:
- turn the current heliacal design vessel into a true subsystem constitution record
Deliverables:
- document the current implemented event functions versus the still-deferred generalized family
- state explicitly that
VisibilityModelis currently too narrow to serve as the full future policy surface - define the engine boundary:
- astronomy stays outside
moira.heliacal - event search may live in heliacal/visibility code
- workflow/service orchestration remains out of scope
- astronomy stays outside
Exit criteria:
- the constitution says exactly what is already implemented
- the deferred frontier is named explicitly
6. Phase V1 — Observer Environment Policy
Goal:
- define the observer environment layer cleanly before adding more visibility doctrine
Deliverables:
V1.1 Observer environment vessel
Introduce a dedicated immutable vessel, for example:
ObserverVisibilityEnvironment
light_pollution_class
limiting_magnitude
local_horizon_altitude_deg
temperature_c
pressure_mbar
relative_humidity
observer_altitude_m
observing_aid
Notes:
light_pollution_classshould not be a free-form descriptive string. It should be a closed policy field representing a recognized observing-sky darkness class, preferably a Bortle-style enum or equivalent ordinal scale. Its role is environmental classification, not direct photometric truth.limiting_magnitudeshould remain directly settable, but its semantics must be explicit: it is the operative visibility-threshold value used by the engine. It may be supplied as an explicit user override or derived from the active light-pollution policy.local_horizon_altitude_degremains a separate geometric constraint. It must not be conflated with atmospheric refraction or sky-brightness policy. It describes obstruction of the observer's actual horizon profile.
These fields belong to different domains:
light_pollution_classis a site-environment classifierlimiting_magnitudeis a visibility-threshold parameterlocal_horizon_altitude_degis a geometric horizon constraint- atmospheric refraction is an apparent-altitude correction
Do not let these fields pretend to do the same job.
V1.2 Light pollution doctrine
Define a typed light-pollution policy:
- minimum admitted representation: Bortle class or equivalent
- optional direct sky-brightness override later if justified
The first implementation should be simple and explicit:
- one typed classification
- one documented mapping into limiting magnitude / sky-brightness assumptions
Policy law:
- light pollution influences limiting magnitude, but is not identical to it
- local horizon altitude affects whether something is geometrically visible above the observer's horizon, but not how bright the sky is
- atmospheric refraction alters apparent altitude near the horizon, but is not the same thing as the terrain/building horizon
Precedence law:
- if
limiting_magnitudeis explicitly provided, it supersedes any value derived fromlight_pollution_class - if it is absent, the engine may derive an estimated limiting magnitude from the active light-pollution policy and other declared observing assumptions
V1.3 Aid policy
Replace bare optical_aid: str style policy with a typed observer-aid enum.
Keep the first admitted family narrow:
- naked eye
- binoculars
- telescope
V1.4 Backward-compatibility relation
Current VisibilityModel should either:
- become a narrower internal/input vessel consumed by the new environment policy, or
- be deprecated in favor of the fuller environment object
Exit criteria:
- light pollution has a declared home
- observer environment is no longer conflated with visibility doctrine
7. Phase V2 — Visibility Physics / Contrast Doctrine
Goal:
- define what "visible" means mathematically
Deliverables:
V2.1 Visibility criterion family
Introduce a typed criterion family, for example:
VisibilityCriterionFamily
LIMITING_MAGNITUDE
CONTRAST_THRESHOLD
SCHAEFER_STYLE
The exact admitted names can differ, but Moira must not pretend one criterion family stands for all visibility doctrine.
V2.2 Visibility policy
Introduce a fuller immutable policy, for example:
VisibilityPolicy
criterion_family
extinction_model
twilight_model
environment
use_refraction
moonlight_policy
This policy governs:
- extinction treatment
- twilight brightness treatment
- whether moonlight is ignored, included, or approximated
- how the environment is applied
V2.3 Initial admitted criterion
Admit only one narrow first criterion family.
Recommended first freeze:
- limiting-magnitude / extinction / twilight threshold family
Reason:
- Moira already has many of the ingredients
- it is easier to validate than a more ambitious contrast-physics model
- it provides a clean place for light pollution to matter
This first admitted family should be named explicitly, for example:
LIMITING_MAGNITUDE_THRESHOLD
In this first family:
light_pollution_classdoes not directly enter the visibility equations as a physical variable- it is a policy input that maps to an estimated sky condition
limiting_magnitudeis the actual operational quantity that enters visibility filteringlocal_horizon_altitude_degis a geometric cutoff applied to apparent altitude after refraction
V2.4 Exact vs approximate classification
The subsystem must distinguish:
- exact astronomical geometry
- exact arithmetic under the admitted criterion
- approximate environmental / observational assumptions
Visibility is inherently model-dependent. That fact must stay visible.
V2.5 First admitted formula chain
For the first admitted criterion family, the formulas should be layered like this:
- derive the operative limiting magnitude
- compute apparent altitude from true altitude plus refraction
- apply geometric horizon filtering
- apply brightness filtering
Canonical precedence law:
effective_limiting_magnitude =
user_limiting_magnitude
if user_limiting_magnitude is not None
else policy_limiting_magnitude(light_pollution_class)
Recommended first derivation policy:
- make the light-pollution-to-limiting-magnitude mapping explicit and auditable
- prefer a named policy rather than a hidden heuristic
Admissible first policy examples:
Table form:
Bortle 1 → 7.6
Bortle 2 → 7.1
Bortle 3 → 6.6
Bortle 4 → 6.1
Bortle 5 → 5.6
Bortle 6 → 5.1
Bortle 7 → 4.6
Bortle 8 → 4.1
Bortle 9 → 3.6
or the equivalent linear policy:
policy_limiting_magnitude(bortle_class) = 8.1 - 0.5 * bortle_class
These values are policy values, not sacred physics. Their importance is that they remain explicit and inspectable.
Altitude chain:
apparent_altitude =
true_altitude + refraction_correction(true_altitude, pressure, temperature)
Geometric admission:
is_geometrically_visible =
apparent_altitude >= local_horizon_altitude_deg
Brightness admission:
is_bright_enough =
apparent_magnitude <= effective_limiting_magnitude
Combined first-family observational admission rule:
observable =
is_geometrically_visible and is_bright_enough
This keeps the roles clean:
- light pollution informs the threshold but is not the threshold
- threshold filters brightness only
- local horizon filters geometry only
- refraction modifies altitude only
Exit criteria:
- a visibility event can be said to occur under a named criterion family
- light pollution and extinction are applied through declared policy
8. Phase V3 — Generalized Event Semantics
Goal:
- widen the event family beyond the currently admitted concrete helpers
Deliverables:
V3.1 Generalized event search surface
Introduce a central search surface, for example:
visibility_event(
target,
event_kind,
jd_start,
latitude,
longitude,
*,
heliacal_policy,
visibility_policy,
search_policy,
)
This should not replace the existing narrow helpers immediately. Those helpers can become thin stable wrappers over the generalized surface.
V3.2 Search policy
Introduce a dedicated search policy:
VisibilitySearchPolicy
search_window_days
coarse_step_days
refine_tolerance_days
long_search
Search policy must remain separate from visibility doctrine.
V3.3 Event family expansion
Current concrete family already includes:
- heliacal rising
- heliacal setting
- acronychal rising
- acronychal setting
Future admitted family may also include:
- cosmic rising
- cosmic setting
- generalized first/last visibility under named criterion families
V3.4 Planet vs star boundary
This phase must keep target-family semantics explicit:
- planets
- stars
- Moon
Stellar events should route through the star subsystem rather than bypass it.
Exit criteria:
- one generalized search surface exists
- current concrete helpers can be expressed through it
- event semantics remain typed and explicit
9. Phase V4 — Validation Program
Goal:
- establish summit-grade validation before widening public claims
Deliverables:
V4.1 Validation strata
Validation must be stratified:
-
astronomical geometry validation
- topocentric altitude / azimuth
- twilight state
- elongation
- apparent magnitude
-
criterion validation
- visibility threshold behavior under synthetic conditions
- light-pollution mapping sanity
- extinction sensitivity
-
event validation
- known published heliacal events
- modern planetary apparition windows
- historical stellar events where source quality is strong enough
V4.2 Authority hierarchy
Prefer:
- primary observational/astronomical literature
- domain-primary heliacal sources where explicit methods are given
- then specialist secondary software only as comparison layers
Do not let Swiss become the summit authority for visibility doctrine.
V4.3 Validation corpus
Build a validation corpus split into:
- modern planetary events
- historical planetary events
- stellar events
- edge cases: poor transparency, bright twilight, low-altitude horizons
V4.4 Tolerance doctrine
Tolerance should be declared by validation family:
- event date windows
- event time windows
- acceptable model divergence under different criterion families
Exit criteria:
- public docs can state what has been validated and under which criterion
- Moira avoids false precision claims in observational-visibility work
10. Phase V5 — Public Surface Widening
Goal:
- expose the generalized subsystem only after doctrine and validation are stable
Recommended order:
- keep the owning surface in
moira.heliacal - preserve narrow wrappers for concrete planetary events
- expose generalized policies and generalized search only after V1-V4 are complete
- delay package-root widening until the criterion family and environment policy are stable
Do not start with facade-first convenience.
11. Phase V6 — Optional Enhancements
These are valid, but should remain later:
- moonlight-aware sky brightness
- terrain/horizon profile integration
- stellar catalog-wide heliacal batch search
- observer-experience scaling
- wavelength-specific visibility refinements
- research comparison against multiple visibility doctrines
These are later because they increase model sensitivity and validation burden faster than they increase core engine truth.
12. Proposed Data / Policy Objects
Minimum near-term target set:
LightPollutionClass
ObserverAid
ObserverVisibilityEnvironment
VisibilityCriterionFamily
VisibilityPolicy
VisibilitySearchPolicy
VisibilityAssessment
GeneralVisibilityEvent
The exact names may change. The separation of responsibilities should not.
13. Recommended Implementation Order
The smallest correct path is:
- V0 constitutional cleanup
- V1 observer environment policy
- V2 one admitted visibility criterion family
- V3 generalized event search surface
- V4 validation corpus and tolerance doctrine
- only then wider public exposure
This order is mandatory if light pollution is to be admitted honestly.
If light pollution is added before V1 and V2 are explicit, it will almost certainly become an undocumented fudge factor rather than a truthful engine policy.
14. Immediate Next Move
The immediate next move should be:
- revise
moira.heliacalso it distinguishes:- current concrete event surfaces
- current narrow policy vessels
- still-deferred generalized visibility doctrine
- define
ObserverVisibilityEnvironmentandLightPollutionClass - freeze one initial visibility criterion family before any larger event widening
That is the smallest path that makes room for light pollution without losing Moira's engine discipline.