moira

Physical Heliacal Visibility Admission Doctrine

Date: 2026-08-07 Status: additive engine, facade, REST, data, validation, and local Phase 7 artifact gates closed; publication and deployment remain separate Governing roadmap: PHYSICAL_HELIACAL_VISIBILITY_IMPLEMENTATION_PLAN.md

Purpose

This document freezes the meanings, supported domain, failure law, data boundary, and additive public-contract shape for Moira’s physical heliacal-visibility project.

It is the implementation authority for the admitted opt-in physical assessment and event model. The existing legacy search remains the default public/facade/REST behavior; the additive physical contract does not silently reinterpret that compatibility surface. Phase 5 admitted the dedicated facade and REST transports, Phase 6 admitted two private numerical kernels, and Phase 7 binds the evidence, external resource, packaging, and release boundary.

Compatibility Boundary

The existing HeliacalEventKind enum is frozen with these six strings:

Their current calculations, defaults, return shapes, None behavior, facade behavior, and REST projection remain legacy contracts. The modernization must not:

The current CRUMEY_2014_POINT_SOURCE single-epoch assessment also remains unchanged. It is not silently widened from its admitted scotopic astronomical domain into a twilight event criterion.

Physical Model Identity

The first composite physical model identifier is:

clear_sky_naked_eye_point_source_v1

This is a first-class immutable model family, not a moving alias for “best available.” A policy preset may select it, but the preset must resolve to this exact identifier and expose every component identity.

The initial component identities are:

Component Frozen identifier Role
Directional atmosphere libradtran_2_0_6_mystic_spherical_v1 Offline-generated transmission and twilight radiance
Point-source detection blackwell_crumey_full_range_point_source_v1 Detection threshold across the generated twilight luminance domain
Spectral response cie_mes2_2010_v1 Declared photopic/scotopic interpolation, never an unnamed conversion
Observational lineage tousey_koomen_twilight_1953_v1 Independent twilight comparison cases

These identifiers have passed the Phase 1-3 engine gates, the Phase 5-6 transport and native gates, and the local Phase 7 offline artifact gate. They stay opt-in and do not become facade or REST defaults.

Physical Phase Taxonomy

The additive direct-module enum is PhysicalVisibilityPhase with exactly these four strings:

Value Within-day event Across-day ownership
morning_first_rising Opening of a visible interval connected to the target’s apparent rising before apparent sunrise First qualifying morning after a non-qualifying morning
morning_first_setting Closing of a visible interval connected to the target’s apparent setting before apparent sunrise First qualifying morning after a non-qualifying morning
evening_last_rising Opening of a visible interval connected to the target’s apparent rising after apparent sunset Last qualifying evening before a non-qualifying evening
evening_last_setting Closing of a visible interval connected to the target’s apparent setting after apparent sunset Last qualifying evening before a non-qualifying evening

This follows the four visible phases summarized from Ptolemy by Schironi: morning rising and setting are first appearances before sunrise; evening rising and setting are last appearances after sunset.

The words heliacal, acronychal, and cosmic are not used in this new enum. Modern usage of those labels is not consistent enough to carry the exact event law without the morning/evening, first/last, and rising/setting terms.

Legacy cosmic events remain legacy geometrical events. They are outside the new physical four-phase taxonomy.

Observation-Day Law

The API receives longitude but not a civil timezone. It therefore must not invent a civil date.

The physical solver assigns samples to a deterministic local mean solar day:

observation_day_key = floor(jd_ut + 0.5 + longitude_deg / 360)

longitude_deg uses Moira’s existing east-positive convention.

The key identifies the candidate local observing day. Results also return the complete UT Julian dates, so callers with a civil-time authority can project the event themselves.

search_window_days limits candidate phase-day keys. The solver may inspect one guard day before or after that interval solely to prove first/last ownership. A guard day cannot be returned as the requested event unless it is inside the caller’s candidate interval.

Observation-Window Law

For each candidate day, the solver constructs the connected interval in which:

Morning windows end at apparent sunrise. Evening windows begin at apparent sunset. Apparent sunrise and sunset use the same refraction and horizon policy as the returned window receipt.

A day qualifies only when a non-empty visible interval is connected to the relevant apparent target rising or setting. An isolated visibility island elsewhere in the night does not qualify as that target phase.

The visibility margin is:

visibility_margin(t)
    = limiting_magnitude(t) - conditioned_target_magnitude(t)

The boundary rule is:

If the horizon itself creates the transition, the threshold time may coincide with the apparent target rise or set. Otherwise the event time is the refined zero of the physical visibility margin inside the connected window.

The event receipt distinguishes visibility_margin and target_horizon boundary sources. A margin-root residual is required only for a visibility_margin boundary; it is not fabricated as zero for a horizon boundary.

The solver must find every candidate crossing and must separately detect a tangent or near-zero interval. Returning the first sampled visible time is not an event solution.

The first event admission binds a source-controlled Lipschitz/zero-enclosure certificate to the exact version 1.2 data pack. Same-sign intervals are excluded only when the admitted rate bound proves they cannot contain zero; otherwise they are recursively enclosed. A possible-zero interval without a witness fails closed as crossing_completeness_not_certified. Dense sampling alone is not called a completeness certificate.

First-Day and Last-Day Law

A morning phase is returned only if:

  1. the current morning qualifies;
  2. the immediately preceding comparable morning does not qualify; and
  3. both day classifications are evaluable.

An evening phase is returned only if:

  1. the current evening qualifies;
  2. the immediately following comparable evening does not qualify; and
  3. both day classifications are evaluable.

Missing evidence on either comparison day is not treated as “not visible.” It makes first/last ownership not evaluable.

Supported Physical Domain

Target class

The first admission is:

binocular here means use of both unaided eyes, not binocular optical equipment.

The observer protocol identifier is:

known_location_directed_averted_observation_v1

It assumes a continuous non-flickering target, natural pupils, a known target position, deliberate directed attention, and averted/peripheral fixation after adaptation to the immediate directional field. This is the task admitted by the CIE MES2 component; it is not a claim about central/foveal detection. Casual discovery, wide-field search, central fixation, flicker, and a population probability are different experiments and are not silently represented by an experience or confidence slider.

If the admitted threshold equations require a fixed field factor, the value and source equation are part of the component receipt. It is not a mutable proxy for observer skill.

For known_location_directed_averted_observation_v1, the admitted contract is the fixed Crumey equation-53 notional value F = 2. Crumey’s F can combine target, medium, laboratory-scaling, detection-practice, and personal effects; it is not a separable generic observer variable. The physical policy therefore exposes no experience or confidence slider. A different calibrated value requires a separately versioned observer protocol with its own experimental receipt and validity domain.

The first planetary candidates are Mercury, Venus, Mars, Jupiter, and Saturn. A planet enters the public model only after its dynamic visual magnitude and target spectral treatment carry source receipts and pass independent validation.

Those five candidates have passed the Phase 2 single-epoch engine gate. Their planetary response profiles are pack-owned and cannot be replaced by caller-supplied weights. Phase angle and, for Saturn, effective ring sub-latitude must remain inside the source-owned profile domain or the assessment fails closed.

A fixed star enters only when its identity, visual photometry, and spectral or color transformation are source-identified and complete. An ambiguous catalog color_index must not be guessed to be B-V, Gaia BP-RP, or another system.

The first Phase 3 event admission is deliberately narrower:

Sirius never enters the legacy native arcus accelerator. Its exact catalog identity, visual magnitude, source receipts, and response weights must agree with the external pack or evaluation fails closed.

Uranus, Neptune, minor planets, comets, novae, and other targets require separate target-admission evidence. They are not accepted merely because the ephemeris layer can calculate a position.

Excluded bodies and aids

Hard outer envelope

Phase 1 may narrow these limits after grid and error measurements. It may not widen them without amending this doctrine.

Quantity Hard outer envelope Unit or convention
Spectral integration 380 to 780 nm
Solar-center altitude -18 to 0 geometric degrees
Target altitude used by radiative transfer -1 to 45 true geometric degrees
Relative solar azimuth 0 to 180 absolute degrees
Observer altitude 0 to 5,000 m above mean sea level
Surface pressure 500 to 1,100 hPa
Aerosol optical depth 0 to 1 AOD at 550 nm
Angstrom exponent 0 to 2.5 dimensionless
Total ozone column 200 to 500 Dobson units
Ground albedo 0 to 1 dimensionless
Relative humidity 0 to 100 percent
Near-surface temperature 180 to 330 K

The generated data-pack manifest is the effective numerical domain. A point inside this outer envelope but outside the manifest still fails closed. No dimension may be extrapolated.

Refraction

The horizon/window decision uses apparent altitude. Directional radiative transfer uses true line-of-sight geometry. Both values and the refraction model identity survive in the receipt. Refraction is applied exactly once.

Horizon

The scalar apparent-horizon altitude remains the compatibility path. Phase 4 also admits an explicit caller-supplied circular azimuth/apparent-altitude terrain profile. The profile is never inferred from coordinates, downloaded, or substituted for a missing input. It must carry a profile identifier, source identifier, and lowercase SHA-256 source receipt.

The exact pack begins at 0.25 degrees true target altitude. When its refracted apparent equivalent is above the caller’s scalar horizon, that pack floor narrows the event window and is reported as target_data_pack_altitude_floor. It is not mislabeled as a measured or visual horizon.

For the directional profile:

The profile applies to both the target and the Sun. The exact-pack target floor remains a separate boundary and the effective target boundary is the maximum of the directional terrain altitude and the refracted pack floor. The event solver does not use apparent altitude - H(azimuth) as its certified signal because azimuth is undefined at the zenith. Instead it uses the local unit direction’s vertical component z, horizontal magnitude r, and terrain altitude H(theta):

g = z - r * tan(H(theta))

For admitted altitudes, g has exactly the sign and zeros of apparent altitude - H; at the zenith r = 0, so the signal is independent of undefined azimuth. Let S be the profile’s maximum absolute circular-linear slope, T the maximum abs(tan(H)), and Q the maximum sec(H)^2. The horizontal cone has Lipschitz factor K = sqrt(T^2 + (Q*S)^2). With the conservative admitted local-direction angular-rate ceiling of 1024 degrees/day, the runtime certificate is:

maximum absolute signal rate =
    radians(1024) * (1 + K) signal units/day

Taking the maximum with the constant pack floor preserves the slope ceiling; the floor altitude is also included when computing T and Q. Profile identity, resolution, S, K, queried azimuths, effective boundaries, and certificate identity survive in the receipts. If the certificate cannot exclude an unresolved crossing, the event fails closed.

Input Precedence and Completeness

Background authority is resolved in this order:

  1. measured directional spectral radiance at the target direction and time;
  2. measured directional photopic/scotopic luminance with its weighting function and spectral assumptions;
  3. the declared libRadtran directional twilight table plus a measured dark-sky anchor; or
  4. a named atmosphere plus an explicitly enabled coarse Bortle fallback.

Only one authority may supply the same physical component. A measured background that already contains airglow, zodiacal light, integrated starlight, or artificial light cannot be combined with modeled copies of those components.

A separately modeled airglow, zodiacal-light, integrated-starlight, or artificial-light input is caller-supplied evidence, not an engine default. It must carry positive photopic/scotopic directional luminance, model and source identity, a source SHA-256, spatial/temporal/directional applicability, validity-domain identity, and uncertainty authority. Combining any such component with a dark-sky anchor requires the anchor to declare that its component inventory is complete. Duplicate component kinds, overlap with the anchor inventory, or combination with a measured total fail closed.

The engine receipts each separately modeled component. It does not silently include that component’s unadmitted scientific uncertainty in the data-pack numerical-error envelope.

An SQM input must record:

An unqualified scalar SQM value cannot become a spectral twilight background.

A named atmosphere profile must resolve and receipt every value it supplies. Pressure may be derived from altitude only through a named atmospheric profile, with the profile, equation, source, and derived value reported. Caller-supplied values override profile values only when the policy explicitly allows the override and the receipt marks it.

Required units are:

Bortle is a coarse compatibility input. It is never inferred from location and is used only when the caller explicitly selects the coarse fallback.

Data-Pack and Offline Boundary

The physical reference table is not bundled in the MIT engine wheel.

It is a separately versioned, immutable, checksummed visibility data pack with:

The engine wheel may include only a metadata-only compatibility manifest. The runtime accepts an explicit caller-supplied data-pack path. Normal calculation never downloads or updates the pack.

Pack version 1.0 remains loadable for its Phase 1 atmospheric tables but contains no admitted planetary target profiles. Pack version 1.1 adds the source-locked Mercury-through-Saturn profiles required by the Phase 2 public assessment. Pack version 1.2 preserves every version 1.1 numerical payload byte and adds the source-locked Sirius profile required by Phase 3. Physical event search admits only version 1.2 with root manifest:

cf93433a9f66a5ea92832271ce3c4b023fcc8693164803539a9f1be85b17468c

Single-epoch assessment remains compatible with the admitted 1.0, 1.1, and 1.2 contracts according to their capabilities. Callers may pin the exact root manifest SHA-256 in both runtime configuration and policy.

Missing, incompatible, or corrupt data is a typed non-evaluable outcome.

Numerical Error and Scientific-Uncertainty Boundary

An evaluated Phase 2 result carries both the nominal visibility margin and a separate declared data-pack numerical-error envelope. The envelope includes:

For modeled twilight, only the modeled twilight term is perturbed; the caller-supplied dark-sky anchor is held at its supplied value and its measurement uncertainty remains explicitly unquantified. For a measured-total background, Moira does not invent a background-error bound. It propagates only the pack-owned direct-extinction error and names the measurement uncertainty as unquantified.

The receipt reports limiting-magnitude and visibility-margin envelope limits and one classification within the pack numerical envelope: visible, not_visible, or indeterminate. The ordinary visible field remains the nominal model result. P95 interpolation diagnostics are not promoted into maximum bounds. The reported solver term is not a hard maximum. This envelope is not a probability, population model, or scientific confidence interval. Planetary photometry, spectral-source, CIE/threshold model, observer-population, real-atmosphere, and input-measurement uncertainty remain separate named limitations.

libRadtran remains an external GPL reference generator. No libRadtran source, binary, Python binding, or runtime invocation enters the engine or data pack. Only generated numerical products, complete generator configuration, and provenance receipts may cross the build boundary.

This is the project’s packaging disposition, not legal advice. Release notice and artifact review remain mandatory before public distribution.

Additive Public Contract

Representative additive Python types:

Additive functions:

physical_visibility_assessment(...)
    -> PhysicalVisibilityAssessment

physical_visibility_event(...)
    -> PhysicalVisibilityEventResult

The assessment request carries:

The first fixed-star contract is Sirius and consumes only the pack-owned source-identified identity, Johnson V, and CALSPEC/CIE response. Other targets still require a separate admission gate.

The event request additionally carries:

PhysicalVisibilityPolicy carries:

The local data-pack filesystem path is runtime configuration, not scientific policy. Python receives it through a dedicated VisibilityDataPackConfig or engine configuration. A REST client never supplies an arbitrary server path. The REST deployment binds its allowed pack path and clients may assert only the expected public pack identity/checksum.

Admitted dedicated REST routes:

POST /v1/visibility/physical-assessment
POST /v1/visibility/physical-event

The legacy /v1/visibility/assessment and /v1/heliacal/visibility-event routes remain exact compatibility surfaces.

Every physical result returns a status:

An event result includes:

VisibilityDataPackReceipt includes:

Stable Non-Evaluable Reasons

The following identifiers are reserved:

The stable not_found reason is:

Polar day, polar night, circumpolarity, and never-rising geometry are not collapsed into one label. The specific missing solar or target boundary is reported.

Closed Exclusions

The first physical admission excludes:

An exclusion is not a backlog defect. Reopening it requires a named source, new validity domain, additive contract proposal, independent validation, and an admission receipt.

Phase 0 Decision

The physical doctrine is frozen for implementation planning:

Any implementation that contradicts this document must stop and amend Phase 0 before continuing.