Skip to content

fix(backend): guarded status transitions for error issues and investigations - #2310

Merged
Makisuo merged 6 commits into
mainfrom
fix/guarded-status-transitions
Nov 6, 2026
Merged

Makisuo merged 6 commits into
mainfrom
fix/guarded-status-transitions

fix(backend): close four guarded-transition gaps from review

640481d
Select commit
Loading
Failed to load commit list.
Maple Review Bot / Maple / review succeeded Nov 6, 2026 in 2m 43s

Confidence 10/10 · No issues found

🟢 Confidence 10/10 · safe to merge. Every guarded write is pinned by a PGlite test at this head, including the loser-of-a-race 409 and the dropped late diagnosis.
no findings · tests covered · risk medium · 2/2 new units observable

Guards every error-issue and investigation status write on the state it was decided from, and pins the losers of a race to typed 409s or no-ops. The open TransitionConflictError from transition-row.ts is handled at all six call sites at this head, so it should stop reaching maple-api.

  • applyTransition guards on fromState and remaps the conflict to a 409
  • Tick regressions only reopen rows still done; snooze/lease races are skipped
  • Manual investigation moves are limited to MANUAL_INVESTIGATION_TRANSITIONS, reopen targets the run's own verdict
  • Late diagnosis/partial writes on settled runs are dropped with a span attribute

Production impact

Open errors in the changed files (1)
Issue Service Occurrences File
@maple/backend/TransitionConflictError maple-api 4 packages/backend/src/platform/transition-row.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/backend/src/services/errors/ErrorsService.ts 71k ErrorsService.expireLeases 71k/day, 0.0% err
packages/backend/src/services/errors/apply-diagnosis.ts 53 ApplyDiagnosis.applyDiagnosisWrites 33/day, 0.0% err
ApplyDiagnosis.applyInconclusiveWrites 20/day, 0.0% err
Telemetry this change adds and removes (2)
  • ➕ attribute maple.investigation.late_write_dropped · packages/backend/src/services/errors/apply-diagnosis.ts:132
  • ➕ attribute maple.error_tick.regressions_lost · packages/backend/src/services/errors/error-tick-persistence.ts:635
Ingest cost of new log lines
  • packages/backend/src/services/errors/ErrorsService.ts:1060: If this logs once per call, about 593 MB/month: the file's operations run 71k times a day.
What was checked
  • expireLeases guard leaseExpiresAt.lt(nowMs) matches the preamble's isNotNull + < now filter (ErrorsService.ts:1088, :1020)
  • The restart re-arm still works: triageStatusFor("investigating") is pending, which skips the none/pending guard (InvestigationService.ts:78)
  • Each transitionRow caller (applyTransition, restart, updateStatus, apply-diagnosis, issue-hub, webhook-events) remaps or swallows the conflict
Observability coverage: 2 of 2 changes observable
Change Kind Observable Evidence
Errors tick per-row transitions (snooze wakeup, lease expiry) background worker step yes skipLostTransition logs with orgId/issueId/via; ErrorsService.expireLeases span already exists
Investigation diagnosis / status writes database write yes maple.investigation.late_write_dropped span attribute and Effect.logWarning in apply-diagnosis.ts:132

640481d · Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.