Skip to main content

0.9.5 — Analysis Job Cancellation and Concurrency Control

Released 2026-10-06.

Stop a running or queued analysis job, single or all at once — and a race that could previously let two triggers for the same artefact both run to completion is now closed.

What's new​

Cancel a single analysis. A "Cancel" action next to any queued or running analysis stops it immediately — dequeued if it hasn't started, signalled to halt if it has — with a confirmation prompt before anything happens.

Cancel all active analyses for one artefact. When more than one analysis is active for the same requirement or story, a "Cancel All" action stops every one of them in a single confirmed action, and reports by name if any individual job couldn't be stopped rather than treating a partial failure as a silent success.

Automatic supersession is now race-free. Triggering a new analysis for a newer revision of a requirement or story automatically stops any still-active analysis for the old revision before the new one starts — and two triggers arriving at (almost) the same moment can no longer both win, closing a race that could previously produce duplicate results for the same artefact.

Bug fixes​

  • Closed a race where two analysis triggers for the same artefact revision, arriving in quick succession, could both reach completion — the second trigger is now reliably rejected (same revision already active) or made to supersede the first (newer revision), never both left running.
  • Cancelled analysis jobs now appear in the job history view; previously they vanished from the active list with no record.

Behind the scenes​

  • An atomic SELECT ... FOR UPDATE guard at enqueue time, replacing unconditional supersession logic, now runs on every path that can start a requirement or story analysis.
  • 64 new automated test scenarios across 5 user stories (controller and UI), plus a controllable test-only background job used to make timing-sensitive cancellation scenarios deterministic.

Upgrade notes​

No action needed. One new database column (analyses.rq_job_id, nullable); existing analysis records are unaffected.