@pipeline-builder/pipeline-data 4.1.24 → 4.1.25

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.
Files changed (64) hide show
  1. package/lib/api/alert-destinations.d.ts +17 -0
  2. package/lib/api/alert-destinations.js +36 -0
  3. package/lib/api/reporting/analytics-queries.d.ts +274 -0
  4. package/lib/api/reporting/analytics-queries.js +598 -0
  5. package/lib/api/reporting/daily-rollup.d.ts +41 -0
  6. package/lib/api/reporting/daily-rollup.js +173 -0
  7. package/lib/api/reporting/deploy-rollup.d.ts +78 -0
  8. package/lib/api/reporting/deploy-rollup.js +203 -0
  9. package/lib/api/reporting/dora-scoring.d.ts +14 -0
  10. package/lib/api/reporting/dora-scoring.js +25 -1
  11. package/lib/api/reporting/dora.js +30 -6
  12. package/lib/api/reporting/failure-classifier.d.ts +54 -0
  13. package/lib/api/reporting/failure-classifier.js +179 -0
  14. package/lib/api/reporting/ingest.d.ts +2 -2
  15. package/lib/api/reporting/ingest.js +129 -4
  16. package/lib/api/reporting/last-deploy.d.ts +31 -0
  17. package/lib/api/reporting/last-deploy.js +93 -0
  18. package/lib/api/reporting/needs-attention.d.ts +93 -0
  19. package/lib/api/reporting/needs-attention.js +152 -0
  20. package/lib/api/reporting/plugin-exposure.d.ts +129 -0
  21. package/lib/api/reporting/plugin-exposure.js +312 -0
  22. package/lib/api/reporting/retention-sweep.js +9 -1
  23. package/lib/api/reporting/sql-helpers.d.ts +35 -2
  24. package/lib/api/reporting/sql-helpers.js +39 -1
  25. package/lib/api/reporting/stakeholder/compose.d.ts +115 -0
  26. package/lib/api/reporting/stakeholder/compose.js +234 -0
  27. package/lib/api/reporting/stakeholder/index.d.ts +14 -0
  28. package/lib/api/reporting/stakeholder/index.js +17 -0
  29. package/lib/api/reporting/stakeholder/period.d.ts +102 -0
  30. package/lib/api/reporting/stakeholder/period.js +273 -0
  31. package/lib/api/reporting/stakeholder/report-html.d.ts +93 -0
  32. package/lib/api/reporting/stakeholder/report-html.js +208 -0
  33. package/lib/api/reporting/stakeholder/sections.d.ts +117 -0
  34. package/lib/api/reporting/stakeholder/sections.js +249 -0
  35. package/lib/api/reporting/stakeholder/store.d.ts +450 -0
  36. package/lib/api/reporting/stakeholder/store.js +981 -0
  37. package/lib/api/reporting/stakeholder/templates.d.ts +21 -0
  38. package/lib/api/reporting/stakeholder/templates.js +104 -0
  39. package/lib/api/reporting/types.d.ts +73 -0
  40. package/lib/api/reporting/types.js +1 -1
  41. package/lib/api/reporting-service.d.ts +94 -5
  42. package/lib/api/reporting-service.js +169 -10
  43. package/lib/api/soft-delete-sweep.d.ts +11 -2
  44. package/lib/api/soft-delete-sweep.js +17 -6
  45. package/lib/database/drizzle-schema.d.ts +2263 -385
  46. package/lib/database/drizzle-schema.js +18 -7
  47. package/lib/database/index.d.ts +1 -1
  48. package/lib/database/index.js +4 -2
  49. package/lib/database/schema/compliance.d.ts +0 -682
  50. package/lib/database/schema/compliance.js +6 -66
  51. package/lib/database/schema/ecosystem.d.ts +20 -157
  52. package/lib/database/schema/ecosystem.js +23 -16
  53. package/lib/database/schema/pipeline.d.ts +200 -0
  54. package/lib/database/schema/pipeline.js +100 -1
  55. package/lib/database/schema/plugin.d.ts +20 -1
  56. package/lib/database/schema/plugin.js +13 -1
  57. package/lib/database/schema/reporting-analytics.d.ts +1212 -0
  58. package/lib/database/schema/reporting-analytics.js +250 -0
  59. package/lib/database/schema/reporting-stakeholder.d.ts +1405 -0
  60. package/lib/database/schema/reporting-stakeholder.js +251 -0
  61. package/lib/index.d.ts +10 -1
  62. package/lib/index.js +15 -1
  63. package/lib/testing/exports.json +67 -4
  64. package/package.json +4 -3
@@ -0,0 +1,17 @@
1
+ /** One destination, reduced to what a delivery needs. */
2
+ export interface NotificationDestination {
3
+ id: string;
4
+ /** `slack` | `webhook` | `email` | `in-app`. */
5
+ channel: string;
6
+ /** The URL or address. Bearer-equivalent for a webhook — never logged. */
7
+ target: string;
8
+ label: string;
9
+ }
10
+ /**
11
+ * Every ENABLED, undeleted destination for an org.
12
+ *
13
+ * Runs in the caller's ambient tenant context, so RLS is the tenancy gate — a caller
14
+ * without a context for this org reads nothing, which is the correct answer rather than
15
+ * an error.
16
+ */
17
+ export declare function listEnabledAlertDestinations(orgId: string): Promise<NotificationDestination[]>;
@@ -0,0 +1,36 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Reading an org's notification destinations.
5
+ *
6
+ * These rows are ADMIN-OWNED: an org's admins decided where this organization's
7
+ * notifications go, and everything that needs to notify an org reads the same list
8
+ * rather than growing its own copy. Platform owns the writes (create, update, test,
9
+ * delete) in its alert-destination service; this is the read, here so that a service
10
+ * with no Drizzle dependency of its own can use it.
11
+ *
12
+ * Whoever reads this list must not treat it as a URL they chose. A caller that let a
13
+ * user name the target would have reinvented an SSRF, which is exactly why the write
14
+ * side validates the channel/target pairing and the transport resolves-and-pins the host.
15
+ */
16
+ import { and, eq, isNull } from 'drizzle-orm';
17
+ import { schema } from '../database/drizzle-schema.js';
18
+ import { withTenantTx } from '../database/tenancy.js';
19
+ /**
20
+ * Every ENABLED, undeleted destination for an org.
21
+ *
22
+ * Runs in the caller's ambient tenant context, so RLS is the tenancy gate — a caller
23
+ * without a context for this org reads nothing, which is the correct answer rather than
24
+ * an error.
25
+ */
26
+ export async function listEnabledAlertDestinations(orgId) {
27
+ const rows = await withTenantTx((tx) => tx.select({
28
+ id: schema.orgAlertDestination.id,
29
+ channel: schema.orgAlertDestination.channel,
30
+ target: schema.orgAlertDestination.target,
31
+ label: schema.orgAlertDestination.label,
32
+ }).from(schema.orgAlertDestination)
33
+ .where(and(eq(schema.orgAlertDestination.orgId, orgId), eq(schema.orgAlertDestination.enabled, true), isNull(schema.orgAlertDestination.deletedAt))));
34
+ return rows;
35
+ }
36
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxlcnQtZGVzdGluYXRpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9hbGVydC1kZXN0aW5hdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7Ozs7Ozs7O0dBWUc7QUFFSCxPQUFPLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDOUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQVl0RDs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLDRCQUE0QixDQUFDLEtBQWE7SUFDOUQsTUFBTSxJQUFJLEdBQUcsTUFBTSxZQUFZLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUM7UUFDaEQsRUFBRSxFQUFFLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFO1FBQ2pDLE9BQU8sRUFBRSxNQUFNLENBQUMsbUJBQW1CLENBQUMsT0FBTztRQUMzQyxNQUFNLEVBQUUsTUFBTSxDQUFDLG1CQUFtQixDQUFDLE1BQU07UUFDekMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLO0tBQ3hDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUFDO1NBQ2hDLEtBQUssQ0FBQyxHQUFHLENBQ1IsRUFBRSxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLEVBQzNDLEVBQUUsQ0FBQyxNQUFNLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUM1QyxNQUFNLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUFDLFNBQVMsQ0FBQyxDQUM3QyxDQUFDLENBQUMsQ0FBQztJQUNOLE9BQU8sSUFBaUMsQ0FBQztBQUMzQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogUmVhZGluZyBhbiBvcmcncyBub3RpZmljYXRpb24gZGVzdGluYXRpb25zLlxuICpcbiAqIFRoZXNlIHJvd3MgYXJlIEFETUlOLU9XTkVEOiBhbiBvcmcncyBhZG1pbnMgZGVjaWRlZCB3aGVyZSB0aGlzIG9yZ2FuaXphdGlvbidzXG4gKiBub3RpZmljYXRpb25zIGdvLCBhbmQgZXZlcnl0aGluZyB0aGF0IG5lZWRzIHRvIG5vdGlmeSBhbiBvcmcgcmVhZHMgdGhlIHNhbWUgbGlzdFxuICogcmF0aGVyIHRoYW4gZ3Jvd2luZyBpdHMgb3duIGNvcHkuIFBsYXRmb3JtIG93bnMgdGhlIHdyaXRlcyAoY3JlYXRlLCB1cGRhdGUsIHRlc3QsXG4gKiBkZWxldGUpIGluIGl0cyBhbGVydC1kZXN0aW5hdGlvbiBzZXJ2aWNlOyB0aGlzIGlzIHRoZSByZWFkLCBoZXJlIHNvIHRoYXQgYSBzZXJ2aWNlXG4gKiB3aXRoIG5vIERyaXp6bGUgZGVwZW5kZW5jeSBvZiBpdHMgb3duIGNhbiB1c2UgaXQuXG4gKlxuICogV2hvZXZlciByZWFkcyB0aGlzIGxpc3QgbXVzdCBub3QgdHJlYXQgaXQgYXMgYSBVUkwgdGhleSBjaG9zZS4gQSBjYWxsZXIgdGhhdCBsZXQgYVxuICogdXNlciBuYW1lIHRoZSB0YXJnZXQgd291bGQgaGF2ZSByZWludmVudGVkIGFuIFNTUkYsIHdoaWNoIGlzIGV4YWN0bHkgd2h5IHRoZSB3cml0ZVxuICogc2lkZSB2YWxpZGF0ZXMgdGhlIGNoYW5uZWwvdGFyZ2V0IHBhaXJpbmcgYW5kIHRoZSB0cmFuc3BvcnQgcmVzb2x2ZXMtYW5kLXBpbnMgdGhlIGhvc3QuXG4gKi9cblxuaW1wb3J0IHsgYW5kLCBlcSwgaXNOdWxsIH0gZnJvbSAnZHJpenpsZS1vcm0nO1xuaW1wb3J0IHsgc2NoZW1hIH0gZnJvbSAnLi4vZGF0YWJhc2UvZHJpenpsZS1zY2hlbWEuanMnO1xuaW1wb3J0IHsgd2l0aFRlbmFudFR4IH0gZnJvbSAnLi4vZGF0YWJhc2UvdGVuYW5jeS5qcyc7XG5cbi8qKiBPbmUgZGVzdGluYXRpb24sIHJlZHVjZWQgdG8gd2hhdCBhIGRlbGl2ZXJ5IG5lZWRzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBOb3RpZmljYXRpb25EZXN0aW5hdGlvbiB7XG4gIGlkOiBzdHJpbmc7XG4gIC8qKiBgc2xhY2tgIHwgYHdlYmhvb2tgIHwgYGVtYWlsYCB8IGBpbi1hcHBgLiAqL1xuICBjaGFubmVsOiBzdHJpbmc7XG4gIC8qKiBUaGUgVVJMIG9yIGFkZHJlc3MuIEJlYXJlci1lcXVpdmFsZW50IGZvciBhIHdlYmhvb2sg4oCUIG5ldmVyIGxvZ2dlZC4gKi9cbiAgdGFyZ2V0OiBzdHJpbmc7XG4gIGxhYmVsOiBzdHJpbmc7XG59XG5cbi8qKlxuICogRXZlcnkgRU5BQkxFRCwgdW5kZWxldGVkIGRlc3RpbmF0aW9uIGZvciBhbiBvcmcuXG4gKlxuICogUnVucyBpbiB0aGUgY2FsbGVyJ3MgYW1iaWVudCB0ZW5hbnQgY29udGV4dCwgc28gUkxTIGlzIHRoZSB0ZW5hbmN5IGdhdGUg4oCUIGEgY2FsbGVyXG4gKiB3aXRob3V0IGEgY29udGV4dCBmb3IgdGhpcyBvcmcgcmVhZHMgbm90aGluZywgd2hpY2ggaXMgdGhlIGNvcnJlY3QgYW5zd2VyIHJhdGhlciB0aGFuXG4gKiBhbiBlcnJvci5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxpc3RFbmFibGVkQWxlcnREZXN0aW5hdGlvbnMob3JnSWQ6IHN0cmluZyk6IFByb21pc2U8Tm90aWZpY2F0aW9uRGVzdGluYXRpb25bXT4ge1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHguc2VsZWN0KHtcbiAgICBpZDogc2NoZW1hLm9yZ0FsZXJ0RGVzdGluYXRpb24uaWQsXG4gICAgY2hhbm5lbDogc2NoZW1hLm9yZ0FsZXJ0RGVzdGluYXRpb24uY2hhbm5lbCxcbiAgICB0YXJnZXQ6IHNjaGVtYS5vcmdBbGVydERlc3RpbmF0aW9uLnRhcmdldCxcbiAgICBsYWJlbDogc2NoZW1hLm9yZ0FsZXJ0RGVzdGluYXRpb24ubGFiZWwsXG4gIH0pLmZyb20oc2NoZW1hLm9yZ0FsZXJ0RGVzdGluYXRpb24pXG4gICAgLndoZXJlKGFuZChcbiAgICAgIGVxKHNjaGVtYS5vcmdBbGVydERlc3RpbmF0aW9uLm9yZ0lkLCBvcmdJZCksXG4gICAgICBlcShzY2hlbWEub3JnQWxlcnREZXN0aW5hdGlvbi5lbmFibGVkLCB0cnVlKSxcbiAgICAgIGlzTnVsbChzY2hlbWEub3JnQWxlcnREZXN0aW5hdGlvbi5kZWxldGVkQXQpLFxuICAgICkpKTtcbiAgcmV0dXJuIHJvd3MgYXMgTm90aWZpY2F0aW9uRGVzdGluYXRpb25bXTtcbn1cbiJdfQ==
@@ -0,0 +1,274 @@
1
+ import type { FailureCategory } from '../../database/schema/reporting-analytics.js';
2
+ /** The window and org scope every query takes. */
3
+ export interface AnalyticsScope {
4
+ orgId: string;
5
+ /** `[self, ...descendants]` for a rollup; undefined = this org only. */
6
+ orgIds?: string[];
7
+ from: string;
8
+ to: string;
9
+ }
10
+ /** One pipeline's line in the breakdown. */
11
+ export interface PipelineBreakdownRow {
12
+ pipelineId: string;
13
+ pipelineName: string | null;
14
+ project: string | null;
15
+ runs: number;
16
+ succeeded: number;
17
+ failed: number;
18
+ successPct: number | null;
19
+ p95Ms: number | null;
20
+ deploys: number;
21
+ /** The most recent failure's day and stage, for "what to look at first". */
22
+ lastFailureAt: string | null;
23
+ lastFailureStage: string | null;
24
+ buildSeconds: number;
25
+ }
26
+ /**
27
+ * Per-pipeline delivery, worst first.
28
+ *
29
+ * WORST FIRST, and capped, because the point of the section is "where should
30
+ * attention go". A list sorted by name, or an unbounded one, is a data dump: the
31
+ * lead still has to find the problem, which is the work the report was supposed to
32
+ * do. Ties break on volume, so a 50%-success pipeline that ran twice does not
33
+ * outrank one that ran two hundred times.
34
+ *
35
+ * `successPct` is NULL for a pipeline with no runs in the window — not 0. A
36
+ * pipeline nobody ran is not a pipeline that failed.
37
+ */
38
+ export declare function getPipelineBreakdown(scope: AnalyticsScope, limit?: number): Promise<PipelineBreakdownRow[]>;
39
+ /** One failure category's share of the period. */
40
+ export interface FailureCategoryRow {
41
+ category: FailureCategory;
42
+ label: string;
43
+ count: number;
44
+ sharePct: number;
45
+ /** Whether the team can act on it, or it happened to them. */
46
+ teamActionable: boolean;
47
+ /** Change vs the previous period, in failures. */
48
+ change: number | null;
49
+ /** The pipelines it hit hardest. */
50
+ topPipelines: Array<{
51
+ pipelineId: string;
52
+ pipelineName: string | null;
53
+ count: number;
54
+ }>;
55
+ }
56
+ /**
57
+ * Failures by category, with the previous period's counts for the trend.
58
+ *
59
+ * SPLITS ACTIONABLE FROM NOT. A week whose failures were all cloud throttling is a
60
+ * different conversation from one whose failures were all broken tests, and
61
+ * presenting them in one ranked list invites exactly the wrong conclusion — a team
62
+ * being asked to fix an AWS capacity problem.
63
+ */
64
+ export declare function getFailureAnalysis(scope: AnalyticsScope, previous?: {
65
+ from: string;
66
+ to: string;
67
+ }): Promise<{
68
+ categories: FailureCategoryRow[];
69
+ total: number;
70
+ actionableTotal: number;
71
+ }>;
72
+ /** One stage's timing, for the drill-down. */
73
+ export interface StagePerformanceRow {
74
+ stageName: string;
75
+ runs: number;
76
+ p50Ms: number | null;
77
+ p95Ms: number | null;
78
+ /** Change in p95 vs the previous period, as a percentage. */
79
+ p95ChangePct: number | null;
80
+ failed: number;
81
+ }
82
+ /**
83
+ * Per-stage timings for one pipeline, slowest first.
84
+ *
85
+ * The section a lead opens after the breakdown says a pipeline got slower: "which
86
+ * stage" is the next question, and answering it from raw events would mean a
87
+ * second scan of the same window.
88
+ */
89
+ export declare function getStagePerformance(scope: AnalyticsScope, pipelineId: string, previous?: {
90
+ from: string;
91
+ to: string;
92
+ }): Promise<StagePerformanceRow[]>;
93
+ /** Build time by project and pipeline. No money anywhere. */
94
+ export interface ResourceRow {
95
+ project: string | null;
96
+ pipelineId: string;
97
+ pipelineName: string | null;
98
+ buildSeconds: number;
99
+ runs: number;
100
+ sharePct: number;
101
+ }
102
+ /**
103
+ * Where the build time went.
104
+ *
105
+ * SECONDS, NOT DOLLARS. A cost figure needs the instance types, the spot/on-demand
106
+ * mix and the account's own discounts, none of which this platform knows — so a
107
+ * dollar number here would be a guess presented as an invoice. Build time is the
108
+ * thing actually measured.
109
+ */
110
+ export declare function getResourceConsumption(scope: AnalyticsScope, limit?: number): Promise<{
111
+ pipelines: ResourceRow[];
112
+ totalBuildSeconds: number;
113
+ }>;
114
+ /** One commit's journey across environments. */
115
+ export interface PromotionRow {
116
+ commitSha: string;
117
+ /** Environment → when it landed there, in the order it reached them. */
118
+ stops: Array<{
119
+ environment: string;
120
+ deployedAt: string;
121
+ hoursFromPrevious: number | null;
122
+ }>;
123
+ /** True when the commit reached a non-production environment and stopped. */
124
+ stuck: boolean;
125
+ furthest: string;
126
+ }
127
+ /**
128
+ * Where commits got to, and where they stopped.
129
+ *
130
+ * "Stuck" is the number worth reading. A commit that reached staging four days ago
131
+ * and never went further is work that is finished and not delivered — which does
132
+ * not appear in deployment frequency, success rate or lead time, because by every
133
+ * one of those measures nothing happened.
134
+ */
135
+ export declare function getPromotionView(scope: AnalyticsScope, productionEnv?: string, limit?: number): Promise<{
136
+ commits: PromotionRow[];
137
+ stuckCount: number;
138
+ }>;
139
+ /** Outdated plugin usage, per pipeline and step. */
140
+ export interface OutdatedPluginRow {
141
+ pipelineId: string;
142
+ pipelineName: string | null;
143
+ stageName: string;
144
+ stepName: string;
145
+ plugin: string;
146
+ inUse: string | null;
147
+ latest: string | null;
148
+ gap: string | null;
149
+ withinPolicy: boolean;
150
+ }
151
+ /**
152
+ * Which pipelines are behind on a plugin, worst gap first.
153
+ *
154
+ * Reads the DECLARED side (`pipeline_plugin_resolution`). A pipeline's declared
155
+ * range and what it last actually ran can disagree — which is why the vulnerability
156
+ * section below reads the deployed side and says which it is showing.
157
+ */
158
+ export declare function getOutdatedPlugins(scope: AnalyticsScope, limit?: number): Promise<{
159
+ rows: OutdatedPluginRow[];
160
+ behindPipelines: number;
161
+ majorBehind: number;
162
+ }>;
163
+ /** A pipeline's exposure to a vulnerable plugin version. */
164
+ export interface VulnerabilityRow {
165
+ pipelineId: string;
166
+ pipelineName: string | null;
167
+ plugin: string;
168
+ version: string;
169
+ /** `deployed` = what actually ran; `declared` = what the config asks for. */
170
+ source: string;
171
+ critical: number;
172
+ high: number;
173
+ findings: Array<Record<string, unknown>>;
174
+ flaggedAt: string;
175
+ }
176
+ /**
177
+ * Plugin vulnerabilities, per pipeline, Criticals first.
178
+ *
179
+ * SAYS WHETHER IT IS DECLARED OR DEPLOYED. A pipeline whose config was updated to a
180
+ * fixed version but which has not re-synthed is still running the vulnerable image,
181
+ * and a report that collapsed the two would tell a manager the problem is solved
182
+ * while the old image keeps running.
183
+ */
184
+ export declare function getPluginVulnerabilities(scope: AnalyticsScope, limit?: number): Promise<{
185
+ rows: VulnerabilityRow[];
186
+ exposedPipelines: number;
187
+ criticalPipelines: number;
188
+ }>;
189
+ /** Adoption and deploy-tracking coverage within the reported scope. */
190
+ export interface AdoptionSummary {
191
+ activePipelines: number;
192
+ totalPipelines: number;
193
+ /** Pipelines that produced a deploy row — i.e. ones DORA can see. */
194
+ deployTrackedPipelines: number;
195
+ /** By `creation_source`, for "are the golden paths being used". */
196
+ bySource: Record<string, number>;
197
+ /** Teams in the rollup that had activity. 1 for a single-org report. */
198
+ activeTeams: number;
199
+ /** Only when the org configured the assumption. Never platform-supplied. */
200
+ estimatedMinutesSaved: number | null;
201
+ }
202
+ /**
203
+ * Adoption, coverage and creation source.
204
+ *
205
+ * `deployTrackedPipelines` is the honest denominator for everything DORA says: a
206
+ * pipeline that has not re-synthed with deploy tags produces no deploy rows, so it
207
+ * is invisible to deployment frequency — and reporting "4 deploys" without saying
208
+ * that 20 of 30 pipelines cannot be seen is the single most misleading thing this
209
+ * feature could do.
210
+ */
211
+ export declare function getAdoption(scope: AnalyticsScope, timeSavedMinutes?: number | null): Promise<AdoptionSummary>;
212
+ /** One pipeline's failure streak and last successful day. */
213
+ export interface PipelineStreakRow {
214
+ pipelineId: string;
215
+ /**
216
+ * Failures in the trailing run of days on which NOTHING succeeded.
217
+ *
218
+ * A LOWER BOUND, and deliberately so. The rollup is per day, so within the most
219
+ * recent day that did have a success there is no way to tell whether the failures
220
+ * came before or after it — that day is excluded rather than guessed at. What
221
+ * survives is a run of failures with no success anywhere between them, which is
222
+ * exactly the claim the finding makes.
223
+ */
224
+ consecutiveFailures: number;
225
+ /** The last day with at least one success, or null within the lookback. */
226
+ lastSuccessAt: Date | null;
227
+ }
228
+ /**
229
+ * Failure streaks and last-success dates, for the needs-attention rules.
230
+ *
231
+ * Reads the daily rollup, not `pipeline_events` — the same reason as everything
232
+ * else here: a streak that ended three weeks ago must still be readable after
233
+ * retention has swept the events that produced it.
234
+ *
235
+ * `lookbackDays` extends PAST the window on purpose. "Last succeeded 12 days ago"
236
+ * is the finding a weekly report most needs, and a query bounded by a 7-day window
237
+ * could never produce it.
238
+ */
239
+ export declare function getPipelineStreaks(scope: AnalyticsScope, lookbackDays?: number): Promise<PipelineStreakRow[]>;
240
+ /**
241
+ * Pipelines that RAN in the window but produced no deploy rows.
242
+ *
243
+ * A measurement gap, not a failure, and the reason a deployment-frequency number can
244
+ * be quietly wrong: a pipeline whose synth predates the `pb.deploys` tags deploys
245
+ * perfectly well and is invisible to every DORA aggregate. Nothing else in the
246
+ * report would say so.
247
+ */
248
+ export declare function getUntrackedPipelines(scope: AnalyticsScope): Promise<string[]>;
249
+ /**
250
+ * Pipelines running a plugin version with an OPEN Critical exposure.
251
+ *
252
+ * Point-in-time, not windowed: what matters is whether the pipeline is running one
253
+ * NOW. A Critical that was open last Tuesday and is fixed today is not something to
254
+ * put in front of a manager, and `fixed_at` is what says so.
255
+ *
256
+ * An ACCEPTED exposure is excluded. Someone with the authority to accept a risk has
257
+ * already decided about it in writing, with a reason and a deadline; re-raising it
258
+ * weekly is how a report teaches its reader to skip a section. The lapse of that
259
+ * acceptance is a separate finding (`lapsedAcceptances`).
260
+ */
261
+ export declare function getVulnerablePipelines(scope: AnalyticsScope): Promise<string[]>;
262
+ /**
263
+ * When each pipeline in the window was last changed.
264
+ *
265
+ * `pipelines.updated_at`, not an audit query: the audit trail lives in another store
266
+ * with its own retention, and the one fact this needs — "was this touched shortly
267
+ * before it broke" — is already on the row, durably, in the same transaction the
268
+ * change was made in.
269
+ *
270
+ * The consequence is stated rather than hidden: `updated_at` moves for ANY write,
271
+ * including a rename. So the finding says "after a configuration change", which is
272
+ * true of a rename too, and does not claim to name the change.
273
+ */
274
+ export declare function getPipelineConfigChanges(scope: AnalyticsScope): Promise<Map<string, Date>>;