Skip to content

Goal: Sentry Configuration as Code

Arda’s Sentry alerting is configured by hand in the Sentry UI. Seven issue alert rules currently exist across two projects, with overlapping scope, one outright duplicate, and a Linear integration that is only correctly configured on a rule that is disabled. This project builds a small, reusable configuration-as-code layer for Sentry issue alert rules — snapshot, plan, apply, verify — and then uses it to perform a specific, auditable migration: consolidate high-priority routing into Linear, add an urgent tier, and retire the arda-frontend Slack notifications.

The layer is deliberately narrow. It is not a general-purpose Sentry SDK; it models only the API surface required for issue alert rules, but is structured so that additional resource types (projects, DSNs, uptime monitors, dashboards) can be added by writing one new file, not by refactoring the core.

  • None yet. A PDEV ticket should be created to track this work.
RepositoryRolePlanned Changes
infrastructurePrimary artifact repoNew Sentry configuration-as-code library, CLI, desired-state config, migration and rollback scripts
documentationProject artifactsThis goal, design and decision-log documents, schema notes, completion report
  1. A snapshot command captures all issue alert rules for arda-frontend and platform-be verbatim to disk, with a manifest recording org, projects, rule IDs, and a token fingerprint (hash — never the token).
  2. Rule types are derived from observed live payloads, not from documentation or memory. Every empirically discovered shape is recorded in a schema-notes document with the date observed and its provenance.
  3. Server-managed fields are determined empirically (GETPUT unchanged → GET → diff) and stripped by normalization, so an unchanged rule produces an empty diff.
  4. A plan command prints a readable, path-addressed changeset and exits non-zero when changes are pending (CI-friendly).
  5. apply is dry-run by default, requires --confirm, and refuses to run without a snapshot from the current session.
  6. verify re-reads live state and asserts conformance with the desired state.
  7. The migration script is idempotent — running it twice produces no second set of changes — and refuses to run while any entry in its DECISIONS block is still TODO.
  8. A rollback script restores from a named snapshot directory, with the new-rule-IDs limitation stated explicitly in code and documentation.
  9. Adding a new resource type requires one new file implementing the resource interface plus a registry entry — demonstrated by review, not by speculative implementation.
  10. The guidance compliance audit has been run against the finished branch and its result recorded in the PR, before the PR is opened for external review.

Sentry was introduced to the platform by the Sentry Integration project, which explicitly placed “Sentry alert rule implementation” out of scope, leaving only recommendations. This project picks that thread up.

Note a divergence worth confirming: the Sentry Integration design specified Sentry projects named arda-operations and arda-accounts, one per backend component. The live org has arda-frontend and platform-be. Reality and the design document disagree; the live org is authoritative for this project’s purposes, but the discrepancy should be reconciled.

Seven issue alert rules, verified in the org arda-systems (region https://us.sentry.io):

IDProject(s)NameStatusNotes
3153115bothSend a notification for high priority issuesenabledEmail to issue owners + Linear action (priority 1, no assignee/label/project)
3426957platform-beSend a notification for high priority issuesenabledEmail only, frequency 0 — the duplicate
3190653bothSentry Alerts - prodenabledSlack #sentry-fe-prod, first-seen, env production
3190652arda-frontendSentry Alerts - stageenabledSlack, first-seen, env stage
3190649arda-frontendSentry Alerts - devenabledSlack, first-seen, env dev
3462179platform-beOperations fatal startup / uncaught exceptionenabledSlack, level=fatal + mechanism:UncaughtExceptionHandler
3433641arda-frontendNotify via LineardisabledLinear action, priority 2, has labelId and assigneeId, priority ≥ 75 filter

Linear priority mapping, confirmed from live config: 1 = Urgent, 2 = High, 3 = Medium, 4 = Low. Rule 3433641 is the best-configured Linear action in the org and serves as the template for the migration’s action blocks.

This work is the first inhabitant of OperationsManagement — a fourth platform element alongside Environments, Root, and the informal tools/scripts collection. It holds resources that observe, alert on, and administer the platform rather than run it; Grafana and comparable observability runtime are future candidates.

Two framing points settled before design, recorded in infrastructure/knowledge-base/platform-architecture.md:

  • cdk in this repo names the IaC machinery generally, not AWS CDK. The Construct / Stack / Application / Instance vocabulary is borrowed from AWS with a looser reading — a Construct need not extend constructs.Construct, a Stack need not become a CloudFormation stack. platform/constructs/postmark/ is the standing proof.
  • The element is spelled OperationsManagement, never oam, in paths. src/main/cdk/constructs/oam/ already means something else — infrastructure-supporting constructs (IAM roles, secrets, OIDC providers, CloudWatch dashboards).

The capability layers as follows. Layers 1–2 are shared with any future OperationsManagement provider; layer 3 is Sentry’s declared desired state:

LayerLocationContents
Vendor metadataplatform/sentry-service.ts, platform/one-password.tsOrg slug, region URL, API base, SENTRY_API_SURFACE freshness block, Linear priority mapping, credential item reference
Transport + enginetools/lib/sentry/ (client + resources), tools/lib/desired-state/, tools/lib/sentry/, tools/lib/drift/sentry-probe.tsAuthenticated transport with retry/backoff; vendor-neutral reconcile engine (resource seam, diff, plan, snapshot); Sentry resource implementations; read helpers
Constructplatform/constructs/sentry/LinearRoutedAlertTier — parametric on priority, environment, threshold, and Linear binding. Instantiated twice: High and Urgent.
Stackstacks/operations-management/sentry-fault-alerting.tsDeployed per Sentry project (arda-frontend, platform-be)
Applicationapps/OperationsManagement/index.tsComposes the Sentry stacks today; Grafana and others later
Instanceinstances/OperationsManagement/arda-systems.tsThe values that configure it: org slug, Linear IDs, environment names, thresholds
Driverstools/, scripts/sentry/Config driver and drift driver; thin 1Password operator wrapper

Three consequences worth stating explicitly, because each one changes the design:

  1. The functional decomposition lands at the Stack layer. Fault (issue alert rules) and Performance (metric alerts, dashboards, thresholds) deploy and change independently, and a Stack is the unit of deployment. A future sentry-performance-monitoring.ts becomes a sibling Stack, not a second toolchain — the client, engine, diff, plan, and CLI are untouched.
  2. The DECISIONS block becomes the Instance file. That is the repo’s established home for “values that configure a capability for deployment”, it is reviewable in a PR, and it turns the refuse-if-TODO gate from a runtime check into a type error.
  3. No cdk.context.json handoff. Postmark needs one because Route53 records depend on DKIM keys, forcing a pre-deploy step. Nothing in CloudFormation references a Sentry alert rule, so OperationsManagement is an independent deployment target. It reuses the vocabulary and the platform/ metadata layer, and nothing else.
  • Library — authenticated HTTP client with Retry-After handling and backoff, issue-alert rule types derived from live fixtures, a resource abstraction that is the extensibility seam, structural diff with empirical normalization, plan computation, and snapshot dump/restore.
  • CLIsnapshot, import, plan, apply, verify subcommands with a JSONL audit log behind an --audit flag.
  • Migration script — phased (snapshotdiscoverplanapplyverify), individually confirmable, resumable, with a typed DECISIONS block that gates execution.
  • Rollback script — restore from a named snapshot.
  • Schema notes — every empirically discovered condition/filter/action shape, dated and attributed.
  • General-purpose coverage of the Sentry API. Only issue alert rules are modeled.
  • Metric alert rules, dashboards, uptime monitors, projects, DSNs, and teams — the abstraction must accommodate them; this project does not implement them.
  • Reconciling the Sentry project topology with the Sentry Integration design (arda-operations / arda-accounts vs. arda-frontend / platform-be).
  • Changes to the Linear workspace itself (teams, projects, labels, workflow states, automation rules).
  • CI wiring of plan as a drift gate. The command is built to be CI-friendly; scheduling it is follow-on work.
  1. Do not invent the API schema. Sentry’s issue-alert rule JSON — condition IDs, filter IDs, action IDs, and their field names — is under-documented, and the sentry_app action backing the Linear integration is especially opaque. Every payload is obtained read-modify-write from live state or by round-trip discovery. Guessing at a field name is a stop-and-ask condition, not a judgment call.
  2. Never apply unattended. The migration is built, dry-run, and its plan presented. Execution is the user’s call.
  3. SENTRY_AUTH_TOKEN comes from the environment only — never from a file, never hardcoded. Fail fast with a clear message when unset.
  4. Fits the existing toolset. The code joins the repository’s established TypeScript/ts-node/Jest stack and reuses tools/lib/ helpers rather than standing up a parallel toolchain. This supersedes the source prompt’s zero-dependency, --experimental-strip-types, no-build-step constraint, which would have meant a second retry/backoff client beside postmark-client.ts.
  5. Correctness over coverage. A narrow, correct model beats a broad, speculative one.
  6. Commits land in logical increments — client, then types and resource, then diff and plan, then CLI, then migration — not one terminal commit.

Superseded. The decisions originally listed here (D-01D-08) were carried into decision-log.md as DQ-001DQ-020 and all but one are settled. Recon against the live org reshaped several of them beyond recognition:

OriginalWhat actually happened
D-01 code placementResolved — see Architecture Placement and DQ-001
D-02 urgentEnvironmentAlpha001-prod is real, but only on platform-be; the two projects share no environment name. Resolved by a logical-environment abstraction (DQ-012)
D-03 escalationStrategyPremise disproved by probe. A later rule firing for an already-ticketed Sentry issue creates no second ticket and does not upgrade priority — escalation was silently lost. Urgent now notifies via Slack instead (DQ-017)
D-04 Linear IDsResolved live: label = “Bug”, state = “Triage”, routing per discipline (DQ-010)
D-05 frontendScopeDissolved. Attachment is via detectorIds, so detach is a reversible array edit, not a delete-vs-keep dilemma (DQ-005)
D-06 removalModeDelete outright (DQ-018)
D-07 snapshotsCommitted (DQ-006)
D-08 trigger narrowingDrop existing_high_priority_issue (DQ-020)

Two assumptions in this goal were also overturned outright: the API surface is Sentry’s workflow engine, not the legacy issue-alert-rule API (DQ-004); and the 30-minute Urgent window is not expressible — Sentry’s interval enum has no 30m (DQ-008).

#DeliverableLocation
1Sentry vendor metadata and credential referenceplatform/sentry-service.ts, platform/one-password.ts
2Sentry transport clienttools/lib/sentry/client.ts
3Vendor-neutral desired-state enginetools/lib/desired-state/
4Issue-alert resource implementation and read probetools/lib/sentry/, tools/lib/drift/sentry-probe.ts
5Constructs, Stack, Application, Instanceplatform/constructs/sentry/, stacks/operations-management/, apps/OperationsManagement/, instances/OperationsManagement/
6Config driver and drift driver + operator wrappertools/, scripts/sentry/
7One-time migration and rollback scriptstools/ (transitional — apply subsumes them once desired state is declared)
8Sentry API observations note (dated, per SENTRY_API_SURFACE)current-system/oam/sentry-service/sentry-api-observations.md
9Design document and decision logThis project directory
10Plan output from a live dry runThis project directory
  • Design — the design produced from this goal.
  • Decision Log — settled decisions and rejected alternatives, including the ones that overturned this goal’s assumptions.
  • Sentry Integration — the project that introduced Sentry and deferred alert rules.
  • Operations Sentry — completed backend Sentry onboarding.
  • Sentry Observability — how Arda uses Sentry today: capture topology, projects, environments.
  • Platform elements and the generalized IaC vocabulary — the four platform elements, Construct/Stack/Application/Instance, and how non-AWS providers fit. Written by this project.
  • tools/ vs scripts/ split criteria — logic in tools/, operator ergonomy in scripts/.
  • typescript-coding skill (workspace/instructions/claude/skills/typescript-coding/) — strict mode, ESM packaging, zero-dependency patterns. Note: this skill has no counterpart page on the documentation site.

Copyright: (c) Arda Systems 2025-2026, All rights reserved