@derwinjs/db 0.11.0 → 0.13.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.
@@ -0,0 +1,48 @@
1
+ /**
2
+ * createPrismaCostRegressionEvaluator — Sprint 12 Phase 4 (QAP-135).
3
+ *
4
+ * PR-time gate that compares a proposed fix-attempt's projected cost against
5
+ * the historical median for similar fixes scoped by
6
+ * (projectId, classification, surface) within a trailing window. Composes with
7
+ * the pure helper from @derwinjs/core to compute the verdict.
8
+ *
9
+ * # No new migration
10
+ *
11
+ * Reads the existing `QAFixAttempt.costCents` field (Int?, INTEGER cents —
12
+ * legacy schema, same column BudgetGate aggregates over since Sprint 8
13
+ * Phase 3 / QAP-084). The factory divides by 100 to surface USD floats so
14
+ * the SDK contract surface stays in dollars; no schema migration is needed
15
+ * for QAP-135.
16
+ *
17
+ * # Cohort scoping
18
+ *
19
+ * The QAFixAttempt rows do NOT carry classification or surface directly —
20
+ * those live on the joined QATicket model. Cohort filter is therefore
21
+ * expressed as `where.ticket: { classification, surface }` (the relation
22
+ * field on QAFixAttempt is `ticket`, joined via `qaTicketId`).
23
+ *
24
+ * # Window field
25
+ *
26
+ * QAFixAttempt has `attemptedAt` (not `createdAt`); the trailing-window
27
+ * filter uses that column.
28
+ *
29
+ * # Tenant isolation
30
+ *
31
+ * Every read scopes by `projectId`. Cross-tenant probes naturally surface
32
+ * as `no_baseline_yet` (the cohort findMany returns no rows for the wrong
33
+ * tenant), which is indistinguishable from a real cohort with insufficient
34
+ * samples — Pattern D defense-in-depth.
35
+ */
36
+ import type { PrismaClient } from './prisma.js';
37
+ import { type CostRegressionEvaluator } from '@derwinjs/sdk';
38
+ export interface PrismaCostRegressionEvaluatorConfig {
39
+ /** Generated Prisma client. Pass an instance per process. */
40
+ prisma: PrismaClient;
41
+ /**
42
+ * Optional clock injection for deterministic window-boundary tests. Tests
43
+ * pass a fixed Date; production callers omit (defaults to `new Date()`).
44
+ */
45
+ now?: () => Date;
46
+ }
47
+ export declare function createPrismaCostRegressionEvaluator(config: PrismaCostRegressionEvaluatorConfig): CostRegressionEvaluator;
48
+ //# sourceMappingURL=cost-regression-evaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-regression-evaluator.d.ts","sourceRoot":"","sources":["../src/cost-regression-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAEL,KAAK,uBAAuB,EAG7B,MAAM,eAAe,CAAC;AAKvB,MAAM,WAAW,mCAAmC;IAClD,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;IACrB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AA6DD,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,mCAAmC,GAC1C,uBAAuB,CAkDzB"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * createPrismaCostRegressionEvaluator — Sprint 12 Phase 4 (QAP-135).
3
+ *
4
+ * PR-time gate that compares a proposed fix-attempt's projected cost against
5
+ * the historical median for similar fixes scoped by
6
+ * (projectId, classification, surface) within a trailing window. Composes with
7
+ * the pure helper from @derwinjs/core to compute the verdict.
8
+ *
9
+ * # No new migration
10
+ *
11
+ * Reads the existing `QAFixAttempt.costCents` field (Int?, INTEGER cents —
12
+ * legacy schema, same column BudgetGate aggregates over since Sprint 8
13
+ * Phase 3 / QAP-084). The factory divides by 100 to surface USD floats so
14
+ * the SDK contract surface stays in dollars; no schema migration is needed
15
+ * for QAP-135.
16
+ *
17
+ * # Cohort scoping
18
+ *
19
+ * The QAFixAttempt rows do NOT carry classification or surface directly —
20
+ * those live on the joined QATicket model. Cohort filter is therefore
21
+ * expressed as `where.ticket: { classification, surface }` (the relation
22
+ * field on QAFixAttempt is `ticket`, joined via `qaTicketId`).
23
+ *
24
+ * # Window field
25
+ *
26
+ * QAFixAttempt has `attemptedAt` (not `createdAt`); the trailing-window
27
+ * filter uses that column.
28
+ *
29
+ * # Tenant isolation
30
+ *
31
+ * Every read scopes by `projectId`. Cross-tenant probes naturally surface
32
+ * as `no_baseline_yet` (the cohort findMany returns no rows for the wrong
33
+ * tenant), which is indistinguishable from a real cohort with insufficient
34
+ * samples — Pattern D defense-in-depth.
35
+ */
36
+ import { CostRegressionEvaluatorError, } from '@derwinjs/sdk';
37
+ import { DEFAULT_WINDOW_MS, evaluateCostRegression } from '@derwinjs/core';
38
+ // ─── Validation ──────────────────────────────────────────────────────────
39
+ function validateInput(input) {
40
+ if (typeof input.projectId !== 'string' || input.projectId.length === 0) {
41
+ throw new CostRegressionEvaluatorError('invalid_input', 'CostRegressionEvaluator: projectId is required');
42
+ }
43
+ if (typeof input.classification !== 'string' || input.classification.length === 0) {
44
+ throw new CostRegressionEvaluatorError('invalid_input', 'CostRegressionEvaluator: classification is required');
45
+ }
46
+ if (typeof input.surface !== 'string' || input.surface.length === 0) {
47
+ throw new CostRegressionEvaluatorError('invalid_input', 'CostRegressionEvaluator: surface is required');
48
+ }
49
+ if (typeof input.attemptedFixCostUsd !== 'number' ||
50
+ !Number.isFinite(input.attemptedFixCostUsd) ||
51
+ input.attemptedFixCostUsd < 0) {
52
+ throw new CostRegressionEvaluatorError('invalid_input', 'CostRegressionEvaluator: attemptedFixCostUsd must be a non-negative finite number');
53
+ }
54
+ if (input.thresholdMultiplier !== undefined) {
55
+ if (!Number.isFinite(input.thresholdMultiplier) || input.thresholdMultiplier <= 0) {
56
+ throw new CostRegressionEvaluatorError('invalid_input', 'CostRegressionEvaluator: thresholdMultiplier must be a positive finite number');
57
+ }
58
+ }
59
+ if (input.minSamples !== undefined) {
60
+ if (!Number.isInteger(input.minSamples) || input.minSamples < 1) {
61
+ throw new CostRegressionEvaluatorError('invalid_input', 'CostRegressionEvaluator: minSamples must be a positive integer');
62
+ }
63
+ }
64
+ if (input.windowMs !== undefined) {
65
+ if (!Number.isFinite(input.windowMs) || input.windowMs <= 0) {
66
+ throw new CostRegressionEvaluatorError('invalid_input', 'CostRegressionEvaluator: windowMs must be a positive finite number');
67
+ }
68
+ }
69
+ }
70
+ // ─── Factory ─────────────────────────────────────────────────────────────
71
+ export function createPrismaCostRegressionEvaluator(config) {
72
+ const { prisma } = config;
73
+ const now = config.now ?? (() => new Date());
74
+ return {
75
+ async evaluate(input) {
76
+ validateInput(input);
77
+ const windowMs = input.windowMs ?? DEFAULT_WINDOW_MS;
78
+ const since = new Date(now().getTime() - windowMs);
79
+ let attempts;
80
+ try {
81
+ attempts = await prisma.qAFixAttempt.findMany({
82
+ where: {
83
+ projectId: input.projectId,
84
+ attemptedAt: { gte: since },
85
+ costCents: { not: null },
86
+ ticket: {
87
+ classification: input.classification,
88
+ // SurfaceCategory enum — SDK input mirrors QATicket.surface, so
89
+ // Prisma accepts it directly without a cast.
90
+ surface: input.surface,
91
+ },
92
+ },
93
+ select: { costCents: true },
94
+ });
95
+ }
96
+ catch (err) {
97
+ const message = err instanceof Error ? err.message : String(err);
98
+ throw new CostRegressionEvaluatorError('storage_failed', `cost-regression query failed: ${message}`, err);
99
+ }
100
+ // QAFixAttempt.costCents is INT cents (legacy schema, preserved for
101
+ // back-compat with the audit trail). Divide by 100 to surface USD
102
+ // floats so the contract surface stays in dollars. Same conversion
103
+ // BudgetGate applies (see packages/db/src/budget-gate.ts).
104
+ const costsUsd = [];
105
+ for (const a of attempts) {
106
+ if (typeof a.costCents === 'number') {
107
+ costsUsd.push(a.costCents / 100);
108
+ }
109
+ }
110
+ return evaluateCostRegression(input, costsUsd);
111
+ },
112
+ };
113
+ }
114
+ //# sourceMappingURL=cost-regression-evaluator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-regression-evaluator.js","sourceRoot":"","sources":["../src/cost-regression-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EACL,4BAA4B,GAI7B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAc3E,4EAA4E;AAE5E,SAAS,aAAa,CAAC,KAAmC;IACxD,IAAI,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,4BAA4B,CACpC,eAAe,EACf,gDAAgD,CACjD,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,cAAc,KAAK,QAAQ,IAAI,KAAK,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClF,MAAM,IAAI,4BAA4B,CACpC,eAAe,EACf,qDAAqD,CACtD,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,4BAA4B,CACpC,eAAe,EACf,8CAA8C,CAC/C,CAAC;IACJ,CAAC;IACD,IACE,OAAO,KAAK,CAAC,mBAAmB,KAAK,QAAQ;QAC7C,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC;QAC3C,KAAK,CAAC,mBAAmB,GAAG,CAAC,EAC7B,CAAC;QACD,MAAM,IAAI,4BAA4B,CACpC,eAAe,EACf,mFAAmF,CACpF,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;QAC5C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,KAAK,CAAC,mBAAmB,IAAI,CAAC,EAAE,CAAC;YAClF,MAAM,IAAI,4BAA4B,CACpC,eAAe,EACf,+EAA+E,CAChF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,4BAA4B,CACpC,eAAe,EACf,gEAAgE,CACjE,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,4BAA4B,CACpC,eAAe,EACf,oEAAoE,CACrE,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,4EAA4E;AAE5E,MAAM,UAAU,mCAAmC,CACjD,MAA2C;IAE3C,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC1B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAE7C,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,KAAmC;YAChD,aAAa,CAAC,KAAK,CAAC,CAAC;YAErB,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,iBAAiB,CAAC;YACrD,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC;YAEnD,IAAI,QAAwC,CAAC;YAC7C,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC;oBAC5C,KAAK,EAAE;wBACL,SAAS,EAAE,KAAK,CAAC,SAAS;wBAC1B,WAAW,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE;wBAC3B,SAAS,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE;wBACxB,MAAM,EAAE;4BACN,cAAc,EAAE,KAAK,CAAC,cAAc;4BACpC,gEAAgE;4BAChE,6CAA6C;4BAC7C,OAAO,EAAE,KAAK,CAAC,OAAO;yBACvB;qBACF;oBACD,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;iBAC5B,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjE,MAAM,IAAI,4BAA4B,CACpC,gBAAgB,EAChB,iCAAiC,OAAO,EAAE,EAC1C,GAAG,CACJ,CAAC;YACJ,CAAC;YAED,oEAAoE;YACpE,kEAAkE;YAClE,mEAAmE;YACnE,2DAA2D;YAC3D,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACzB,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;oBACpC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;YAED,OAAO,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACjD,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@
16
16
  export declare const PACKAGE_NAME: "@derwinjs/db";
17
17
  export { createPrismaQATicketStore, type PrismaQATicketStoreConfig } from './qa-ticket-store.js';
18
18
  export { createPrismaQAFixAttemptStore, type PrismaQAFixAttemptStoreConfig, } from './qa-fix-attempt-store.js';
19
+ export { createPrismaQAAuditArtifactStore, type PrismaQAAuditArtifactStoreConfig, } from './qa-audit-artifact-store.js';
19
20
  export { createPrismaQARunStore, type PrismaQARunStoreConfig } from './qa-run-store.js';
20
21
  export { createPrismaQAPatternStore, type PrismaQAPatternStoreConfig } from './qa-pattern-store.js';
21
22
  export { createPrismaQARevertStore, type PrismaQARevertStoreConfig } from './qa-revert-store.js';
@@ -38,5 +39,7 @@ export { createPrismaContractBaselineStore, type PrismaContractBaselineStoreConf
38
39
  export { createPrismaTenantFuzzConfigStore, type PrismaTenantFuzzConfigStoreConfig, } from './tenant-fuzz-config-store.js';
39
40
  export { createPrismaRumSampleStore, RumSampleStoreError, type PrismaRumSampleStoreConfig, } from './rum-sample-store.js';
40
41
  export { createPrismaMilestoneEventStore, type PrismaMilestoneEventStoreConfig, } from './milestone-event-store.js';
42
+ export { createPrismaCostRegressionEvaluator, type PrismaCostRegressionEvaluatorConfig, } from './cost-regression-evaluator.js';
43
+ export { createPrismaSelfReviewVerdictStore, type PrismaSelfReviewVerdictStoreConfig, } from './self-review-verdict-store.js';
41
44
  export * from './prisma.js';
42
45
  //# sourceMappingURL=index.d.ts.map
@@ -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;AACpC,OAAO,EACL,8BAA8B,EAC9B,KAAK,8BAA8B,GACpC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChG,OAAO,EACL,4BAA4B,EAC5B,SAAS,EACT,KAAK,4BAA4B,GAClC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uCAAuC,EACvC,KAAK,uCAAuC,GAC7C,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,qCAAqC,EACrC,KAAK,qCAAqC,GAC3C,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iCAAiC,EACjC,SAAS,EACT,cAAc,EACd,KAAK,iCAAiC,GACvC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,EAC9B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,4BAA4B,EAC5B,KAAK,4BAA4B,GAClC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,kCAAkC,EAClC,4BAA4B,EAC5B,KAAK,kCAAkC,GACxC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,EAC/B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,iCAAiC,EACjC,KAAK,iCAAiC,GACvC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,iCAAiC,EACjC,KAAK,iCAAiC,GACvC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,0BAA0B,EAC1B,mBAAmB,EACnB,KAAK,0BAA0B,GAChC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,+BAA+B,EAC/B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;AA4BpC,cAAc,aAAa,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,EACL,gCAAgC,EAChC,KAAK,gCAAgC,GACtC,MAAM,8BAA8B,CAAC;AACtC,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;AAChG,OAAO,EACL,4BAA4B,EAC5B,SAAS,EACT,KAAK,4BAA4B,GAClC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uCAAuC,EACvC,KAAK,uCAAuC,GAC7C,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,qCAAqC,EACrC,KAAK,qCAAqC,GAC3C,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iCAAiC,EACjC,SAAS,EACT,cAAc,EACd,KAAK,iCAAiC,GACvC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,EAC9B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,4BAA4B,EAC5B,KAAK,4BAA4B,GAClC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,kCAAkC,EAClC,4BAA4B,EAC5B,KAAK,kCAAkC,GACxC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,EAC/B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,iCAAiC,EACjC,KAAK,iCAAiC,GACvC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,iCAAiC,EACjC,KAAK,iCAAiC,GACvC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,0BAA0B,EAC1B,mBAAmB,EACnB,KAAK,0BAA0B,GAChC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,+BAA+B,EAC/B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,mCAAmC,EACnC,KAAK,mCAAmC,GACzC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,kCAAkC,EAClC,KAAK,kCAAkC,GACxC,MAAM,gCAAgC,CAAC;AA4BxC,cAAc,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -17,6 +17,7 @@ export const PACKAGE_NAME = '@derwinjs/db';
17
17
  // ─── Storage implementations ─────────────────────────────────────────────
18
18
  export { createPrismaQATicketStore } from './qa-ticket-store.js';
19
19
  export { createPrismaQAFixAttemptStore, } from './qa-fix-attempt-store.js';
20
+ export { createPrismaQAAuditArtifactStore, } from './qa-audit-artifact-store.js';
20
21
  export { createPrismaQARunStore } from './qa-run-store.js';
21
22
  export { createPrismaQAPatternStore } from './qa-pattern-store.js';
22
23
  export { createPrismaQARevertStore } from './qa-revert-store.js';
@@ -39,6 +40,8 @@ export { createPrismaContractBaselineStore, } from './contract-baseline-store.js
39
40
  export { createPrismaTenantFuzzConfigStore, } from './tenant-fuzz-config-store.js';
40
41
  export { createPrismaRumSampleStore, RumSampleStoreError, } from './rum-sample-store.js';
41
42
  export { createPrismaMilestoneEventStore, } from './milestone-event-store.js';
43
+ export { createPrismaCostRegressionEvaluator, } from './cost-regression-evaluator.js';
44
+ export { createPrismaSelfReviewVerdictStore, } from './self-review-verdict-store.js';
42
45
  // ─── Prisma client re-export ─────────────────────────────────────────────
43
46
  //
44
47
  // @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;AACpC,OAAO,EACL,8BAA8B,GAE/B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAkC,MAAM,qBAAqB,CAAC;AAChG,OAAO,EACL,4BAA4B,EAC5B,SAAS,GAEV,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uCAAuC,GAExC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,qCAAqC,GAEtC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iCAAiC,EACjC,SAAS,EACT,cAAc,GAEf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAA+B,MAAM,kBAAkB,CAAC;AACvF,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,GAE/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,4BAA4B,GAE7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,kCAAkC,EAClC,4BAA4B,GAE7B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,GAEhC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,iCAAiC,GAElC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,iCAAiC,GAElC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,0BAA0B,EAC1B,mBAAmB,GAEpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,+BAA+B,GAEhC,MAAM,4BAA4B,CAAC;AAEpC,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
+ {"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,EACL,gCAAgC,GAEjC,MAAM,8BAA8B,CAAC;AACtC,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;AAChG,OAAO,EACL,4BAA4B,EAC5B,SAAS,GAEV,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uCAAuC,GAExC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,qCAAqC,GAEtC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iCAAiC,EACjC,SAAS,EACT,cAAc,GAEf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAA+B,MAAM,kBAAkB,CAAC;AACvF,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,GAE/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,4BAA4B,GAE7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,kCAAkC,EAClC,4BAA4B,GAE7B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,GAEhC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,iCAAiC,GAElC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,iCAAiC,GAElC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,0BAA0B,EAC1B,mBAAmB,GAEpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,+BAA+B,GAEhC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,mCAAmC,GAEpC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,kCAAkC,GAEnC,MAAM,gCAAgC,CAAC;AAExC,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":"learning-health-reporter.d.ts","sourceRoot":"","sources":["../src/learning-health-reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAKL,KAAK,sBAAsB,EAC5B,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,kCAAkC;IACjD,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AAUD,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,kCAAkC,GACzC,sBAAsB,CAiGxB"}
1
+ {"version":3,"file":"learning-health-reporter.d.ts","sourceRoot":"","sources":["../src/learning-health-reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAKL,KAAK,sBAAsB,EAC5B,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,kCAAkC;IACjD,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AAUD,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,kCAAkC,GACzC,sBAAsB,CA4GxB"}
@@ -27,6 +27,7 @@
27
27
  * merged attempts).
28
28
  * - Lifeline `QAPatternInsight` → Derwin `QAPattern` (D-2 rename).
29
29
  */
30
+ import { translateFixSuccessToOutcomeQuality } from '@derwinjs/core';
30
31
  import { LearningHealthReporterError, } from '@derwinjs/sdk';
31
32
  // ─── Constants (Lifeline parity) ─────────────────────────────────────────
32
33
  const DEFAULT_WINDOW_DAYS = 30;
@@ -75,9 +76,19 @@ export function createPrismaLearningHealthReporter(config) {
75
76
  });
76
77
  const topImprovingClassifications = patterns.map((p) => ({
77
78
  classification: p.classification,
78
- // Filter ensures fixSuccessScore !== null, but TS narrows it to
79
- // number | null because Prisma's type widens. Coerce defensively.
80
- score: p.fixSuccessScore ?? 0,
79
+ // Unit translation: QAPattern.fixSuccessScore is a signed mean in
80
+ // [-1, +1] (Lifeline-shape preserved per D-2 Decision 1). The SDK
81
+ // contract for ClassificationTrendRow.score is the [0, 1]
82
+ // outcomeQuality scale, so consumers like LearningHealthDashboard
83
+ // can render Math.round(score * 100) without producing negative
84
+ // percentages on regression-heavy patterns. The WHERE filter above
85
+ // (`fixSuccessScore: { not: null }`) means the null branch is
86
+ // unreachable in practice — the defensive `=== null` guard is
87
+ // there for the Prisma type-widening case (Prisma's projection
88
+ // type doesn't narrow with WHERE clauses).
89
+ score: p.fixSuccessScore === null
90
+ ? null
91
+ : translateFixSuccessToOutcomeQuality(p.fixSuccessScore),
81
92
  sampleSize: p.fixOutcomeSampleSize,
82
93
  }));
83
94
  // ─── 3. Patterns with samples (transparency metric) ────────────────
@@ -1 +1 @@
1
- {"version":3,"file":"learning-health-reporter.js","sourceRoot":"","sources":["../src/learning-health-reporter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"learning-health-reporter.js","sourceRoot":"","sources":["../src/learning-health-reporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * QAAuditArtifactStore — Prisma implementation against Derwin's AuditArtifact
3
+ * table.
4
+ *
5
+ * QAP-094 follow-on (Sprint 13 Phase 2). Implements the QAAuditArtifactStore
6
+ * contract from @derwinjs/sdk (see packages/sdk/src/types/
7
+ * qa-audit-artifact-store.ts) against the @derwinjs/db Prisma client. Pattern
8
+ * matches createPrismaQAFixAttemptStore: a factory taking `{ prisma }` so the
9
+ * caller injects the client at boot.
10
+ *
11
+ * Tenant isolation: `listArtifactsForFixAttempt` filters by BOTH
12
+ * `qaFixAttemptId` AND `projectId` in a single Prisma `findMany`. A
13
+ * cross-tenant probe (right id, wrong projectId) returns []; an unknown id
14
+ * returns []; a known id with no artifacts returns []. The three negatives
15
+ * are indistinguishable — Pattern D defense-in-depth, no separate
16
+ * verify-attempt-exists round-trip.
17
+ */
18
+ import type { PrismaClient } from './prisma.js';
19
+ import { type QAAuditArtifactStore } from '@derwinjs/sdk';
20
+ export interface PrismaQAAuditArtifactStoreConfig {
21
+ /** Generated Prisma client. Pass an instance per process. */
22
+ prisma: PrismaClient;
23
+ }
24
+ export declare function createPrismaQAAuditArtifactStore(config: PrismaQAAuditArtifactStoreConfig): QAAuditArtifactStore;
25
+ //# sourceMappingURL=qa-audit-artifact-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-audit-artifact-store.d.ts","sourceRoot":"","sources":["../src/qa-audit-artifact-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAML,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,gCAAgC;IAC/C,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AAID,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,gCAAgC,GACvC,oBAAoB,CAoBtB"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * QAAuditArtifactStore — Prisma implementation against Derwin's AuditArtifact
3
+ * table.
4
+ *
5
+ * QAP-094 follow-on (Sprint 13 Phase 2). Implements the QAAuditArtifactStore
6
+ * contract from @derwinjs/sdk (see packages/sdk/src/types/
7
+ * qa-audit-artifact-store.ts) against the @derwinjs/db Prisma client. Pattern
8
+ * matches createPrismaQAFixAttemptStore: a factory taking `{ prisma }` so the
9
+ * caller injects the client at boot.
10
+ *
11
+ * Tenant isolation: `listArtifactsForFixAttempt` filters by BOTH
12
+ * `qaFixAttemptId` AND `projectId` in a single Prisma `findMany`. A
13
+ * cross-tenant probe (right id, wrong projectId) returns []; an unknown id
14
+ * returns []; a known id with no artifacts returns []. The three negatives
15
+ * are indistinguishable — Pattern D defense-in-depth, no separate
16
+ * verify-attempt-exists round-trip.
17
+ */
18
+ import { ArtifactStoreError, } from '@derwinjs/sdk';
19
+ // ─── Factory ─────────────────────────────────────────────────────────────
20
+ export function createPrismaQAAuditArtifactStore(config) {
21
+ const { prisma } = config;
22
+ return {
23
+ async listArtifactsForFixAttempt(filter) {
24
+ validateFilter(filter);
25
+ const rows = await prisma.auditArtifact.findMany({
26
+ where: {
27
+ qaFixAttemptId: filter.qaFixAttemptId,
28
+ projectId: filter.projectId,
29
+ },
30
+ orderBy: { capturedAt: 'asc' },
31
+ });
32
+ return rows.map(mapArtifact);
33
+ },
34
+ };
35
+ }
36
+ function mapArtifact(row) {
37
+ return {
38
+ id: row.id,
39
+ projectId: row.projectId,
40
+ qaFixAttemptId: row.qaFixAttemptId,
41
+ qaTicketId: row.qaTicketId,
42
+ artifactType: row.artifactType,
43
+ stage: row.stage,
44
+ storageBackend: row.storageBackend,
45
+ storageKey: row.storageKey,
46
+ contentType: row.contentType,
47
+ sizeBytes: row.sizeBytes,
48
+ contentHash: row.contentHash,
49
+ capturedAt: row.capturedAt,
50
+ };
51
+ }
52
+ function validateFilter(filter) {
53
+ if (filter.qaFixAttemptId.trim().length === 0) {
54
+ throw new ArtifactStoreError('invalid_input', 'qaFixAttemptId is required for listArtifactsForFixAttempt');
55
+ }
56
+ if (filter.projectId.trim().length === 0) {
57
+ throw new ArtifactStoreError('invalid_input', 'projectId is required for listArtifactsForFixAttempt — there is no cross-tenant list query');
58
+ }
59
+ }
60
+ //# sourceMappingURL=qa-audit-artifact-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-audit-artifact-store.js","sourceRoot":"","sources":["../src/qa-audit-artifact-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EACL,kBAAkB,GAMnB,MAAM,eAAe,CAAC;AASvB,4EAA4E;AAE5E,MAAM,UAAU,gCAAgC,CAC9C,MAAwC;IAExC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAE1B,OAAO;QACL,KAAK,CAAC,0BAA0B,CAC9B,MAAwC;YAExC,cAAc,CAAC,MAAM,CAAC,CAAC;YAEvB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC;gBAC/C,KAAK,EAAE;oBACL,cAAc,EAAE,MAAM,CAAC,cAAc;oBACrC,SAAS,EAAE,MAAM,CAAC,SAAS;iBAC5B;gBACD,OAAO,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE;aAC/B,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC;KACF,CAAC;AACJ,CAAC;AAyBD,SAAS,WAAW,CAAC,GAA2B;IAC9C,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,YAAY,EAAE,GAAG,CAAC,YAAiC;QACnD,KAAK,EAAE,GAAG,CAAC,KAA2B;QACtC,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,UAAU,EAAE,GAAG,CAAC,UAAU;KAC3B,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,MAAwC;IAC9D,IAAI,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,kBAAkB,CAC1B,eAAe,EACf,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,kBAAkB,CAC1B,eAAe,EACf,4FAA4F,CAC7F,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * createPrismaSelfReviewVerdictStore — Prisma-backed implementation of the
3
+ * SDK SelfReviewVerdictStore contract introduced by QAP-133.
4
+ *
5
+ * Sprint 13 Phase 9 (recursive self-review pre-merge gate). One row per
6
+ * self-review call regardless of outcome — the audit trail is
7
+ * non-negotiable. The orchestrator persists every call's verdict; the
8
+ * `?force=true` operator-override path on the orchestrate route also writes
9
+ * here with verdict='pass' and reasonHints capturing the operator's userId
10
+ * so every override is auditable.
11
+ *
12
+ * Tenant isolation: every method scopes by projectId. Pattern D applies —
13
+ * `getLatestForAttempt` returns null on cross-tenant or missing rows
14
+ * (defense-in-depth against tenant enumeration). `listVerdicts` returns []
15
+ * on cross-tenant projectId.
16
+ *
17
+ * Validation runs at the factory boundary BEFORE any Prisma call — empty
18
+ * `projectId` / `qaFixAttemptId` / `qaTicketId` / negative issue counts
19
+ * throw `invalid_input` so the error surfaces with a clear caller-bug code
20
+ * rather than as a Prisma constraint violation.
21
+ */
22
+ import { type PrismaClient } from './prisma.js';
23
+ import { type SelfReviewVerdictStore } from '@derwinjs/sdk';
24
+ export interface PrismaSelfReviewVerdictStoreConfig {
25
+ /** Generated Prisma client. Pass an instance per process. */
26
+ prisma: PrismaClient;
27
+ }
28
+ export declare function createPrismaSelfReviewVerdictStore(config: PrismaSelfReviewVerdictStoreConfig): SelfReviewVerdictStore;
29
+ //# sourceMappingURL=self-review-verdict-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-review-verdict-store.d.ts","sourceRoot":"","sources":["../src/self-review-verdict-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAML,KAAK,sBAAsB,EAE5B,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,kCAAkC;IACjD,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AA8ED,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,kCAAkC,GACzC,sBAAsB,CA+FxB"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * createPrismaSelfReviewVerdictStore — Prisma-backed implementation of the
3
+ * SDK SelfReviewVerdictStore contract introduced by QAP-133.
4
+ *
5
+ * Sprint 13 Phase 9 (recursive self-review pre-merge gate). One row per
6
+ * self-review call regardless of outcome — the audit trail is
7
+ * non-negotiable. The orchestrator persists every call's verdict; the
8
+ * `?force=true` operator-override path on the orchestrate route also writes
9
+ * here with verdict='pass' and reasonHints capturing the operator's userId
10
+ * so every override is auditable.
11
+ *
12
+ * Tenant isolation: every method scopes by projectId. Pattern D applies —
13
+ * `getLatestForAttempt` returns null on cross-tenant or missing rows
14
+ * (defense-in-depth against tenant enumeration). `listVerdicts` returns []
15
+ * on cross-tenant projectId.
16
+ *
17
+ * Validation runs at the factory boundary BEFORE any Prisma call — empty
18
+ * `projectId` / `qaFixAttemptId` / `qaTicketId` / negative issue counts
19
+ * throw `invalid_input` so the error surfaces with a clear caller-bug code
20
+ * rather than as a Prisma constraint violation.
21
+ */
22
+ import { Prisma } from './prisma.js';
23
+ import { SelfReviewVerdictStoreError, } from '@derwinjs/sdk';
24
+ // ─── Constants ───────────────────────────────────────────────────────────
25
+ const DEFAULT_LIST_LIMIT = 50;
26
+ const MAX_LIST_LIMIT = 200;
27
+ const VALID_VERDICTS = new Set([
28
+ 'pass',
29
+ 'fail',
30
+ 'manual_review_required',
31
+ ]);
32
+ // ─── Validation ──────────────────────────────────────────────────────────
33
+ function assertNonEmpty(value, fieldName) {
34
+ if (typeof value !== 'string' || value.trim() === '') {
35
+ throw new SelfReviewVerdictStoreError('invalid_input', `createPrismaSelfReviewVerdictStore: ${fieldName} is required and non-empty`);
36
+ }
37
+ }
38
+ function assertNonNegativeInteger(value, fieldName) {
39
+ if (typeof value !== 'number' ||
40
+ !Number.isFinite(value) ||
41
+ value < 0 ||
42
+ !Number.isInteger(value)) {
43
+ throw new SelfReviewVerdictStoreError('invalid_input', `createPrismaSelfReviewVerdictStore: ${fieldName} must be a non-negative integer`);
44
+ }
45
+ }
46
+ function assertVerdict(value) {
47
+ if (typeof value !== 'string' || !VALID_VERDICTS.has(value)) {
48
+ throw new SelfReviewVerdictStoreError('invalid_input', `createPrismaSelfReviewVerdictStore: verdict must be one of 'pass' | 'fail' | 'manual_review_required'`);
49
+ }
50
+ }
51
+ function assertCreateInput(input) {
52
+ assertNonEmpty(input.projectId, 'projectId');
53
+ assertNonEmpty(input.qaFixAttemptId, 'qaFixAttemptId');
54
+ assertNonEmpty(input.qaTicketId, 'qaTicketId');
55
+ assertNonEmpty(input.classification, 'classification');
56
+ assertNonEmpty(input.surface, 'surface');
57
+ assertVerdict(input.verdict);
58
+ assertNonNegativeInteger(input.criticalIssuesFound, 'criticalIssuesFound');
59
+ assertNonNegativeInteger(input.minorIssuesFound, 'minorIssuesFound');
60
+ if (!Array.isArray(input.reasonHints)) {
61
+ throw new SelfReviewVerdictStoreError('invalid_input', `createPrismaSelfReviewVerdictStore: reasonHints must be an array of strings`);
62
+ }
63
+ for (const hint of input.reasonHints) {
64
+ if (typeof hint !== 'string') {
65
+ throw new SelfReviewVerdictStoreError('invalid_input', `createPrismaSelfReviewVerdictStore: reasonHints must be an array of strings`);
66
+ }
67
+ }
68
+ }
69
+ function clampLimit(value) {
70
+ if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0)
71
+ return DEFAULT_LIST_LIMIT;
72
+ return Math.min(MAX_LIST_LIMIT, Math.floor(value));
73
+ }
74
+ // ─── Factory ─────────────────────────────────────────────────────────────
75
+ export function createPrismaSelfReviewVerdictStore(config) {
76
+ const { prisma } = config;
77
+ return {
78
+ async createVerdict(input) {
79
+ assertCreateInput(input);
80
+ try {
81
+ const row = await prisma.selfReviewVerdict.create({
82
+ data: {
83
+ projectId: input.projectId,
84
+ qaFixAttemptId: input.qaFixAttemptId,
85
+ qaTicketId: input.qaTicketId,
86
+ classification: input.classification,
87
+ surface: input.surface,
88
+ verdict: input.verdict,
89
+ reasonHints: input.reasonHints,
90
+ criticalIssuesFound: input.criticalIssuesFound,
91
+ minorIssuesFound: input.minorIssuesFound,
92
+ },
93
+ });
94
+ return toRecord(row);
95
+ }
96
+ catch (err) {
97
+ if (err instanceof Prisma.PrismaClientKnownRequestError && err.code === 'P2003') {
98
+ // FK violation — projectId or qaFixAttemptId references a row
99
+ // that does not exist. Surface as fk_violation so the API layer
100
+ // can return 400 / 404 as appropriate.
101
+ throw new SelfReviewVerdictStoreError('fk_violation', `createPrismaSelfReviewVerdictStore: projectId or qaFixAttemptId does not resolve to an existing row`, err);
102
+ }
103
+ throw new SelfReviewVerdictStoreError('storage_failed', `createPrismaSelfReviewVerdictStore: createVerdict raised: ${err.message}`, err);
104
+ }
105
+ },
106
+ async listVerdicts(input) {
107
+ assertNonEmpty(input.projectId, 'projectId');
108
+ const limit = clampLimit(input.limit);
109
+ const where = { projectId: input.projectId };
110
+ if (input.qaFixAttemptId !== undefined) {
111
+ assertNonEmpty(input.qaFixAttemptId, 'qaFixAttemptId');
112
+ where.qaFixAttemptId = input.qaFixAttemptId;
113
+ }
114
+ if (input.verdict !== undefined) {
115
+ assertVerdict(input.verdict);
116
+ where.verdict = input.verdict;
117
+ }
118
+ try {
119
+ const rows = await prisma.selfReviewVerdict.findMany({
120
+ where,
121
+ orderBy: { createdAt: 'desc' },
122
+ take: limit,
123
+ });
124
+ return rows.map(toRecord);
125
+ }
126
+ catch (err) {
127
+ throw new SelfReviewVerdictStoreError('storage_failed', `createPrismaSelfReviewVerdictStore: listVerdicts raised: ${err.message}`, err);
128
+ }
129
+ },
130
+ async getLatestForAttempt(input) {
131
+ assertNonEmpty(input.qaFixAttemptId, 'qaFixAttemptId');
132
+ assertNonEmpty(input.projectId, 'projectId');
133
+ try {
134
+ const row = await prisma.selfReviewVerdict.findFirst({
135
+ where: {
136
+ qaFixAttemptId: input.qaFixAttemptId,
137
+ projectId: input.projectId,
138
+ },
139
+ orderBy: { createdAt: 'desc' },
140
+ });
141
+ return row === null ? null : toRecord(row);
142
+ }
143
+ catch (err) {
144
+ throw new SelfReviewVerdictStoreError('storage_failed', `createPrismaSelfReviewVerdictStore: getLatestForAttempt raised: ${err.message}`, err);
145
+ }
146
+ },
147
+ };
148
+ }
149
+ function toRecord(row) {
150
+ return {
151
+ id: row.id,
152
+ projectId: row.projectId,
153
+ qaFixAttemptId: row.qaFixAttemptId,
154
+ qaTicketId: row.qaTicketId,
155
+ classification: row.classification,
156
+ surface: row.surface,
157
+ // The string column is held as a free-form String at the schema level
158
+ // (no Prisma enum) — the SDK contract narrows it to the union after
159
+ // a runtime validation guard.
160
+ verdict: row.verdict,
161
+ reasonHints: row.reasonHints,
162
+ criticalIssuesFound: row.criticalIssuesFound,
163
+ minorIssuesFound: row.minorIssuesFound,
164
+ createdAt: row.createdAt,
165
+ };
166
+ }
167
+ //# sourceMappingURL=self-review-verdict-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-review-verdict-store.js","sourceRoot":"","sources":["../src/self-review-verdict-store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@derwinjs/db",
3
- "version": "0.11.0",
3
+ "version": "0.13.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.11.0",
37
- "@derwinjs/sdk": "0.11.0"
36
+ "@derwinjs/core": "0.13.0",
37
+ "@derwinjs/sdk": "0.13.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@vitest/coverage-v8": "^2.1.9",