Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ManiFed/TTN/llms.txt

Use this file to discover all available pages before exploring further.

Every night, the Telescope Net cloud server answers the same question for each connected Seestar: which targets should it observe, in what order, and for how long? The answer emerges from a three-stage pipeline — alert ingestion builds the pool of candidates, composite scoring ranks every (target, node) pairing, and the plan generator turns those scores into sequenced observation lists. CHORUS, the default live scheduler, replaces the final stage with an information-theoretic assignment algorithm described on the CHORUS page. This page covers the underlying scoring machinery that feeds into both.

Pipeline Overview

Alert Ingestion  →  Composite Scoring  →  Plan Generation
(hourly)            (per ingest + replan) (every 120 min)
Alert ingestion runs first and triggers an immediate rescore whenever new targets appear. The replan loop fires every 120 minutes independently, rescoring and regenerating plans for the entire fleet even when no new alerts have arrived. The two loops are decoupled so that a slow broker poll never delays plan delivery.

Alert Sources

The alert-ingest background loop polls six sources once per hour:
SourceWhat it provides
ALeRCEZTF-based photometric classifier — supernovae, variable stars, active galactic nuclei
ATLASAsteroid Terrestrial-impact Last Alert System — rapid transients and novae
ASAS-SNAll-Sky Automated Survey for Supernovae — bright transients and CVs
AAVSO alertsVSX watchlist targets and community-reported outbursts
GaiaGaia Science Alerts — photometric transients across the sky
TNSTransient Name Server — classified supernovae and other reported events
New targets are inserted into the targets table with their RA/Dec, magnitude, type, discovery timestamp, and priority. Transients not seen by any source for expire_days (default 45) are deactivated automatically.

Composite Scoring Formula

scoring.score_all() computes a score for every (target, node) pair and persists the results to the scores table. The composite is:
total = w_brightness · brightness_match
      + w_science    · scientific_value
      + w_time       · time_criticality
      + w_coverage   · coverage_gap
      + w_observe    · observability
      + w_roi        · science_roi
All six components are normalised to 0–1 so the weights read directly as relative importance. The default weights are brightness: 0.20, science: 0.25, time: 0.15, coverage: 0.15, observe: 0.25, roi: 0.10.

Score Components

brightness_match — how well the target’s magnitude sits within the node’s usable range. Scores 1.0 near the midpoint of [mag_bright_limit, mag_faint_limit], falling to 0.0 at or beyond the hard limits. scientific_value — the target’s priority field, set by the alert source or campaign programme. Ranges from 0.0 (low) to 1.0 (critical campaign target). time_criticality — urgency based on target type and age. Fresh transients score 1.0 on discovery day and decay with a 12-day half-life toward a floor of 0.3. Non-time-critical targets hold a flat baseline of 0.2. coverage_gap — blends two signals: short-term recency (40 %) measuring how long ago the last measurement arrived relative to the target’s expected cadence, and long-term historical neglect (60 %) comparing our own observation count against the expected cadence over a 30-day window, further weighted by science priority. When external AAVSO and ALeRCE coverage data is available it is blended equally with internal coverage to prevent targets from appearing neglected simply because the network was clouded out. observability — the weighted blend of six site-specific factors described in the next section. science_roi — science yield from recent network outcomes: AAVSO acceptance rate (45 %), cadence-gap closure rate (35 %), and timely coverage of time-critical events (20 %) over the last 90 days. Sparse histories are pulled toward 0.5 so new targets remain viable.

Observability Sub-Weights

The observe component is itself a weighted average of six factors, with weights that are live-tuned and stored in the tuning_state table:
observability_weights:
  light_pollution: 0.20
  weather:         0.25
  moon:            0.15
  airmass:         0.15
  window:          0.15
  telescope:       0.10
FactorComputation
light_pollutionSky background suitability: bright targets tolerate light pollution; faint ones need dark skies (mpsas 22 = pristine → 1.0; mpsas 17 = inner city → 0.0)
weatherNight-mean composite of cloud cover (1 − cloud fraction), atmospheric seeing, and transparency — from 7timer ASTRO data where available, falling back to Open-Meteo cloud cover
moonLunar interference: scales with illumination × angular proximity at midnight; < 10° separation scores 0.05 regardless
airmassBest achievable airmass over the night: X = 1 → 1.0, X = 3 → 0.0 (linear)
windowFraction of the dark window the target is above min_altitude_deg; ≥ 4 hours visible saturates at 1.0
telescopeHardware match: aperture-limited magnitude headroom and field-of-view suitability to the target class
A target that is never above the node’s minimum altitude horizon at any point in the night scores exactly 0.0 for observability, and therefore 0.0 for total, regardless of all other factors.

Reliability Multiplier

The raw composite score is multiplied by a reliability factor that reflects how much science a node has actually delivered to AAVSO, not what it claims it can deliver:
total_score = theoretical_score × (0.5 + 0.5 × reliability_score)
reliability_scoreMultiplierMeaning
1.0× 1.00Proven node — no penalty applied
0.5× 0.75New or data-sparse node — slight preference for proven peers
0.0× 0.50Persistently poor data — still receives some assignments (floor prevents starvation)
New nodes (fewer than 10 observations) start at 0.50 and converge toward their true value over approximately 20–30 observations.

Reliability Score Formula

Computed nightly by registry.refresh_all_performance() from the measurements table:
reliability = 0.40 × aavso_acceptance_rate
            + 0.25 × (1 − outlier_rate)
            + 0.20 × min(1, clear_nights_30d / 30)
            + 0.15 × precision_factor

precision_factor = max(0, 1 − mean_uncertainty / 0.30)
The formula is intentionally multi-dimensional: a node cannot inflate its score by optimising one metric — it must deliver across all four simultaneously. aavso_acceptance_rate is the ultimate output measure; outlier_rate captures cross-validation disagreement; clear_nights_30d combines weather and hardware reliability; precision_factor rewards photometric precision up to the AAVSO quality ceiling of 0.30 mag.

Node Data Model

The scheduler reads the following columns from the nodes table when building scores and plans:
ColumnUsed for
latitude, longitudeNight window calculation, altitude curve, airmass, moon angle
elevationPressure correction for airmass
utc_offset_hoursTwilight times in local clock
light_pollution_mpsasSky background noise and faint-target magnitude limit
bortleHuman-readable sky quality label
horizon_maskJSON [[alt, az], …] — local obstructions; targets behind them are never scheduled

Autonomy Flags

Four boolean columns in the nodes table indicate unattended operation capability. The scheduler does not apply a direct numeric penalty for missing flags today, but nodes with all four tend to produce better clear_nights_30d and higher aavso_accepted counts — which flows directly into their reliability_score.
FlagWhy it matters
has_dew_heaterPrevents lens fogging in humid conditions. Without one, a node can fail silently — images blur, plate-solving fails, and the whole night produces no measurements
has_power_mgmtSmart power box lets the node agent remotely cycle a hung Seestar. Without it, a crashed scope means a missed assignment with no recovery until a human intervenes
has_enclosureDome or minidome — the node can observe through light rain, wind, and heavy dew. Dramatically improves clear_nights_30d which feeds the reliability score
has_upsBrief power cuts don’t kill the night. Especially relevant for nodes in regions with unstable grid power — protects both clear_nights_30d and aavso_acceptance_rate

Plan Output

The scheduler emits ObservationPlan objects (from src/shared_models.py) stored as JSON in the plans table. Each plan contains a list of PlanItem records:
{
  "plan_id": "plan_4a7b2c1d3e",
  "node_id": "node_a3f9b2c1",
  "night": "2026-07-15",
  "generated_at": "2026-07-15T20:00:00Z",
  "items": [
    {
      "target": "SS Cyg",
      "ra_deg": 325.678,
      "dec_deg": 43.586,
      "exp_dur": 30.0,
      "exp_count": 40,
      "filter": "CV",
      "scheduled_start": "2026-07-15T22:15:00Z"
    }
  ],
  "contingencies": { "alternates": [] }
}
CHORUS plans include an additional contingencies object with precomputed alternate targets and late-start ladders. Node agents running older software ignore unknown keys — the plan format is additive and backward-compatible.

Interrupt System

High-priority alerts (bright novae, rapid transient brightening, ToO requests) can be broadcast to nodes without waiting for the next replan cycle. The admin endpoint POST /api/v1/interrupts inserts a row in the interrupts table; nodes poll GET /api/v1/interrupts on each heartbeat cycle and act on any unexpired entries.

Manual Operations

The scripts/manage.py admin CLI wraps the same HTTP endpoints. Run python3 scripts/manage.py ingest instead of constructing curl commands for day-to-day use.
Trigger the scoring and planning loops on demand using the admin endpoints:
# Trigger alert ingestion + composite rescoring
curl -X POST \
  -H "X-Admin-Key: your-admin-key" \
  http://localhost:8800/api/v1/admin/ingest

# Trigger full rescore + plan regeneration for all nodes
curl -X POST \
  -H "X-Admin-Key: your-admin-key" \
  http://localhost:8800/api/v1/admin/replan
Both endpoints return immediately and run the operation synchronously — the response arrives only when the operation completes. For large fleets, replan can take several seconds as CHORUS runs its full T1 → T2 → T3 pipeline.

Build docs developers (and LLMs) love