[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. 🫖 Status page with uptime monitoring & API monitoring as code 🫖 openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor

feat(incidents): record source and source_ref on incident events (#2913) master

* feat(incidents): record source and source_ref on incident events Every incident event now stores where it came from (dashboard, api, mcp, slack, agent, system), taken from the actor in appendIncidentEvent, plus a nullable pointer back to the origin: the Slack permalink, or the API key id for api / mcp. - ServiceContext.origin.ref carries the pointer. Slack fills it with the pinned message's permalink, the approval card's permalink, or the agent thread root's permalink. Slash commands and the declare modal have no message, so it stays null. A failed getPermalink logs and does not fail the write. - An agent-drafted postmortem is stored as source "agent". - Pinned notes no longer get a "[From Slack](url)" suffix. The timeline reads source / sourceRef and shows "via Slack|API|MCP". It still falls back to the old suffix and the "by the agent" text for older rows. - packages/db/scripts/backfill-incident-event-source.mts moves old suffixes into the new columns (dry run unless --apply). The migration is not in this commit. Run `pnpm generate` in packages/db. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QRVXfYfPKMofkscoevyDax * fix(incidents): add the event source migration; address review - Add migration 0094: `incident_event.source` and `source_ref`. Seeding and every DB-backed CI job failed without it. - tRPC `draftPostmortem` no longer takes `draftedBy` from the client and always saves as "user". Before, any writer could get an event stored as `source = "agent"`. Agent drafts keep their own paths (`draftPostmortemWithAgent`, the `draft_postmortem` tool). - handler.test.ts: poll for the captured agent options with a deadline instead of a fixed 100ms sleep. - Comment why an origin ref takes precedence over the actor's key id. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QRVXfYfPKMofkscoevyDax * refactor(dashboard): show the event source with TimelineActorSource only Drop the separate "via …" text component. TimelineActorSource now has two modes. With an avatar it is the corner badge, as before. Without one it is an inline icon after the name. Both keep the same tooltip and link to the origin (the Slack permalink from source_ref). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QRVXfYfPKMofkscoevyDax * refactor(dashboard): resolve the event origin once, badge on cards only Compact rows read as one sentence, so they show no source; the Slack badge stays on the card avatar. eventOrigin handles both shapes: the legacy "[From Slack](url)" note suffix and source / source_ref, with the suffix as a fallback for unbackfilled Slack rows. Seed one legacy note next to the new-form one. * refactor(services): put the Slack permalink on the actor Drop ServiceContext.origin. The event ref is derived from the actor for every type now: key id for api and mcp, permalink for slack. The three Slack call sites set it when they build the context, and SlackActor is the services union member instead of a copy. * ci: apply automated fixes * fix(dashboard): read the legacy Slack suffix only on Slack or unsourced notes A dashboard or API note whose last line was a literal "[From Slack](url)" lost that line and showed a Slack badge. Only Slack ever wrote the suffix, so it is read only when source is null or slack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QRVXfYfPKMofkscoevyDax * refactor(services): lift legacy Slack notes into source columns on read listIncidentEvents normalizes the "[From Slack](url)" note suffix into source / source_ref so every reader sees the columns. The dashboard module that did this client-side is gone; its cases move to a services test, including the guard that only Slack or unsourced notes are read. * ci: apply automated fixes --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>