@derwinjs/db 0.5.0 → 0.7.0
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.
- package/dist/drift-detector.d.ts +63 -0
- package/dist/drift-detector.d.ts.map +1 -0
- package/dist/drift-detector.js +0 -0
- package/dist/drift-detector.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/rag-retriever.d.ts.map +1 -1
- package/dist/rag-retriever.js +38 -0
- package/dist/rag-retriever.js.map +1 -1
- package/dist/regression-detector.d.ts +45 -0
- package/dist/regression-detector.d.ts.map +1 -0
- package/dist/regression-detector.js +78 -0
- package/dist/regression-detector.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default DriftDetector — QAP-Sprint7 Phase 6 / QAP-077.
|
|
3
|
+
*
|
|
4
|
+
* Stock implementation of the SDK DriftDetector contract
|
|
5
|
+
* (packages/sdk/src/types/drift-detector.ts). Compares per-(classification,
|
|
6
|
+
* surface) success rates over a recent CURRENT window against a longer
|
|
7
|
+
* BASELINE window (the period immediately preceding the current window) and
|
|
8
|
+
* emits a DriftAlarm[] for tuples whose current rate is materially worse
|
|
9
|
+
* than baseline.
|
|
10
|
+
*
|
|
11
|
+
* Window semantics:
|
|
12
|
+
* t0 = now
|
|
13
|
+
* currentStart = t0 - currentWindowDays
|
|
14
|
+
* baselineStart = currentStart - baselineWindowDays
|
|
15
|
+
*
|
|
16
|
+
* currentWindow = [currentStart, t0)
|
|
17
|
+
* baselineWindow = [baselineStart, currentStart)
|
|
18
|
+
*
|
|
19
|
+
* The two windows are NON-overlapping by construction so an attempt counts in
|
|
20
|
+
* exactly one window; the comparison is genuinely "recent vs prior" rather
|
|
21
|
+
* than "recent vs trailing-30-day-including-this-week".
|
|
22
|
+
*
|
|
23
|
+
* Sample selection mirrors LearningHealthReporter (Sprint 2 Group D-3):
|
|
24
|
+
* - dispatchStatus IN ('AUTO_MERGED', 'HUMAN_MERGED') — Lifeline's MERGED
|
|
25
|
+
* under Option β
|
|
26
|
+
* - mergedAt within the window
|
|
27
|
+
* - fixSuccessScore not null — only attempts that have been scored count
|
|
28
|
+
* toward the success rate; pending-outcome attempts are excluded from
|
|
29
|
+
* both numerator and denominator (otherwise a brand-new merge with no
|
|
30
|
+
* score yet would be miscounted as a failure).
|
|
31
|
+
*
|
|
32
|
+
* Success classification:
|
|
33
|
+
* fixSuccessScore > 0 → success (Layer F scoring tiers: +0.2 / +0.5 / +1.0)
|
|
34
|
+
* fixSuccessScore <= 0 → failure (-1.0 / -0.5 / 0.0)
|
|
35
|
+
*
|
|
36
|
+
* classification + surface live on QATicket, not QAFixAttempt, so the query
|
|
37
|
+
* pulls them via the `ticket` relation in a single findMany then aggregates
|
|
38
|
+
* in-memory. For Sprint 7 cron usage this is fine (tens to low-hundreds of
|
|
39
|
+
* MERGED attempts per project per 37-day span); a future scale-out could
|
|
40
|
+
* push the grouping into a raw SQL aggregate over the join.
|
|
41
|
+
*
|
|
42
|
+
* Failure semantics: throws DriftDetectorError('invalid_input') on malformed
|
|
43
|
+
* input (negative window, empty projectId). Empty projects return [].
|
|
44
|
+
*
|
|
45
|
+
* Tenant isolation: projectId flows directly into the Prisma `where` clause,
|
|
46
|
+
* matching the rest of Layer F.
|
|
47
|
+
*/
|
|
48
|
+
import type { PrismaClient } from './prisma.js';
|
|
49
|
+
import { type DriftDetector } from '@derwinjs/sdk';
|
|
50
|
+
export interface PrismaDriftDetectorConfig {
|
|
51
|
+
/** Generated Prisma client. Pass an instance per process. */
|
|
52
|
+
prisma: PrismaClient;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Build a DriftDetector backed by Prisma over QAFixAttempt + QATicket.
|
|
56
|
+
*
|
|
57
|
+
* The returned `scan` is intended to be invoked from a periodic job
|
|
58
|
+
* (mirroring OutcomeRecorder + TrustScoreUpdater from QAP-075). Sprint 8
|
|
59
|
+
* may expose `GET /qa/drift-alarms` if operator-facing UI needs it; the
|
|
60
|
+
* scan itself stays cron-callable independent of an HTTP route.
|
|
61
|
+
*/
|
|
62
|
+
export declare function createPrismaDriftDetector(config: PrismaDriftDetectorConfig): DriftDetector;
|
|
63
|
+
//# sourceMappingURL=drift-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift-detector.d.ts","sourceRoot":"","sources":["../src/drift-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,yBAAyB;IACxC,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AAYD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,yBAAyB,GAAG,aAAa,CA6G1F"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift-detector.js","sourceRoot":"","sources":["../src/drift-detector.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -23,5 +23,7 @@ export { createPrismaQAUniformityStore, type PrismaQAUniformityStoreConfig, } fr
|
|
|
23
23
|
export { createPrismaAgentFindingsIngestor, type PrismaAgentFindingsIngestorConfig, } from './agent-findings-ingestor.js';
|
|
24
24
|
export { createPrismaLearningHealthReporter, type PrismaLearningHealthReporterConfig, } from './learning-health-reporter.js';
|
|
25
25
|
export { createPrismaCoverageGapReporter, type PrismaCoverageGapReporterConfig, } from './coverage-gap-reporter.js';
|
|
26
|
+
export { createPrismaRegressionDetector, type PrismaRegressionDetectorConfig, } from './regression-detector.js';
|
|
27
|
+
export { createPrismaDriftDetector, type PrismaDriftDetectorConfig } from './drift-detector.js';
|
|
26
28
|
export * from './prisma.js';
|
|
27
29
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,eAAO,MAAM,YAAY,EAAG,cAAuB,CAAC;AAIpD,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,EAC7B,KAAK,6BAA6B,GACnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,0BAA0B,EAAE,KAAK,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,EAC7B,KAAK,6BAA6B,GACnC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iCAAiC,EACjC,KAAK,iCAAiC,GACvC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,kCAAkC,EAClC,KAAK,kCAAkC,GACxC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,EAC/B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,eAAO,MAAM,YAAY,EAAG,cAAuB,CAAC;AAIpD,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,EAC7B,KAAK,6BAA6B,GACnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,0BAA0B,EAAE,KAAK,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,EAC7B,KAAK,6BAA6B,GACnC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iCAAiC,EACjC,KAAK,iCAAiC,GACvC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,kCAAkC,EAClC,KAAK,kCAAkC,GACxC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,EAC/B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,8BAA8B,EAC9B,KAAK,8BAA8B,GACpC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AA4BhG,cAAc,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,8 @@ export { createPrismaQAUniformityStore, } from './qa-uniformity-store.js';
|
|
|
24
24
|
export { createPrismaAgentFindingsIngestor, } from './agent-findings-ingestor.js';
|
|
25
25
|
export { createPrismaLearningHealthReporter, } from './learning-health-reporter.js';
|
|
26
26
|
export { createPrismaCoverageGapReporter, } from './coverage-gap-reporter.js';
|
|
27
|
+
export { createPrismaRegressionDetector, } from './regression-detector.js';
|
|
28
|
+
export { createPrismaDriftDetector } from './drift-detector.js';
|
|
27
29
|
// ─── Prisma client re-export ─────────────────────────────────────────────
|
|
28
30
|
//
|
|
29
31
|
// @derwinjs/db ships its OWN generated Prisma client (output: prisma-client/
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,cAAuB,CAAC;AAEpD,4EAA4E;AAE5E,OAAO,EAAE,yBAAyB,EAAkC,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,GAE9B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAA+B,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,0BAA0B,EAAmC,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAE,yBAAyB,EAAkC,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,GAE9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iCAAiC,GAElC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,kCAAkC,GAEnC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,GAEhC,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,cAAuB,CAAC;AAEpD,4EAA4E;AAE5E,OAAO,EAAE,yBAAyB,EAAkC,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,GAE9B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAA+B,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,0BAA0B,EAAmC,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAE,yBAAyB,EAAkC,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,GAE9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iCAAiC,GAElC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,kCAAkC,GAEnC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,GAEhC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,8BAA8B,GAE/B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAkC,MAAM,qBAAqB,CAAC;AAEhG,4EAA4E;AAC5E,EAAE;AACF,6EAA6E;AAC7E,wEAAwE;AACxE,sEAAsE;AACtE,wEAAwE;AACxE,wEAAwE;AACxE,gDAAgD;AAChD,EAAE;AACF,+DAA+D;AAC/D,0EAA0E;AAC1E,yCAAyC;AACzC,+EAA+E;AAC/E,yCAAyC;AACzC,uEAAuE;AACvE,sEAAsE;AACtE,kEAAkE;AAClE,+BAA+B;AAC/B,EAAE;AACF,oBAAoB;AACpB,8DAA8D;AAC9D,4CAA4C;AAC5C,qEAAqE;AACrE,QAAQ;AACR,gDAAgD;AAEhD,cAAc,aAAa,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rag-retriever.d.ts","sourceRoot":"","sources":["../src/rag-retriever.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAGL,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"rag-retriever.d.ts","sourceRoot":"","sources":["../src/rag-retriever.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAGL,KAAK,YAAY,EAIlB,MAAM,eAAe,CAAC;AASvB,MAAM,WAAW,wBAAwB;IACvC,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AAiBD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,wBAAwB,GAAG,YAAY,CAmIvF"}
|
package/dist/rag-retriever.js
CHANGED
|
@@ -122,6 +122,30 @@ export function createPrismaRAGRetriever(config) {
|
|
|
122
122
|
}
|
|
123
123
|
return { id };
|
|
124
124
|
},
|
|
125
|
+
async updateOutcomeQuality(input) {
|
|
126
|
+
validateUpdateOutcomeQualityInput(input);
|
|
127
|
+
// Pattern D — tenant isolation. The WHERE clause scopes by both
|
|
128
|
+
// projectId AND fixAttemptId so a Sprint 7 Phase 5 update cannot
|
|
129
|
+
// bleed across tenants even if the caller mis-routes a fixAttemptId.
|
|
130
|
+
// Cross-tenant or missing-row → updateMany returns count=0; surface
|
|
131
|
+
// that as `{ updated: 0 }` per the contract (no throw).
|
|
132
|
+
//
|
|
133
|
+
// We deliberately use the typed `updateMany` (not raw SQL) because:
|
|
134
|
+
// (a) the `embedding` column is Unsupported but we're not touching
|
|
135
|
+
// it — we only set `outcomeQuality` (Float, fully typed); and
|
|
136
|
+
// (b) `updateMany` returns the affected-row count, which we need to
|
|
137
|
+
// hand back to the orchestrator for the audit trail.
|
|
138
|
+
const result = await prisma.rAGCorpus.updateMany({
|
|
139
|
+
where: {
|
|
140
|
+
projectId: input.projectId,
|
|
141
|
+
fixAttemptId: input.fixAttemptId,
|
|
142
|
+
},
|
|
143
|
+
data: {
|
|
144
|
+
outcomeQuality: input.outcomeQuality,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
return { updated: result.count };
|
|
148
|
+
},
|
|
125
149
|
};
|
|
126
150
|
}
|
|
127
151
|
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
@@ -147,6 +171,20 @@ function validateFindSimilarInput(input) {
|
|
|
147
171
|
throw new RAGRetrieverError('invalid_embedding_length', `queryEmbedding must be ${String(EMBEDDING_DIM)}-dim, got ${actual}`);
|
|
148
172
|
}
|
|
149
173
|
}
|
|
174
|
+
function validateUpdateOutcomeQualityInput(input) {
|
|
175
|
+
if (typeof input.projectId !== 'string' || !input.projectId.trim()) {
|
|
176
|
+
throw new RAGRetrieverError('invalid_input', 'projectId is required');
|
|
177
|
+
}
|
|
178
|
+
if (typeof input.fixAttemptId !== 'string' || !input.fixAttemptId.trim()) {
|
|
179
|
+
throw new RAGRetrieverError('invalid_input', 'fixAttemptId is required');
|
|
180
|
+
}
|
|
181
|
+
if (typeof input.outcomeQuality !== 'number' ||
|
|
182
|
+
Number.isNaN(input.outcomeQuality) ||
|
|
183
|
+
input.outcomeQuality < 0 ||
|
|
184
|
+
input.outcomeQuality > 1) {
|
|
185
|
+
throw new RAGRetrieverError('invalid_input', 'outcomeQuality must be in [0, 1]');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
150
188
|
function validatePersistInput(input) {
|
|
151
189
|
if (typeof input.projectId !== 'string' || !input.projectId.trim()) {
|
|
152
190
|
throw new RAGRetrieverError('invalid_input', 'projectId is required');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rag-retriever.js","sourceRoot":"","sources":["../src/rag-retriever.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,aAAa,CAAC;AACxD,OAAO,EACL,iBAAiB,
|
|
1
|
+
{"version":3,"file":"rag-retriever.js","sourceRoot":"","sources":["../src/rag-retriever.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default RegressionDetector — QAP-Sprint7 Phase 3 / QAP-071.
|
|
3
|
+
*
|
|
4
|
+
* Stock implementation of the SDK RegressionDetector callback type
|
|
5
|
+
* (packages/sdk/src/types/regression-detector.ts). Wires `QATicketStore.listQATickets`
|
|
6
|
+
* with (classification, surface, ageHours, status) filters to find newly-opened
|
|
7
|
+
* tickets matching the original ticket's classification + surface within
|
|
8
|
+
* `withinDays` of `sinceMergedAt`. Returns true iff at least one such ticket
|
|
9
|
+
* exists (excluding the original ticket itself).
|
|
10
|
+
*
|
|
11
|
+
* Why a callback factory in @derwinjs/db rather than a stateful adapter:
|
|
12
|
+
* The RegressionDetector contract is intentionally a function type — not
|
|
13
|
+
* every consumer reads QA tickets to decide regression. A telemetry-driven
|
|
14
|
+
* Datadog/OpenTelemetry impl would query metrics instead. This file provides
|
|
15
|
+
* the *default* QATicketStore-backed callback that runPostVerify wires when
|
|
16
|
+
* the consumer opts into Derwin's standard regression-detection rule.
|
|
17
|
+
*
|
|
18
|
+
* Tenant isolation: the projectId argument from the callback flows directly
|
|
19
|
+
* into ticketStore.getQATicket and ticketStore.listQATickets, both of which
|
|
20
|
+
* are tenant-scoped per QAP-018B. No cross-project leakage is possible at
|
|
21
|
+
* this layer.
|
|
22
|
+
*
|
|
23
|
+
* Failure semantics: the callback never throws. Defense-in-depth — if the
|
|
24
|
+
* original ticket cannot be resolved (missing or cross-tenant), return false
|
|
25
|
+
* (no original means no regression context). This mirrors the orchestrator's
|
|
26
|
+
* "regression detection MUST NOT abort the post-verify path" rule. The
|
|
27
|
+
* upstream caller (runPostVerify) additionally wraps the call in try/catch
|
|
28
|
+
* for the same defensive posture.
|
|
29
|
+
*/
|
|
30
|
+
import type { QATicketStore, RegressionDetector } from '@derwinjs/sdk';
|
|
31
|
+
export interface PrismaRegressionDetectorConfig {
|
|
32
|
+
/**
|
|
33
|
+
* QATicketStore instance — the same instance the rest of the platform uses,
|
|
34
|
+
* so the lookups respect the same tenant scope and DB connection pool.
|
|
35
|
+
*/
|
|
36
|
+
ticketStore: QATicketStore;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build a RegressionDetector backed by QATicketStore.listQATickets.
|
|
40
|
+
*
|
|
41
|
+
* The returned callback is invoked by runPostVerify when post-verify reports
|
|
42
|
+
* failure signals after a merge — see packages/core/src/orchestrator/run-post-verify.ts.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createPrismaRegressionDetector(config: PrismaRegressionDetectorConfig): RegressionDetector;
|
|
45
|
+
//# sourceMappingURL=regression-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regression-detector.d.ts","sourceRoot":"","sources":["../src/regression-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAIvE,MAAM,WAAW,8BAA8B;IAC7C;;;OAGG;IACH,WAAW,EAAE,aAAa,CAAC;CAC5B;AAQD;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,8BAA8B,GACrC,kBAAkB,CAyCpB"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default RegressionDetector — QAP-Sprint7 Phase 3 / QAP-071.
|
|
3
|
+
*
|
|
4
|
+
* Stock implementation of the SDK RegressionDetector callback type
|
|
5
|
+
* (packages/sdk/src/types/regression-detector.ts). Wires `QATicketStore.listQATickets`
|
|
6
|
+
* with (classification, surface, ageHours, status) filters to find newly-opened
|
|
7
|
+
* tickets matching the original ticket's classification + surface within
|
|
8
|
+
* `withinDays` of `sinceMergedAt`. Returns true iff at least one such ticket
|
|
9
|
+
* exists (excluding the original ticket itself).
|
|
10
|
+
*
|
|
11
|
+
* Why a callback factory in @derwinjs/db rather than a stateful adapter:
|
|
12
|
+
* The RegressionDetector contract is intentionally a function type — not
|
|
13
|
+
* every consumer reads QA tickets to decide regression. A telemetry-driven
|
|
14
|
+
* Datadog/OpenTelemetry impl would query metrics instead. This file provides
|
|
15
|
+
* the *default* QATicketStore-backed callback that runPostVerify wires when
|
|
16
|
+
* the consumer opts into Derwin's standard regression-detection rule.
|
|
17
|
+
*
|
|
18
|
+
* Tenant isolation: the projectId argument from the callback flows directly
|
|
19
|
+
* into ticketStore.getQATicket and ticketStore.listQATickets, both of which
|
|
20
|
+
* are tenant-scoped per QAP-018B. No cross-project leakage is possible at
|
|
21
|
+
* this layer.
|
|
22
|
+
*
|
|
23
|
+
* Failure semantics: the callback never throws. Defense-in-depth — if the
|
|
24
|
+
* original ticket cannot be resolved (missing or cross-tenant), return false
|
|
25
|
+
* (no original means no regression context). This mirrors the orchestrator's
|
|
26
|
+
* "regression detection MUST NOT abort the post-verify path" rule. The
|
|
27
|
+
* upstream caller (runPostVerify) additionally wraps the call in try/catch
|
|
28
|
+
* for the same defensive posture.
|
|
29
|
+
*/
|
|
30
|
+
// ─── Constants ────────────────────────────────────────────────────────────
|
|
31
|
+
const HOURS_PER_DAY = 24;
|
|
32
|
+
// ─── Factory ─────────────────────────────────────────────────────────────
|
|
33
|
+
/**
|
|
34
|
+
* Build a RegressionDetector backed by QATicketStore.listQATickets.
|
|
35
|
+
*
|
|
36
|
+
* The returned callback is invoked by runPostVerify when post-verify reports
|
|
37
|
+
* failure signals after a merge — see packages/core/src/orchestrator/run-post-verify.ts.
|
|
38
|
+
*/
|
|
39
|
+
export function createPrismaRegressionDetector(config) {
|
|
40
|
+
const { ticketStore } = config;
|
|
41
|
+
return async ({ projectId, qaTicketId, sinceMergedAt, withinDays }) => {
|
|
42
|
+
// (1) Fetch the original ticket. Both not-found and cross-tenant
|
|
43
|
+
// collisions return null per the QATicketStore contract — either way,
|
|
44
|
+
// returning false here is the correct defensive answer (no original →
|
|
45
|
+
// no regression context to evaluate).
|
|
46
|
+
const original = await ticketStore.getQATicket({ id: qaTicketId, projectId });
|
|
47
|
+
if (original === null) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
// (2) List candidate regression tickets via the store's existing filter
|
|
51
|
+
// shape. We narrow on (classification, surface) to scope to the same
|
|
52
|
+
// failure family, on ageHoursMax = withinDays * 24 to bound the search
|
|
53
|
+
// window, and on status: 'OPEN' so already-resolved historical tickets
|
|
54
|
+
// don't generate false positives. ageHoursMin: 0 is the floor.
|
|
55
|
+
const candidates = await ticketStore.listQATickets({
|
|
56
|
+
projectId,
|
|
57
|
+
classification: original.classification,
|
|
58
|
+
surface: original.surface,
|
|
59
|
+
ageHoursMin: 0,
|
|
60
|
+
ageHoursMax: withinDays * HOURS_PER_DAY,
|
|
61
|
+
status: 'OPEN',
|
|
62
|
+
});
|
|
63
|
+
// (3) Paranoia filter — listQATickets uses age (relative to "now"), not
|
|
64
|
+
// an absolute timestamp, and the original's age might place IT inside
|
|
65
|
+
// the window too. We exclude (a) tickets created at or before the merge
|
|
66
|
+
// moment and (b) the original ticket itself. The combination means:
|
|
67
|
+
// only tickets opened strictly AFTER the merge that are NOT the original
|
|
68
|
+
// count as regressions.
|
|
69
|
+
const mergedAtMs = sinceMergedAt.getTime();
|
|
70
|
+
const matches = candidates.tickets.filter((t) => {
|
|
71
|
+
if (t.id === qaTicketId)
|
|
72
|
+
return false;
|
|
73
|
+
return t.createdAt.getTime() > mergedAtMs;
|
|
74
|
+
});
|
|
75
|
+
return matches.length > 0;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=regression-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regression-detector.js","sourceRoot":"","sources":["../src/regression-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAcH,6EAA6E;AAE7E,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB,4EAA4E;AAE5E;;;;;GAKG;AACH,MAAM,UAAU,8BAA8B,CAC5C,MAAsC;IAEtC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;IAE/B,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE,EAAE;QACpE,iEAAiE;QACjE,sEAAsE;QACtE,sEAAsE;QACtE,sCAAsC;QACtC,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;QAC9E,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,wEAAwE;QACxE,qEAAqE;QACrE,uEAAuE;QACvE,uEAAuE;QACvE,+DAA+D;QAC/D,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC;YACjD,SAAS;YACT,cAAc,EAAE,QAAQ,CAAC,cAAc;YACvC,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,UAAU,GAAG,aAAa;YACvC,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QAEH,wEAAwE;QACxE,sEAAsE;QACtE,wEAAwE;QACxE,oEAAoE;QACpE,yEAAyE;QACzE,wBAAwB;QACxB,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YAC9C,IAAI,CAAC,CAAC,EAAE,KAAK,UAAU;gBAAE,OAAO,KAAK,CAAC;YACtC,OAAO,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5B,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@derwinjs/db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Prisma schema + migrations for Derwin's own Postgres. 14 models, project-namespaced. Per ADR-0005. Ships its own generated Prisma client (multi-platform binaries) for cross-consumer compatibility.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@prisma/client": "^5.22.0",
|
|
36
|
-
"@derwinjs/core": "0.
|
|
37
|
-
"@derwinjs/sdk": "0.
|
|
36
|
+
"@derwinjs/core": "0.7.0",
|
|
37
|
+
"@derwinjs/sdk": "0.7.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@vitest/coverage-v8": "^2.1.9",
|