Skip to content

Radio log: don't treat a Beacon 500 as a failed status change or tasking - #564

Open
Rowantrek wants to merge 5 commits into
master-devfrom
rmacdonald-radiolog-wip
Open

Rowantrek wants to merge 5 commits into
master-devfrom
rmacdonald-radiolog-wip

Conversation

@Rowantrek

Copy link
Copy Markdown
Collaborator

Summary

The Ops/Radio Log dialog changes a team's status or tasks a team before saving the log, and only saves the log if that worked. It asks BeaconClient to throw on errors (throwOnError) so it knows whether the change landed.

The comment at the top of src/shared/BeaconClient/tasking.js says those endpoints "intermittently return 500 despite applying the change". We don't know if Beacon still does this. If it does, the dialog reports a change that worked as a failure and doesn't save the log. A retry then sends the change again, and Beacon rejects it with an error.

This PR makes the dialog check before it reports a failure.

What changes

On a 5xx or network error, the dialog reloads that incident's taskings and checks whether the change went through:

  • Status change: the tasking now has the requested status.
  • Task Team: the team now has an active tasking on the incident.

If it went through, the submit carries on as if it had succeeded: the log is saved, the dialog closes, and for Task Team & SMS the Send SMS dialog opens. A console.warn records that Beacon returned an error but the change landed.

If it didn't go through, or the reload also fails, the error is shown as before. A retry is then checked against freshly loaded data.

A 4xx still fails straight away. Our own errors (such as Beacon not returning a new tasking) and aborted requests also fail straight away.

Simpler error banner. A failed status change or tasking now shows Error: <Beacon's message>. Try again.. If Beacon gave no message, it shows the status code (Beacon returned 500 Internal Server Error) or Couldn't reach Beacon. The full error goes to the console: what was attempted, plus the status, URL, response body and error object.

These messages are unchanged:

  • "changed/tasked, but the log entry didn't save"
  • the pre-submit checks, such as "is now Onsite" or "no longer active"

Implementation

  • OpsLogModalVM.js
    • applyAndConfirm(job, apply, landed) wraps both applyTaskingStatusChange and applyTaskTeam.
    • The "did it land" checks use the tasking, team and incident captured when Submit was clicked, not the live dialog fields. The fields aren't locked while submitting.
    • isUncertainFailure(err) decides which errors trigger the check: 5xx or network errors. 4xx, errors with a userMessage, and AbortError don't.
    • The banner text and console logging are now built by submitFailureMessage and logSubmitFailure.
  • main.js
    • New reloadJobTaskings(jobVm) reloads one incident: one GET /Api/v1/Tasking/Search?JobIds[]=<id> through the existing fetchJobTasking.
    • It resolves true or false.
    • Existing Tasking objects are updated in place by upsertTaskingFromPayload.
  • BeaconClient is unchanged. Other callers still use nullOnError.
  • No change on the normal path. The extra request only happens after a 5xx or a network error.

Known limitation

LAD doesn't remove taskings that are missing from a reload. If Beacon leaves untasked taskings out of Tasking/Search rather than returning them as Untasked, a false 500 on Untask still shows as an error. A retry should then just get a 4xx back from Beacon. Nothing is applied twice.

Docs

  • docs/lad/logs-and-messages.md: the Submit behaviour for status changes and Task Team is now one short paragraph each: LAD does the status change or tasking first, then saves the log; if anything goes wrong the dialog shows the error so you can submit again; nothing is sent twice.

Testing

  • npm test: all 688 tasking tests pass, including 6 new ones in OpsLogModalVM.test.js:
    • status change returns 500 but went through, so the log saves and nothing is resent
    • status change returns 502 and didn't go through, so the error shows and the selected status is kept
    • network error and the reload fails, so the error shows
    • Task Team returns 500 but the tasking was created, so the log saves and the SMS opens without a second tasking
    • Task Team returns 500 and no tasking was created, so the error shows
    • a 400 doesn't trigger a reload
  • npm run lint: clean.
  • scripts/lad-docs harness: I mocked POST /Api/v1/Tasking to create the tasking and then return 500. The dialog sent one POST, found the tasking on reload, saved the log and closed.
  • Not tested against real Beacon. I haven't seen a false 500 there.

🤖 Generated with Claude Code

Rowantrek and others added 5 commits October 16, 2026 12:02
Beacon's tasking endpoints have been known to return 500 after applying the
change. The Ops/Radio Log dialog reported those as failures, so the log
wasn't saved and a retry re-sent the change.

On a 5xx or network error the dialog now reloads that incident's taskings
and checks whether the change landed (the tasking has the requested status,
or the team now has an active tasking there). If it did, the submit carries
on and saves the log; if not, the error is shown as before. A 4xx still
fails straight away.

The banner for a failed status change or tasking is now just Beacon's
message plus "Try again"; the full error (status, URL, body) goes to the
console.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Beacon's tasking endpoints have been known to return 500 after applying the
change. The Ops/Radio Log dialog reported those as failures, so the log
wasn't saved and a retry re-sent the change.

On a 5xx or network error the dialog now reloads that incident's taskings
and checks whether the change landed (the tasking has the requested status,
or the team now has an active tasking there). If it did, the submit carries
on and saves the log; if not, the error is shown as before. A 4xx still
fails straight away.

The banner for a failed status change or tasking is now just Beacon's
message plus "Try again"; the full error (status, URL, body) goes to the
console.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fields aren't locked while submitting, so reading activeTasking() could
look at a different team if the Team field was edited during the reload.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant