Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
e96a529
Add design + plan for shared auth via Keycloak
thusser Aug 12, 2026
abc2b09
Revise shared-auth design: Keycloak as sole issuer, observation-porta…
thusser Aug 12, 2026
48b6c28
Mark pyobs-auth package done in the shared-auth plan
thusser Aug 12, 2026
82ba135
Mark pyobs-archive cutover done in the shared-auth plan
thusser Aug 12, 2026
6544ffa
new graphify files
thusser Aug 12, 2026
262db6f
Rename specs/plans/ files with creation date prefix
thusser Aug 12, 2026
905d33a
Mark pyobs-robotic-backend Keycloak integration done; refresh graphif…
thusser Aug 13, 2026
558cf3e
Add plan to make pydantic config layer reject unknown keys
thusser Aug 15, 2026
f8976ef
Run focus model fit off the event loop
thusser Aug 15, 2026
6f6c0e7
graphify
thusser Aug 15, 2026
a3d3548
v2.0.0.dev74
thusser Aug 15, 2026
fc14c94
Run FITS serialization off the event loop
thusser Aug 15, 2026
e747857
graphify
thusser Aug 15, 2026
ce0bc9d
v2.0.0.dev75
thusser Aug 15, 2026
8839191
graphify
thusser Aug 15, 2026
9ac80d8
Note second scheduler stall occurrence in process-isolation plan
thusser Aug 15, 2026
b3823cd
Mark night-archive I/O hardening plan implemented; update pipeline-pl…
thusser Aug 15, 2026
6630a0c
graphify
thusser Aug 15, 2026
559ed2c
Update camera driver/GUI split plan: note TIS revert, mark fli execut…
thusser Aug 15, 2026
1c740ac
Publish live exposure progress in BaseCamera
thusser Aug 15, 2026
14a82f8
graphify
thusser Aug 15, 2026
d62573a
Update logevent double-delivery plan: correct TLS/vhost attribution, …
thusser Aug 15, 2026
3ea4570
graphify
thusser Aug 15, 2026
0159542
v2.0.0.dev76
thusser Aug 15, 2026
a72f5e5
graphify
thusser Aug 15, 2026
b9a2996
Close process-isolation plan: stress test found no GIL contention, dr…
thusser Aug 15, 2026
218e486
graphify
thusser Aug 15, 2026
b2cb3f8
Investigate object kwarg validation: comm_cfg anchor leak makes raise…
thusser Aug 15, 2026
f3180a2
graphify
thusser Aug 15, 2026
9c02f8b
Add plan: log loaded pyobs-* package versions at startup
thusser Aug 15, 2026
b85de87
graphify
thusser Aug 16, 2026
db46bf8
Add per-directory specs index.md; clarify cross-repo docs convention
thusser Aug 16, 2026
3789a69
Correct shared-auth-keycloak plan to reflect actual repo state
thusser Aug 16, 2026
ea05587
Split unfinished plans under a 'Not finished' header
thusser Aug 16, 2026
21f3675
Investigate pydantic extra validation: flag imaging models gap, resol…
thusser Aug 16, 2026
81e13a9
Log loaded pyobs-* package versions at module startup (#759)
thusser Aug 16, 2026
1489838
Fix WeatherAwareMixin retrying park() every cycle while device is in …
thusser Aug 16, 2026
e5afd89
graphify
thusser Aug 16, 2026
04fd518
Investigate LogEvent double-delivery on SAAO production ejabberd
thusser Aug 16, 2026
8df9d9c
Document discussion on LogEvent double-delivery fix and roster/pubsub…
thusser Aug 16, 2026
7066350
Add ADR and plan for explicit pubsub event subscriptions
thusser Aug 16, 2026
ea6d87c
v2.0.0.dev77
thusser Aug 16, 2026
e139de5
Mark core-tier test baseline plan implemented, note auto-merge settings
thusser Aug 16, 2026
a35487e
Bound FITS-header fetch so a dead peer can't stall the frame (#765)
thusser Aug 16, 2026
c5edb84
Mark fits-header-fetch-timeout plan implemented, closed (#768)
thusser Aug 16, 2026
1c20552
Add raw-frame streaming endpoint to BaseVideo alongside MJPEG (#766)
thusser Aug 16, 2026
3bf1bf5
Mark basevideo-raw-frame-streaming plan implemented, closed (#770)
thusser Aug 16, 2026
ab2e87a
Explicit pubsub event subscriptions, decoupled from PEP presence (#761)
thusser Aug 16, 2026
eb0ec15
Mark explicit-pubsub-event-subscriptions plan implemented, closed (#771)
thusser Aug 16, 2026
e398117
Make pydantic config models reject unknown keys (extra="forbid") (#762)
thusser Aug 16, 2026
e250e89
Note PR #762 merged in the pydantic extra=forbid plan
thusser Aug 16, 2026
f53e71a
Backfill CHANGELOG and whatsnew-2.0 for dev53-dev78 (#772)
thusser Aug 16, 2026
9685fb1
Close pydantic-extra-validation plan; update object-kwarg-validation …
thusser Aug 17, 2026
a5646fb
Fix comm_cfg anchor-holder key leaking into config dicts (#773)
thusser Aug 17, 2026
560083c
Mark comm_cfg anchor-leak fix merged (#773), note review round
thusser Aug 17, 2026
cd2fc93
graphify
thusser Aug 18, 2026
20a25b2
Record fleet cleanup pass; environment/database resolved as gone
thusser Aug 18, 2026
f069692
Resolve stale open questions/checklist in object-kwarg-validation plan
thusser Aug 18, 2026
f2c69a8
Record second cleanup pass: chased down the 45 import failures
thusser Aug 18, 2026
856c663
v2.0.0.dev78
thusser Aug 18, 2026
28851d0
Fix TOCTOU race in BaseVideo.activate_camera()/deactivate_camera()
thusser Aug 18, 2026
e7fba4e
v2.0.0.dev79
thusser Aug 18, 2026
643af07
Declare NewImageEvent as sent in BaseVideo.open()
thusser Aug 18, 2026
a82b5f4
v2.0.0.dev80
thusser Aug 18, 2026
9d84955
v2.0.0.dev81
thusser Aug 18, 2026
464ca1d
Document reverted Object.__init__ raise attempt: mixin fan-out blocker
thusser Aug 18, 2026
6685419
Add cooperative-mixin-init plan, prerequisite for Object.__init__ raise
thusser Aug 18, 2026
5d7c78d
Fix camera-driver-gui-split: qhyccd fixes are in unmerged PR #59
thusser Aug 18, 2026
156d9ef
camera-driver-gui-split: qhyccd fixes merged via PR #59
thusser Aug 18, 2026
f75a1da
Bump types-setuptools from 83.0.0.20260807 to 84.0.0.20260812
dependabot[bot] Aug 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 230 additions & 1 deletion CHANGELOG.rst

Large diffs are not rendered by default.

18 changes: 8 additions & 10 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,14 @@ planning notes.

### Cross-repo docs

`pyobs-core` is the only repo in the `pyobs` ecosystem with this `specs/` structure — sibling repos
(`pyobs-gui`, `pyobs-polaris`, hardware-driver plugins, etc.) don't have their own, and setting one
up per repo for the occasional cross-repo doc isn't worth the overhead. Design docs, plans, and ADRs
that concern (or are actually implemented in) a sibling repo still live here. Two things to keep
that discoverable:

- Add a `Repos:` line under `Status:` naming every repo the doc concerns, so it's obvious at a
glance this isn't `pyobs-core`-only.
- The concerned sibling repo(s) should carry a one-line `specs/README.md` pointer back here (not a
full `specs/` structure of their own) — see e.g. `pyobs-gui/specs/README.md`.
`pyobs-core` only keeps specs for its own work and for things that span more than one project.
Design docs, plans, and ADRs that concern a sibling repo (`pyobs-gui`, `pyobs-polaris`,
hardware-driver plugins, etc.) as well as `pyobs-core` still live here.

- Every `specs/` directory keeps a human-readable `index.md` listing its docs.
- A cross-repo doc adds a `Repos:` line under `Status:` naming every repo it concerns, so it's
obvious at a glance this isn't `pyobs-core`-only.
- Sibling repos reference the specs that are about them in their own `specs/index.md`.

## Tooling

Expand Down
83 changes: 83 additions & 0 deletions docs/source/whatsnew-2.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,28 @@ subclasses ``ICamera``/``ISpectrograph`` directly (not via ``BaseCamera``/``Base
and actually wants exposure-progress semantics, add ``IExposure`` to its own bases explicitly and
publish ``ExposureState`` via ``self.comm.set_state(...)``.

``IVideo`` gains a raw stream, ``video`` renamed to ``mjpeg``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

``VideoCapabilities.video`` is renamed to ``mjpeg``, and a new ``raw`` field
(``str | None``) advertises the path of the new raw-frame endpoint (see
`Raw-frame video streaming`_ below). ``live_view`` is folded into ``video_path``, alongside a new
``raw_path``. Breaking for any client reading ``VideoCapabilities.video`` by name.

Other renamed/removed utilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* ``pyobs.utils.pipeline.Night`` is renamed to ``Reduction`` (the class covers solar reductions
too, not just nighttime ones). ``store_local`` is replaced by a single ``output`` parameter
(a local path, a dict, or an ``Archive``), so input and output archives can differ. The dead
``worker_procs`` parameter and the ``**kwargs`` catch-all on ``Reduction.__init__`` are removed,
so a typo'd config key now raises ``TypeError`` instead of being silently swallowed.
* ``AperturePhotometry`` is now abstract — it was never meant to be instantiated directly (that's
what ``PhotUtilsPhotometry``/``SepPhotometry`` are for), and its ``__module__`` override
advertised an import path the package never actually re-exported.
* The generated TypeScript interface exports (``export/typescript/``) are removed. Breaking for
any external tooling that consumed them.

Exception handling
---------------------

Expand Down Expand Up @@ -388,6 +410,16 @@ Raise the shaper limits in ``ejabberd.yml``:
``scripts/xmpp/install-ejabberd.sh`` applies this (plus routing a host onto the ``fast``
shaper via its own vhost ACL) for new hosts automatically.

``HttpFileCache`` authentication
------------------------------------

``HttpFile``'s Basic Auth credentials were never actually checked by ``HttpFileCache`` — the
server accepted every request regardless. Basic Auth is replaced by an opt-in ``token`` param,
checked via constant-time compare, and the download handler gained CORS headers (plus the
required ``OPTIONS`` preflight handler) so browser ``fetch()`` clients like
``pyobs-web-client`` can read cross-origin. Breaking for any client still sending Basic Auth
credentials and expecting them to matter.

New features
============

Expand Down Expand Up @@ -425,6 +457,10 @@ trusted forever. ``WeatherAwareMixin`` uses this for its own weather checks (def
so a dead ``Weather`` update loop degrades to bad-weather within a couple of check cycles
instead of trusting a frozen "good" reading indefinitely.

``BaseCamera`` now actually keeps ``IExposure``'s ``progress``/``exposure_time_left`` live during
an exposure (re-published once a second) — previously they were only published on status
transitions, so both stayed frozen at 0 for the whole exposure despite the state existing.

Some interfaces need a variable, hardware-dependent set of fields rather than a fixed
schema — a telescope's temperature sensors vary in name and count by installation. These
use **extensible, typed collections** instead of one field per sensor:
Expand Down Expand Up @@ -569,6 +605,46 @@ default ``0``) is skipped after the last grab and cut short immediately by eithe
``abort_sequence()`` or ``abort()`` instead of idling out the full wait. Dithering/offsets
between grabs remain out of scope -- that's a pointing-layer concern, not this interface's.

Per-step pipeline error handling
------------------------------------

``ImageProcessor`` gained an ``on_error`` kwarg (``"raise"`` (default) / ``"error"`` / ``"info"``
/ ``"ignore"``) and a ``handle_error(image, error)`` override point.
``PipelineMixin.run_pipeline()`` now dispatches each step's ``ImageError`` per that step's own
setting instead of aborting the whole chain on the first failure from any step — lets one step
stay fatal (a calibration path that must have a valid WCS) while another is non-fatal (a
quick-look pipeline where a missing WCS is fine) within the same pipeline run:

.. code-block:: yaml

pipeline:
- class: pyobs.utils.pipeline.Calibration
on_error: raise # abort the run if calibration fails
- class: pyobs.utils.pipeline.AstrometryDotNet
on_error: info # log and continue if plate-solving fails

``AstrometryDotNet``'s old ``exceptions: bool`` kwarg is deprecated in favor of ``on_error``
(``exceptions=False`` behaves like ``on_error="error"``; ``on_error`` wins if both are set).
Calling a migrated processor directly, outside a pipeline, still always raises regardless of
``on_error``/``exceptions``.

OBSNUM: per-night observation numbers
------------------------------------------

``Mastermind`` now assigns a compound ``<night>-<counter>`` observation number
(``Observation.obsnum``) when a task starts running, persisted via a VFS-cached per-night
counter and written to the ``OBSNUM`` FITS header — lets frames from possibly-multiple cameras
be tied back to the observation that produced them.

Raw-frame video streaming
------------------------------

``BaseVideo`` gained a raw-frame streaming endpoint alongside its existing MJPEG stream: a
multipart, event-driven feed of a JSON FITS-keyed meta header plus raw little-endian frame
bytes, with latest-frame-wins backpressure (a slow client drops stale frames rather than
queuing them up). See `IVideo gains a raw stream, video renamed to mjpeg`_ above for the
capability-level change.

Access control (ACLs)
----------------------

Expand Down Expand Up @@ -634,6 +710,8 @@ Other notable changes
synchronous blocking call anywhere in the module (or a background task) shows up as a
logged stall (once when it starts, once when it clears, with total duration) instead of
only being visible indirectly as peers timing out trying to reach that module.
* Every module now logs the versions of loaded ``pyobs-*`` packages at startup, alongside the
IERS-cache priming that already happens there.

Upgrading
=========
Expand All @@ -659,3 +737,8 @@ GUI/client), check for, in roughly descending order of how likely they are to af
``exc.register_exception(...)`` — see `Exception handling`_ above.
#. If you run your own ejabberd server, apply the ``mod_pubsub`` config change above, and
raise the ``shaper`` limits if you expect real fleet traffic.
#. Any code reading ``VideoCapabilities.video`` — rename to ``mjpeg``.
#. Any code using ``pyobs.utils.pipeline.Night``, its ``store_local`` param, or
``worker_procs`` — rename to ``Reduction`` and switch to the ``output`` param.
#. Any client relying on ``HttpFile``'s Basic Auth against ``HttpFileCache`` — switch to the
new token param, since Basic Auth credentials are no longer accepted at all.
Loading
Loading