Pressing Stop could look like the scan restarting — and for scheduled jobs the Google stage really did restart.
Causes & fixes
Scheduler restarted the Google stage after Stop. A job runs M365 → file sources → Google. It never checked for Stop between stages, and called _gsa.clear() before the Google stage — erasing the Stop and starting a fresh all-users Google scan. The scheduler now checks _scan_abort between stages and doesn't clear the Google abort after a Stop. A stopped job is recorded as cancelled, skips auto-email/retention, and scheduler_done carries cancelled: true (shown as "⏹ … stopped" in the log and job history).
Stopped scans were replayed as if running. Only scan_done ended the "current" SSE scan, so a stopped M365 scan (and every file scan, which ends with file_scan_done) stayed current. Every reconnect — page load or the 4 s watchdog — replayed its events, re-showing the Stop button and progress bar. scan_cancelled and file_scan_done now end the scan too, and sse.replay_messages() never replays a finished scan.
Frontend kept stopped scans "running". The scan_cancelled handler now clears S._m365ScanRunning and only tears down the UI when no Google/file scan is still running. scheduler_done / scheduler_error clear all running flags.
Stop during collection announced a new scan. The collection loops break out silently and the engine then emitted scan_start + "Scanning…". run_scan now checks for Stop right after collection and ends cleanly (checkpoint, finish_scan, scan_cancelled).
No feedback on click. The Stop button now switches to a disabled "Stopping…" state. All show/hide goes through _setStopBtnDisplay(), which resets it when hidden or when a new scan starts.
Behaviour change
After a scan has finished or been stopped, refreshing the page no longer replays that scan's lines into the log. Results still load from the database.
Testing
tests/test_stop_scan.py — 10 tests: SSE replay, Stop during collection, scheduler Stop vs. uninterrupted job. The regression tests fail on the old code.
Full suite: 247 passed.
Frontend (fixes 3 & 5) verified in an isolated harness loading the real scan.js with synthetic SSE events. Not tested against a live M365/Google scan.
## Problem
Pressing **Stop** could look like the scan restarting — and for scheduled jobs the Google stage really did restart.
## Causes & fixes
1. **Scheduler restarted the Google stage after Stop.** A job runs M365 → file sources → Google. It never checked for Stop between stages, and called `_gsa.clear()` before the Google stage — erasing the Stop and starting a fresh all-users Google scan. The scheduler now checks `_scan_abort` between stages and doesn't clear the Google abort after a Stop. A stopped job is recorded as `cancelled`, skips auto-email/retention, and `scheduler_done` carries `cancelled: true` (shown as "⏹ … stopped" in the log and job history).
2. **Stopped scans were replayed as if running.** Only `scan_done` ended the "current" SSE scan, so a stopped M365 scan (and every file scan, which ends with `file_scan_done`) stayed current. Every reconnect — page load or the 4 s watchdog — replayed its events, re-showing the Stop button and progress bar. `scan_cancelled` and `file_scan_done` now end the scan too, and `sse.replay_messages()` never replays a finished scan.
3. **Frontend kept stopped scans "running".** The `scan_cancelled` handler now clears `S._m365ScanRunning` and only tears down the UI when no Google/file scan is still running. `scheduler_done` / `scheduler_error` clear all running flags.
4. **Stop during collection announced a new scan.** The collection loops break out silently and the engine then emitted `scan_start` + "Scanning…". `run_scan` now checks for Stop right after collection and ends cleanly (checkpoint, `finish_scan`, `scan_cancelled`).
5. **No feedback on click.** The Stop button now switches to a disabled "Stopping…" state. All show/hide goes through `_setStopBtnDisplay()`, which resets it when hidden or when a new scan starts.
## Behaviour change
After a scan has finished or been stopped, refreshing the page no longer replays that scan's lines into the log. Results still load from the database.
## Testing
- `tests/test_stop_scan.py` — 10 tests: SSE replay, Stop during collection, scheduler Stop vs. uninterrupted job. The regression tests fail on the old code.
- Full suite: 247 passed.
- Frontend (fixes 3 & 5) verified in an isolated harness loading the real `scan.js` with synthetic SSE events. Not tested against a live M365/Google scan.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Pressing Stop could look like the scan restarting, and for scheduled jobs
it really did restart the Google stage.
- Scheduler: check the abort flag between stages and never clear the
Google abort after a Stop (that started a fresh all-users Google scan).
A stopped job is recorded as "cancelled" and skips email/retention;
scheduler_done carries cancelled=true.
- SSE: scan_cancelled and file_scan_done now end the current scan like
scan_done, and sse.replay_messages() never replays a finished scan.
Previously a stopped M365 scan (and every file scan) stayed "current",
so each reconnect replayed it and re-showed Stop + progress.
- Frontend: scan_cancelled clears the M365 running flag and only tears
down the UI when no Google/file scan is still running; scheduler_done /
scheduler_error clear all running flags.
- run_scan: Stop during collection now ends the scan (checkpoint, finish,
scan_cancelled) instead of announcing scan_start / "Scanning…".
- Stop button: switches to a disabled "Stopping…" state on click; all
show/hide goes through _setStopBtnDisplay(), which resets it when hidden
or when a new scan starts.
Adds tests/test_stop_scan.py (10 tests).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
Pressing Stop could look like the scan restarting — and for scheduled jobs the Google stage really did restart.
Causes & fixes
_gsa.clear()before the Google stage — erasing the Stop and starting a fresh all-users Google scan. The scheduler now checks_scan_abortbetween stages and doesn't clear the Google abort after a Stop. A stopped job is recorded ascancelled, skips auto-email/retention, andscheduler_donecarriescancelled: true(shown as "⏹ … stopped" in the log and job history).scan_doneended the "current" SSE scan, so a stopped M365 scan (and every file scan, which ends withfile_scan_done) stayed current. Every reconnect — page load or the 4 s watchdog — replayed its events, re-showing the Stop button and progress bar.scan_cancelledandfile_scan_donenow end the scan too, andsse.replay_messages()never replays a finished scan.scan_cancelledhandler now clearsS._m365ScanRunningand only tears down the UI when no Google/file scan is still running.scheduler_done/scheduler_errorclear all running flags.scan_start+ "Scanning…".run_scannow checks for Stop right after collection and ends cleanly (checkpoint,finish_scan,scan_cancelled)._setStopBtnDisplay(), which resets it when hidden or when a new scan starts.Behaviour change
After a scan has finished or been stopped, refreshing the page no longer replays that scan's lines into the log. Results still load from the database.
Testing
tests/test_stop_scan.py— 10 tests: SSE replay, Stop during collection, scheduler Stop vs. uninterrupted job. The regression tests fail on the old code.scan.jswith synthetic SSE events. Not tested against a live M365/Google scan.🤖 Generated with Claude Code