@pipeline-builder/pipeline-data 3.4.125 → 3.4.127

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -100,6 +100,54 @@ interface BuildFailure {
100
100
  occurrences: number;
101
101
  lastSeen: string;
102
102
  }
103
+ /** Effective standard-event retention (days): a valid per-org override wins,
104
+ * else the global env default. Shared by the sweep + the settings surface so
105
+ * they can't drift. The `-1` unlimited sentinel (Phase 8) passes straight
106
+ * through — the sweep reads it as "keep forever, skip this org's standard
107
+ * events". A positive override clamps to [1, RETENTION_MAX_DAYS]; a `null`, a
108
+ * non-integer, or any other out-of-range value (e.g. 0, -2) falls back to the
109
+ * env default. */
110
+ export declare function resolveEventRetentionDays(override?: number | null): number;
111
+ /** Effective DORA-source retention (days): a valid per-org override wins, else
112
+ * the global env default. The `-1` unlimited sentinel (Phase 8) passes straight
113
+ * through — the sweep reads it as "keep forever, skip this org's DORA-source
114
+ * windows". A positive override clamps to [1, RETENTION_MAX_DAYS]; a `null`, a
115
+ * non-integer, or any other out-of-range value (e.g. 0, -2) falls back to the
116
+ * env default. */
117
+ export declare function resolveDoraRetentionDays(override?: number | null): number;
118
+ /** The cutoff instant for a retention window: rows with `created_at` strictly
119
+ * before this (`< cutoff`) are expired. Deterministic for a fixed `now`. */
120
+ export declare function retentionCutoff(now: Date, days: number): Date;
121
+ /** Per-org retention override row (Phase 7). Both nullable ⇒ global defaults. */
122
+ export interface ReportingRetentionSettings {
123
+ eventRetentionDays: number | null;
124
+ doraRetentionDays: number | null;
125
+ defaultEventRetentionDays: number;
126
+ defaultDoraRetentionDays: number;
127
+ }
128
+ /** Options for the reporting retention sweep. */
129
+ export interface ReportingRetentionOptions {
130
+ /** Rows deleted per statement (default 1000). */
131
+ batchSize?: number;
132
+ /** Max batches per table per org per tick (default 50); the rest defers to
133
+ * the next tick so a huge backlog can't hold locks too long. */
134
+ maxBatchesPerTable?: number;
135
+ /** Fixed "now" for the whole sweep (default `new Date()`). */
136
+ now?: Date;
137
+ }
138
+ /** Per-run purge tallies (also logged). */
139
+ export interface ReportingRetentionCounts {
140
+ /** Orgs swept this run. */
141
+ orgs: number;
142
+ /** Standard `pipeline_events` (environment IS NULL) rows purged. */
143
+ standardEvents: number;
144
+ /** DORA-source `pipeline_events` (environment IS NOT NULL) rows purged. */
145
+ doraEvents: number;
146
+ /** `deployment_outcomes` rows purged. */
147
+ deploymentOutcomes: number;
148
+ /** `incidents` rows purged. */
149
+ incidents: number;
150
+ }
103
151
  /**
104
152
  * DORA performance band. `null` = insufficient data to classify (no
105
153
  * deployments/failures/lead-time sample in the window), so the UI shows a
@@ -110,110 +158,216 @@ export type DoraLevel = 'elite' | 'high' | 'medium' | 'low' | null;
110
158
  export interface DoraOptions {
111
159
  /** Restrict to a single pipeline (per-pipeline DORA). */
112
160
  pipelineId?: string;
113
- /** Count only executions deployed to this environment (deploy-scoped). */
161
+ /** Restrict to a single deploy environment (else all deploy environments). */
114
162
  environment?: string;
115
- /** Count only executions tagged with ANY environment (real deployments). */
116
- deploysOnly?: boolean;
163
+ /**
164
+ * Per-org incident→deploy correlation window override (hours). When set (a
165
+ * positive finite number), the incident correlation uses it instead of the
166
+ * global `DORA_INCIDENT_WINDOW_HOURS`. The route resolves this from the org's
167
+ * `dora_settings` row (see {@link ReportingService.getIncidentSettings}) and
168
+ * passes it in; unset falls back to the env default.
169
+ */
170
+ incidentWindowHours?: number;
171
+ }
172
+ /**
173
+ * Per-org reporting settings surfaced to the org-admin panel. `incidentWindowHours`
174
+ * (Phase 5b) is the incident→deploy correlation window; `eventRetentionDays` /
175
+ * `doraRetentionDays` (Phase 7) are the two retention-sweep windows. Each override
176
+ * is `null` when unset (the paired `default*` field shows the env fallback applied).
177
+ */
178
+ export interface IncidentSettings {
179
+ /** The org's stored correlation-window override in hours, or `null` when unset. */
180
+ incidentWindowHours: number | null;
181
+ /** The global env default applied when no override is stored. */
182
+ defaultWindowHours: number;
183
+ /** Standard-event retention override in days, or `null` when unset (Phase 7). */
184
+ eventRetentionDays: number | null;
185
+ /** DORA-source retention override in days, or `null` when unset (Phase 7). */
186
+ doraRetentionDays: number | null;
187
+ /** Global standard-event retention default applied when unset (days). */
188
+ defaultEventRetentionDays: number;
189
+ /** Global DORA-source retention default applied when unset (days). */
190
+ defaultDoraRetentionDays: number;
191
+ }
192
+ /** A partial reporting-settings write (Phase 5b + 7). Only provided fields are
193
+ * upserted; omitted fields are left unchanged (an omitted retention field keeps
194
+ * its stored override / the global default). */
195
+ export interface ReportingSettingsPatch {
196
+ incidentWindowHours?: number;
197
+ eventRetentionDays?: number;
198
+ doraRetentionDays?: number;
199
+ }
200
+ /** One row of the org-admin incidents list (recent incidents + deploy correlation). */
201
+ export interface IncidentListItem {
202
+ incidentId: string;
203
+ environment: string;
204
+ severity: string;
205
+ openedAt: string | null;
206
+ resolvedAt: string | null;
207
+ createdAt: string | null;
208
+ /** True once the incident has a `resolved_at`. */
209
+ resolved: boolean;
210
+ /** The correlated deploy execution id (most recent successful deploy in-window), or null. */
211
+ correlatedExecutionId: string | null;
212
+ /** That deploy's completion instant, or null when uncorrelated. */
213
+ deployCompletedAt: string | null;
214
+ }
215
+ /** Result of the wiring-test dry-run correlation ({@link ReportingService.testIncidentCorrelation}). */
216
+ export interface IncidentTestResult {
217
+ environment: string;
218
+ /** The synthetic incident's openedAt (now, ISO). */
219
+ openedAt: string;
220
+ /** The effective correlation window used. */
221
+ windowHours: number;
222
+ /** Whether a recent successful deploy to `environment` correlated. */
223
+ correlated: boolean;
224
+ /** The correlated deploy execution id, or null. */
225
+ executionId: string | null;
226
+ /** That deploy's completion instant, or null. */
227
+ deployCompletedAt: string | null;
117
228
  }
118
229
  /**
119
230
  * DORA metrics over a [from,to] window, org-scoped (single-org or rollup subtree).
120
231
  *
121
- * A "deployment" is a TERMINAL pipeline-level event, rolled up to one row per
122
- * `execution_id` (FAILED wins, then SUCCEEDED, then CANCELED/STOPPED — same
123
- * precedence as `listPipelineExecutions`).
232
+ * DEPLOY-BASIS every metric derives from real DEPLOY-STAGE executions, i.e.
233
+ * `pipeline_events` rows with `event_type='STAGE'` and a non-null `environment`
234
+ * (the forwarder sets `environment` only for the stages a user declared in
235
+ * `pb.deploys`). A CI-only build/test pipeline with no deploy stage produces NO
236
+ * DORA data — there is no run-based fallback. The panel is empty until deployed
237
+ * pipelines re-synth with the new deploy tags and start emitting deploy events.
124
238
  *
125
- * DISCLOSURE these are RUN-BASED approximations of DORA. A "deployment" here
126
- * is any successful pipeline RUN, not a verified production deployment: the
127
- * event stream carries no deploy-stage/environment marker, so a CI-only
128
- * build/test pipeline counts the same as one that ships to prod. That makes
129
- * `deploymentFrequency` a pipeline-throughput signal and `changeFailureRate` a
130
- * pipeline-failure rate (build/test failures caught in CI count too), and MTTR
131
- * a pipeline-recovery time. Only `leadTime` carries an explicit `approx` flag
132
- * (it is additionally a run-time proxy), but ALL four share the run≠deploy
133
- * caveat until deploy/commit metadata is captured. See docs/dora-metrics.md.
239
+ * `production` is the headline environment; MTTR is measured production-only.
134
240
  */
135
241
  export interface DoraMetrics {
136
- /** The [from,to] window echoed back (started_at range). */
242
+ /** The [from,to] window echoed back (deploy `completed_at` range). */
137
243
  window: {
138
244
  from: string;
139
245
  to: string;
140
246
  };
141
- /**
142
- * Whether the numbers count real deployments or pipeline runs:
143
- * - `'deploy'` — scoped to executions tagged with a deploy `environment`
144
- * (via `environment`/`deploysOnly`); a genuine deployment signal.
145
- * - `'run'` — default: every successful PIPELINE run counts (no deploy
146
- * marker applied). DF/CFR/MTTR then reflect pipeline activity, not deploys.
147
- */
148
- basis: 'deploy' | 'run';
149
247
  /** The scoping applied (echoed for the UI); `null` when unscoped. */
150
248
  filters: {
151
249
  pipelineId: string | null;
152
250
  environment: string | null;
153
251
  };
154
- /** Deployment Frequency SUCCEEDED terminal deployments in the window. */
252
+ /** The headline environment name (`production`). */
253
+ headline: string;
254
+ /** Per-environment DF / CFR / lead time. Sorted headline-first, then A→Z. */
255
+ environments: DoraEnvMetrics[];
256
+ /**
257
+ * Mean Time To Restore — PRODUCTION-ONLY, from `deployment_outcomes`.
258
+ * `median(restored.at − deployed.completed_at)` over restored production
259
+ * incidents (deltas clamped ≥0). `incidents` counts production deploys marked
260
+ * failed; `restored` counts those that recovered; `medianSeconds` is null when
261
+ * no restored incident has a resolvable deploy time.
262
+ */
263
+ meanTimeToRestore: {
264
+ incidents: number;
265
+ restored: number;
266
+ medianSeconds: number | null;
267
+ level: DoraLevel;
268
+ };
269
+ /**
270
+ * Coverage reconciliation — registered pipelines with no observed deploy in
271
+ * the window. A high `withoutDeploys` count means DORA is blind to most of the
272
+ * fleet (pipelines that haven't re-synthed with deploy tags, or don't deploy).
273
+ */
274
+ coverage: {
275
+ /** Pipelines in the registry (org-scoped). */
276
+ registered: number;
277
+ /** Registered pipelines with ≥1 deploy-stage execution in the window. */
278
+ deploying: number;
279
+ /** registered − deploying (clamped ≥0). */
280
+ withoutDeploys: number;
281
+ };
282
+ }
283
+ /** Per-environment DORA metrics (deployment frequency, CFR, lead time). */
284
+ export interface DoraEnvMetrics {
285
+ environment: string;
286
+ /** Deployment Frequency — successful deploy-stage executions for this env. */
155
287
  deploymentFrequency: {
156
- /** Count of successful deployments. */
157
288
  deployments: number;
158
- /** Successful deployments per day over the window. */
159
289
  perDay: number;
160
- /** Performance band, or null when there were no deployments. */
161
290
  level: DoraLevel;
162
291
  };
163
- /** Change Failure Rate — failed / (succeeded + failed); CANCELED excluded. */
292
+ /**
293
+ * Change Failure Rate — two-class:
294
+ * `(deployTimeFailures + postDeployFailures) / attempts`.
295
+ * - `deployTimeFailures` — deploy stage `result=failed` (from events).
296
+ * - `postDeployFailures` — a successful deploy later marked failed in prod
297
+ * (from `deployment_outcomes`).
298
+ * - `attempts` — all terminal deploy-stage attempts (succeeded + failed).
299
+ */
164
300
  changeFailureRate: {
165
- failed: number;
166
- /** succeeded + failed (the CFR denominator). */
167
- total: number;
168
- /** failed/total as a percentage, 0–100, 1 decimal. */
169
- pct: number;
170
- /** Performance band, or null when there were no deployments to judge. */
301
+ rate: number;
302
+ deployTimeFailures: number;
303
+ postDeployFailures: number;
304
+ attempts: number;
171
305
  level: DoraLevel;
172
306
  };
173
- /** Mean Time To Restore — avg gap from a failure INCIDENT to its recovery.
174
- * Consecutive failed runs of a pipeline (with no green run between) collapse
175
- * into one incident; the gap is measured from the first failure's END to the
176
- * recovering run's END. The recovery is visible up to a look-ahead past `to`
177
- * so a failure near the window edge isn't spuriously counted unrestored. */
178
- meanTimeToRestore: {
179
- /** Failure incidents in the window (maximal runs of consecutive failures). */
180
- failures: number;
181
- /** Incidents that were followed by a succeeded run (recovered). */
182
- restored: number;
183
- /** Average restore gap in seconds; null when there were no incidents. */
184
- avgSeconds: number | null;
185
- /** Performance band, or null when there were no incidents. */
186
- level: DoraLevel;
187
- };
188
- /** Lead Time — PROXY: median pipeline RUN TIME of succeeded deployments.
189
- * NOT true commit→prod lead time (executions don't capture commit time),
190
- * hence `approx: true` so the UI/docs can label it. */
307
+ /**
308
+ * Lead Time MEASURED: `median(deploy_completed oldest_commit_time)` over
309
+ * successful deploys with a resolvable commit timestamp (deltas clamped ≥0).
310
+ * `medianSeconds` is `null` (= unknown) when no successful deploy in this env
311
+ * carried a `commit_timestamp`. The old median-run-duration proxy is removed.
312
+ */
191
313
  leadTime: {
192
- /** Succeeded deployments with a duration (the median sample). */
314
+ /** Successful deploys with a resolvable commit time (the median sample). */
193
315
  deployments: number;
194
- /** Median run time in seconds; null when no successful deployments. */
195
316
  medianSeconds: number | null;
196
- approx: true;
197
- /** Performance band, or null when there were no successful deployments. */
198
317
  level: DoraLevel;
199
318
  };
200
319
  }
201
- /** One interval bucket of the DORA trend (deployment frequency + change failure). */
320
+ /** One interval bucket of the DORA trend (deploy frequency + change failure). */
202
321
  export interface DoraTrendPoint {
203
- /** Bucket start (DATE_TRUNC of started_at), ISO text. */
322
+ /** Bucket start (DATE_TRUNC of the deploy `completed_at`), ISO text. */
204
323
  period: string;
205
- /** Successful deployments in the bucket. */
324
+ /** Successful deploy-stage executions in the bucket. */
206
325
  deployments: number;
207
- /** Failed deployments in the bucket. */
326
+ /** Failed deploy-stage executions in the bucket. */
208
327
  failed: number;
209
- /** succeeded + failed in the bucket. */
328
+ /** succeeded + failed in the bucket (deploy attempts). */
210
329
  total: number;
211
- /** failed/total as a percent (0 when total is 0). */
330
+ /** failed/total as a percent (0 when total is 0). Deploy-time CFR only. */
212
331
  changeFailurePct: number;
213
332
  }
333
+ /** Per-stage build-health metrics (Phase 6) for one pipeline over a window. */
334
+ export interface BuildHealthStage {
335
+ stage: string;
336
+ /** Terminal stage runs (succeeded + failed) in the window. */
337
+ runs: number;
338
+ successes: number;
339
+ failures: number;
340
+ /** successes / runs as a percent (0 when runs is 0). */
341
+ successRate: number;
342
+ /** Duration percentiles over the stage's terminal runs; null when no durations. */
343
+ p50Ms: number | null;
344
+ p90Ms: number | null;
345
+ p99Ms: number | null;
346
+ }
347
+ /**
348
+ * Per-pipeline build-health breakdown (Phase 6). Standard reporting (NOT
349
+ * `advanced_reporting`-gated) — per-stage success rate + timing percentiles, with
350
+ * totals summed across stages.
351
+ */
352
+ export interface BuildHealth {
353
+ stages: BuildHealthStage[];
354
+ totals: {
355
+ runs: number;
356
+ failures: number;
357
+ failureRate: number;
358
+ };
359
+ }
360
+ /** Post-deploy incident marker (Phase 5) accepted by `ReportingService.recordIncident`. */
361
+ export interface IncidentInput {
362
+ incidentId: string;
363
+ environment: string;
364
+ openedAt: string;
365
+ resolvedAt?: string;
366
+ severity: string;
367
+ }
214
368
  /** Event payload accepted by `ReportingService.ingestEvents`. Mirrors the route's Zod shape. */
215
369
  export interface IngestEvent {
216
- /** Stable pipeline id the events Lambda read from the `PIPELINE_EVENT_ID`
370
+ /** Stable pipeline id the events Lambda read from the `pb.pipeline-id`
217
371
  * tag (= the platform pipelineId). The registry join key. */
218
372
  pipelineId: string;
219
373
  eventSource: 'codepipeline' | 'codebuild' | 'plugin-build';
@@ -231,10 +385,29 @@ export interface IngestEvent {
231
385
  commitSha?: string;
232
386
  /** Source ref/branch (DORA deploy attribution). */
233
387
  commitRef?: string;
234
- /** Deploy target (e.g. "production"). Its presence marks a real deployment. */
388
+ /** Deploy target (e.g. "production"). Its presence on a STAGE/ACTION event
389
+ * marks a real deployment (derived server-side — there is no `isDeploy`). */
235
390
  environment?: string;
391
+ /** Oldest unshipped commit timestamp (ISO 8601) for measured lead time. */
392
+ commitTimestamp?: string;
393
+ /** Number of commits shipped in this change (≥1). */
394
+ commitCount?: number;
236
395
  detail?: Record<string, unknown>;
237
396
  }
397
+ /**
398
+ * Per-event metric descriptor emitted (via the {@link ReportingService.ingestEvents}
399
+ * `onMetric` hook) for each REGISTERED terminal deploy/stage event, so the route
400
+ * layer can fan them into Prometheus counters without pipeline-data importing
401
+ * api-server's metrics registry. `result` is the terminal outcome; `environment`
402
+ * is non-null only for a deploy-stage event.
403
+ */
404
+ export interface IngestMetric {
405
+ pipelineId: string;
406
+ orgId: string;
407
+ stage: string;
408
+ environment: string | null;
409
+ result: 'succeeded' | 'failed';
410
+ }
238
411
  /** Counts + the (possibly truncated) list of unregistered pipeline ids the caller can log. */
239
412
  export interface IngestResult {
240
413
  inserted: number;
@@ -250,6 +423,7 @@ export interface IngestResult {
250
423
  * - Timeseries queries (execution/build metrics with date ranges): 2 min TTL
251
424
  */
252
425
  export declare class ReportingService {
426
+ #private;
253
427
  /** Invalidate all cached reports for an org (call after event ingest). */
254
428
  invalidateOrg(orgId: string): Promise<void>;
255
429
  /**
@@ -261,7 +435,7 @@ export declare class ReportingService {
261
435
  *
262
436
  * Returns counts + a sample of unregistered pipeline ids for observability.
263
437
  */
264
- ingestEvents(events: IngestEvent[]): Promise<IngestResult>;
438
+ ingestEvents(events: IngestEvent[], onMetric?: (m: IngestMetric) => void): Promise<IngestResult>;
265
439
  /**
266
440
  * Build the org-scope predicate for a report query. With `orgIds` (the
267
441
  * org → team rollup — a parent's `[self, ...descendants]`) it becomes an
@@ -328,43 +502,62 @@ export declare class ReportingService {
328
502
  */
329
503
  getErrors(orgId: string, from: string, to: string, limit?: number, orgIds?: string[]): Promise<ErrorEntry[]>;
330
504
  /**
331
- * 1.9 DORA metrics over [from,to] (started_at range), org-scoped + rollup-aware.
332
- *
333
- * All four metrics derive from a per-execution roll-up of TERMINAL PIPELINE
334
- * events (one row per execution_id+pipeline_id; FAILED wins, then SUCCEEDED,
335
- * then CANCELED/STOPPED mirroring `listPipelineExecutions`). The scan is
336
- * gated by the `p.org_id ${pred}` join exactly like the sibling reports, so a
337
- * rollup passes the org→team subtree and a foreign org's executions never
338
- * enter the aggregate.
339
- *
340
- * DF/CFR/lead-time count only CORE-window executions ([from,to]). MTTR is
341
- * per-INCIDENT: consecutive failures collapse into one incident and the
342
- * recovery lookup may see the next success up to MTTR_RESTORE_LOOKAHEAD past
343
- * `to`, so a failure near the edge isn't right-censored into "never restored".
344
- * The scan bound is therefore `[from, to + look-ahead]`; the started_at range
345
- * still rides the same index as the sibling reports.
505
+ * 1.9 DORA metrics over a [from,to] deploy-completion window, org-scoped +
506
+ * rollup-aware. DEPLOY-BASIS ONLY — every metric derives from real deploy-stage
507
+ * executions (`event_type='STAGE'` with a non-null `environment`, set by the
508
+ * forwarder for the stages a user declared in `pb.deploys`). No run-based
509
+ * fallback: a pipeline with no deploy stage produces no DORA data.
346
510
  *
347
- * DISCLOSURE: by default DF/CFR/MTTR are RUN-based (any successful PIPELINE
348
- * run = a "deployment"), and Lead Time is additionally a run-time PROXY
349
- * flagged `approx: true`. Pass `environment` or `deploysOnly` to scope to
350
- * executions tagged with a real deploy targetthe response `basis` reports
351
- * which was used. See the DoraMetrics doc + docs/dora-metrics.md.
511
+ * Four scoped SQL scans run inside one tx (each org-gated by `p.org_id ${pred}`
512
+ * / `o.org_id ${pred}` so a rollup passes the org→team subtree and a foreign
513
+ * org's rows never enter): (1) terminal deploy rows PER (execution, env) — one
514
+ * "deployment" = one execution reaching an env (D1) DF / deploy-time CFR /
515
+ * measured lead time (lead time joins the execution's earliest commit, D2);
516
+ * the scan also reaches back `windowHours` before `from` so incidents opened
517
+ * near the window start can correlate to a just-prior deploy; (2) `deployment_outcomes`
518
+ * in-window → post-deploy CFR component; (3) production restored/failed
519
+ * outcomes joined to their deploy → MTTR; (4) registry vs deploying → coverage.
520
+ * The cross-source medians (lead time, MTTR) are computed in JS from clamped
521
+ * (≥0) deltas.
352
522
  *
353
523
  * @param opts.pipelineId restrict to one pipeline (per-pipeline DORA)
354
- * @param opts.environment count only executions deployed to this target
355
- * @param opts.deploysOnly count only executions tagged with ANY environment
524
+ * @param opts.environment restrict to one deploy environment
356
525
  */
357
526
  getDoraMetrics(orgId: string, from: string, to: string, orgIds?: string[], opts?: DoraOptions): Promise<DoraMetrics>;
358
- /** Shape a single DORA aggregate row into the public {@link DoraMetrics}. */
527
+ /**
528
+ * Shape the raw DORA scan rows into the public {@link DoraMetrics}. Buckets the
529
+ * terminal deploy rows by environment (DF / deploy-time CFR / measured lead),
530
+ * folds in the post-deploy failure counts (manual outcomes + webhook-ingested
531
+ * incidents, deduped by deploy execution), computes production MTTR from both
532
+ * sources (incident `resolved_at − opened_at` taking precedence over the manual
533
+ * `restored − deployed`), and reconciles coverage — all cross-source medians
534
+ * over deltas clamped ≥0.
535
+ *
536
+ * Phase 5 incident correlation: each incident is attributed to the most recent
537
+ * SUCCESSFUL deploy to its environment with `completed_at ≤ opened_at` within
538
+ * {@link DORA_INCIDENT_WINDOW_HOURS}. That deploy is a post-deploy failure; an
539
+ * uncorrelated incident (no eligible deploy) contributes nothing.
540
+ */
359
541
  private shapeDora;
360
542
  /**
361
- * 1.9b DORA trend — deployment frequency + change-failure rate bucketed by
362
- * `interval` (day/week/month) for a sparkline. Per-execution rollup (one row
363
- * per execution, FAILED wins) bucketed on the execution's started_at. Shares
364
- * the `getDoraMetrics` scoping (org/rollup, pipelineId, deploy-scoping); MTTR
365
- * and lead time are intentionally omitted (too heavy to bucket meaningfully).
543
+ * 1.9b DORA trend — deployment frequency + deploy-time change-failure rate
544
+ * bucketed by `interval` (day/week/month) for a sparkline. Deploy-basis like
545
+ * getDoraMetrics: buckets terminal deploy-stage executions on their
546
+ * `completed_at`. Shares the org/rollup + pipelineId/environment scoping. MTTR,
547
+ * lead time, and post-deploy CFR are intentionally omitted (too heavy to bucket).
366
548
  */
367
549
  getDoraTrend(orgId: string, interval: string, from: string, to: string, orgIds?: string[], opts?: DoraOptions): Promise<DoraTrendPoint[]>;
550
+ /**
551
+ * 1.10 Per-pipeline BUILD HEALTH (Phase 6) — a standard (NOT `advanced_reporting`)
552
+ * per-stage breakdown for one pipeline over a [from,to] window. Aggregates the
553
+ * existing `pipeline_events` STAGE rows: each stage is rolled up per execution
554
+ * to a terminal status (FAILED wins, then SUCCEEDED) + its max duration, then
555
+ * grouped per stage into run/success/failure counts, a success rate, and
556
+ * duration percentiles (p50/p90/p99). Totals sum across stages. Org-scoped via
557
+ * the pipeline join (`p.org_id ${pred}`) + rollup-aware like the sibling reports;
558
+ * a pipelineId owned by another org returns an empty breakdown.
559
+ */
560
+ getBuildHealth(orgId: string, pipelineId: string, from: string, to: string, orgIds?: string[]): Promise<BuildHealth>;
368
561
  /** 2.1 Plugin summary — counts and breakdowns.
369
562
  * INTENTIONALLY SINGLE-ORG (no rollup): plugin inventory is an org-owned
370
563
  * asset count, not an execution/build activity report, so a parent's view is
@@ -397,6 +590,94 @@ export declare class ReportingService {
397
590
  getBuildDuration(orgId: string, from: string, to: string, orgIds?: string[]): Promise<BuildDuration[]>;
398
591
  /** 2.6 Build failures — top error messages. Build activity report — rollup-aware. */
399
592
  getBuildFailures(orgId: string, from: string, to: string, limit?: number, orgIds?: string[]): Promise<BuildFailure[]>;
593
+ /**
594
+ * Record a manual post-deploy outcome marker (Phase 2): a user marks a
595
+ * deployment `failed` (a production incident linked to the deploy) or
596
+ * `restored` (recovered). Idempotent — keyed on (execution_id, outcome) so a
597
+ * duplicate POST refreshes `at` rather than double-counting, while a
598
+ * failed→restored pair stays two rows. Feeds the post-deploy CFR component and
599
+ * the real MTTR. Runs under the caller's org context (RLS WITH CHECK).
600
+ */
601
+ recordDeploymentOutcome(orgId: string, executionId: string, input: {
602
+ outcome: 'failed' | 'restored';
603
+ at: string;
604
+ environment?: string;
605
+ }): Promise<void>;
606
+ /**
607
+ * Ingest a production incident (Phase 5) from the org's incident tooling
608
+ * (PagerDuty / Datadog / Alertmanager webhook). Idempotent — keyed on
609
+ * (org_id, incident_id) so a later resolve re-post upserts `resolved_at`
610
+ * (and refreshes the other mutable fields) instead of inserting a duplicate.
611
+ * DORA correlates each incident to the most recent successful deploy to its
612
+ * `environment`, producing an automated post-deploy failure + a real MTTR.
613
+ * Runs under the caller's org context (RLS WITH CHECK); free-form fields are
614
+ * AWS-id scrubbed at this persistence boundary like the other ingest paths.
615
+ */
616
+ recordIncident(orgId: string, input: IncidentInput): Promise<void>;
617
+ /**
618
+ * Read the per-org DORA settings (Phase 5b). Returns the stored
619
+ * `incidentWindowHours` override (or `null` when unset) plus the global env
620
+ * default, so the settings UI can show both. Runs under the caller's tenant
621
+ * context (RLS-scoped); a single-org read.
622
+ */
623
+ getIncidentSettings(orgId: string): Promise<IncidentSettings>;
624
+ /**
625
+ * Upsert per-org reporting settings (Phase 5b incident window + Phase 7
626
+ * retention overrides), idempotent on `org_id`. A partial write — only the
627
+ * fields present in `patch` are set (so updating retention never clears the
628
+ * incident window, and vice-versa). Set self-serve by an org admin via
629
+ * `PUT /api/reports/settings/incidents`. Runs under the caller's org context
630
+ * (RLS WITH CHECK); a changed value affects DORA aggregates so the org's
631
+ * cached reports are dropped.
632
+ */
633
+ setReportingSettings(orgId: string, patch: ReportingSettingsPatch): Promise<void>;
634
+ /**
635
+ * List recent incidents for an org (Phase 5b org-admin surface), newest first,
636
+ * paginated. Each row carries its resolved state and its deploy correlation —
637
+ * the most recent SUCCESSFUL deploy to the incident's `environment` whose
638
+ * `completed_at` falls within the effective per-org correlation window before
639
+ * `opened_at` (the same rule DORA's CFR/MTTR correlation applies). Single-org
640
+ * (no rollup) — an org admin views their own org's incidents. RLS-scoped via
641
+ * the `p.org_id`/`i.org_id` predicates + the tenant context.
642
+ */
643
+ listIncidents(orgId: string, opts: {
644
+ limit: number;
645
+ offset: number;
646
+ }): Promise<IncidentListItem[]>;
647
+ /**
648
+ * Wiring-test dry-run (Phase 5b): would a synthetic incident opening NOW for
649
+ * `environment` correlate to a recent successful deploy under the org's
650
+ * effective window? This is a NON-persisting correlation check — it verifies
651
+ * the admin's environment naming + window line up with real deploy events
652
+ * WITHOUT writing an incident (so a "test" never pollutes CFR/MTTR). RLS-scoped.
653
+ */
654
+ testIncidentCorrelation(orgId: string, environment: string): Promise<IncidentTestResult>;
655
+ /**
656
+ * Upsert per-org ingestion health (Phase 3): the AWS events Lambda periodically
657
+ * reports forwarded/dropped counters + the last event timestamp so the Reports
658
+ * UI can show flowing / stale / dropping. One row per org (upsert on org_id).
659
+ */
660
+ recordIngestHealth(orgId: string, input: {
661
+ forwarded?: number;
662
+ dropped?: number;
663
+ lastEventAt?: string;
664
+ }): Promise<void>;
665
+ /**
666
+ * Reporting retention sweep (Phase 7). Hard-deletes rows older than their
667
+ * retention window, by `created_at`, across every org that has reporting data —
668
+ * a **split** policy so high-volume standard events expire faster than the
669
+ * low-volume DORA source:
670
+ * - `pipeline_events WHERE environment IS NULL` → standard-event window.
671
+ * - `pipeline_events WHERE environment IS NOT NULL` (deploy stages),
672
+ * `deployment_outcomes`, and `incidents` → DORA-source window.
673
+ * Each org's windows come from its `dora_settings` override, else the global
674
+ * env defaults (see {@link resolveEventRetentionDays} / {@link resolveDoraRetentionDays}).
675
+ * `ingest_health` and `dora_settings` are never purged. One `now` for the whole
676
+ * tick (rows crossing the boundary mid-sweep wait for the next). Establishes a
677
+ * sysadmin tenant scope so the deletes span all orgs / bypass RLS — this is a
678
+ * cross-tenant housekeeping job. Returns (and logs) per-window purge tallies.
679
+ */
680
+ purgeExpiredReportingData(opts?: ReportingRetentionOptions): Promise<ReportingRetentionCounts>;
400
681
  }
401
682
  export declare const reportingService: ReportingService;
402
683
  export {};