Skip to content

feat(sequences): endpoint to update a sequence's azimuth and recompute triangulation #643

Description

@fe51

Objective

Today, a sequence's azimuth (Sequence.sequence_azimuth) is computed once, at sequence creation, from the center of the first detection's bounding box — see resolve_cone (src/app/services/cones.py) called in src/app/api/api_v1/endpoints/detections.py (~L582-590). It never changes afterward.

We want to be able to refine that azimuth after the fact. Two future sources will need this (handled in separate issues ):

  • an operator clicking the fire origin point in the frontend, and/or
  • a CV algorithm estimating the fire origin automatically.

This issue covers the backend workflow only: exposing a clean API entry point that updates the azimuth and keeps the triangulation state consistent.
Note:The source of the new azimuth is not tracked or persisted in this issue.


Current behavior

sequence_azimuth (and cone_angle) feed the whole triangulation pipeline:

  • _attach_sequence_to_alert (src/app/api/api_v1/endpoints/detections.py, ~L392) — builds detection cones, finds overlapping sequences, and creates/merges/links alerts.
  • refresh_alert_state (src/app/services/alerts.py, ~L21) — recomputes an alert's bounds and lat/lon from its member sequences via compute_overlap (src/app/services/overlap.py).

There is no route to change a sequence's azimuth. The only sequence mutations exposed are PATCH /sequences/{id}/label and DELETE /sequences/{id} (src/app/api/api_v1/endpoints/sequences.py). Both, notably, already re-run the alert/triangulation reconciliation after mutating — that's the pattern to follow.

Expected behavior

Expose a new endpoint (suggested: PATCH /sequences/{sequence_id}/azimuth) that, when the azimuth of a sequence is updated:

  1. Persists the new sequence_azimuth.
  2. Recomputes all triangulations involving this sequence (its cone changes, so overlaps with other sequences change).
  3. Reconciles the linked alerts — create / update / remove AlertSequence links and alert lat-lon as needed, exactly as sequence creation and labeling already do.
  4. Leaves the triangulation state consistent across the affected alerts (no orphaned links, no stale alert locations).

The endpoint must be usable both by the frontend (operator refinement) and by an automated CV pipeline (service/admin token).

A suggested approach (can be challenged)

  • Add a SequenceAzimuth request schema in src/app/schemas/sequences.py validating sequence_azimuth in [0, 360) (mirror the model constraint on camera_azimuth).
  • In the endpoint: fetch the sequence, persist the new azimuth, then re-run the same attach/reconcile flow the creation path uses. Note for the implementer: the triangulation entry point _attach_sequence_to_alert currently lives inside the detections endpoint module and is already imported cross-module by src/app/services/validation.py (~L371). Reusing it here (rather than duplicating the logic) likely warrants extracting it into a service module (e.g. app/services/triangulation.py or extending app/services/alerts.py). ?
  • After re-attaching, refresh every previously- and newly-linked alert via refresh_alert_state so alert bounds and location stay correct — including deleting an alert that ends up empty (already handled inside refresh_alert_state).

Auth / roles

Allowed: ADMIN and USER (the acknowledging role).
AGENT must NOT have access. (This intentionally differs from /label, which is ADMIN + AGENT.)

Non-admins are scoped to their own organization -> you might use verify_org_rights (src/app/api/api_v1/endpoints/sequences.py).

Open question to resolve during implementation -> cone angle

Refining the azimuth by clicking a fire origin point conceptually collapses the detection to (near) a point, whereas cone_angle today encodes the bbox width (src/app/services/cones.py) and directly drives cone overlap. So:

  • Is updating cone_angle relevant when the azimuth is refined?
  • If yes, what value —> should the endpoint accept a cone_angle, or should a refined azimuth always snap to a fixed, narrow opening angle (a constant in src/app/core/config.py)?

Acceptance criteria

  • New authenticated endpoint updates sequence_azimuth on a sequence and persists it.
  • Auth enforced: ADMIN + USER allowed, AGENT forbidden (403), non-admins limited to their org.
  • Input validated to [0, 360).
  • After the update, alert links and alert location/bounds are recomputed and left consistent (links added/updated/removed; empty alerts deleted).
  • cone_angle behavior decided and implemented per the open question above.
  • Tests cover: azimuth change that (a) keeps the same alert, (b) breaks an existing overlap/link, (c) creates a new overlap/link, and (d) empties and deletes an alert. Follow the existing endpoint tests in src/tests/endpoints/.

Happy to discuss it 🖌️

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions