@derwinjs/db 0.1.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.
Files changed (102) hide show
  1. package/LICENSE +25 -0
  2. package/README.md +79 -0
  3. package/dist/agent-findings-ingestor.d.ts +40 -0
  4. package/dist/agent-findings-ingestor.d.ts.map +1 -0
  5. package/dist/agent-findings-ingestor.js +154 -0
  6. package/dist/agent-findings-ingestor.js.map +1 -0
  7. package/dist/classification-trust-store.d.ts +31 -0
  8. package/dist/classification-trust-store.d.ts.map +1 -0
  9. package/dist/classification-trust-store.js +154 -0
  10. package/dist/classification-trust-store.js.map +1 -0
  11. package/dist/coverage-gap-reporter.d.ts +35 -0
  12. package/dist/coverage-gap-reporter.d.ts.map +1 -0
  13. package/dist/coverage-gap-reporter.js +84 -0
  14. package/dist/coverage-gap-reporter.js.map +1 -0
  15. package/dist/fix-policy.d.ts +46 -0
  16. package/dist/fix-policy.d.ts.map +1 -0
  17. package/dist/fix-policy.js +162 -0
  18. package/dist/fix-policy.js.map +1 -0
  19. package/dist/index.d.ts +27 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +53 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/learning-health-reporter.d.ts +37 -0
  24. package/dist/learning-health-reporter.d.ts.map +1 -0
  25. package/dist/learning-health-reporter.js +141 -0
  26. package/dist/learning-health-reporter.js.map +1 -0
  27. package/dist/prisma.d.ts +31 -0
  28. package/dist/prisma.d.ts.map +1 -0
  29. package/dist/prisma.js +31 -0
  30. package/dist/prisma.js.map +1 -0
  31. package/dist/qa-fix-attempt-store.d.ts +28 -0
  32. package/dist/qa-fix-attempt-store.d.ts.map +1 -0
  33. package/dist/qa-fix-attempt-store.js +258 -0
  34. package/dist/qa-fix-attempt-store.js.map +1 -0
  35. package/dist/qa-pattern-store.d.ts +32 -0
  36. package/dist/qa-pattern-store.d.ts.map +1 -0
  37. package/dist/qa-pattern-store.js +123 -0
  38. package/dist/qa-pattern-store.js.map +1 -0
  39. package/dist/qa-revert-store.d.ts +24 -0
  40. package/dist/qa-revert-store.d.ts.map +1 -0
  41. package/dist/qa-revert-store.js +139 -0
  42. package/dist/qa-revert-store.js.map +1 -0
  43. package/dist/qa-run-store.d.ts +46 -0
  44. package/dist/qa-run-store.d.ts.map +1 -0
  45. package/dist/qa-run-store.js +201 -0
  46. package/dist/qa-run-store.js.map +1 -0
  47. package/dist/qa-ticket-store.d.ts +35 -0
  48. package/dist/qa-ticket-store.d.ts.map +1 -0
  49. package/dist/qa-ticket-store.js +293 -0
  50. package/dist/qa-ticket-store.js.map +1 -0
  51. package/dist/qa-uniformity-store.d.ts +41 -0
  52. package/dist/qa-uniformity-store.d.ts.map +1 -0
  53. package/dist/qa-uniformity-store.js +288 -0
  54. package/dist/qa-uniformity-store.js.map +1 -0
  55. package/dist/scripts/smoke-auto-fix.d.ts +37 -0
  56. package/dist/scripts/smoke-auto-fix.d.ts.map +1 -0
  57. package/dist/scripts/smoke-auto-fix.js +270 -0
  58. package/dist/scripts/smoke-auto-fix.js.map +1 -0
  59. package/dist/scripts/smoke-learning-loop.d.ts +21 -0
  60. package/dist/scripts/smoke-learning-loop.d.ts.map +1 -0
  61. package/dist/scripts/smoke-learning-loop.js +375 -0
  62. package/dist/scripts/smoke-learning-loop.js.map +1 -0
  63. package/dist/scripts/smoke-orchestration.d.ts +35 -0
  64. package/dist/scripts/smoke-orchestration.d.ts.map +1 -0
  65. package/dist/scripts/smoke-orchestration.js +215 -0
  66. package/dist/scripts/smoke-orchestration.js.map +1 -0
  67. package/dist/scripts/smoke-qa-ticket-store.d.ts +18 -0
  68. package/dist/scripts/smoke-qa-ticket-store.d.ts.map +1 -0
  69. package/dist/scripts/smoke-qa-ticket-store.js +233 -0
  70. package/dist/scripts/smoke-qa-ticket-store.js.map +1 -0
  71. package/package.json +69 -0
  72. package/prisma/migrations/20260501165631_init/migration.sql +407 -0
  73. package/prisma/migrations/20260503051425_0002_qap018b_qaticket_crosslink_fields/migration.sql +6 -0
  74. package/prisma/migrations/20260504231316_add_project_repofullname_and_webhooksecret/migration.sql +12 -0
  75. package/prisma/migrations/20260504232851_add_qaticket_resolvedby/migration.sql +2 -0
  76. package/prisma/migrations/20260505042646_add_qapattern_qarevert/migration.sql +77 -0
  77. package/prisma/migrations/20260505055826_add_qauniformity_and_agent_trigger/migration.sql +35 -0
  78. package/prisma/migrations/migration_lock.toml +3 -0
  79. package/prisma/schema.prisma +748 -0
  80. package/prisma/seed.ts +181 -0
  81. package/prisma-client/default.d.ts +1 -0
  82. package/prisma-client/default.js +1 -0
  83. package/prisma-client/edge.d.ts +1 -0
  84. package/prisma-client/edge.js +631 -0
  85. package/prisma-client/index-browser.js +615 -0
  86. package/prisma-client/index.d.ts +34509 -0
  87. package/prisma-client/index.js +660 -0
  88. package/prisma-client/libquery_engine-darwin-arm64.dylib.node +0 -0
  89. package/prisma-client/libquery_engine-linux-arm64-openssl-3.0.x.so.node +0 -0
  90. package/prisma-client/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  91. package/prisma-client/package.json +97 -0
  92. package/prisma-client/runtime/edge-esm.js +31 -0
  93. package/prisma-client/runtime/edge.js +31 -0
  94. package/prisma-client/runtime/index-browser.d.ts +365 -0
  95. package/prisma-client/runtime/index-browser.js +13 -0
  96. package/prisma-client/runtime/library.d.ts +3403 -0
  97. package/prisma-client/runtime/library.js +143 -0
  98. package/prisma-client/runtime/react-native.js +80 -0
  99. package/prisma-client/runtime/wasm.js +32 -0
  100. package/prisma-client/schema.prisma +748 -0
  101. package/prisma-client/wasm.d.ts +1 -0
  102. package/prisma-client/wasm.js +615 -0
@@ -0,0 +1,46 @@
1
+ /**
2
+ * createPrismaFixPolicy — Prisma-backed implementation of the SDK FixPolicy
3
+ * contract introduced by QAP-012 / ADR-0014.
4
+ *
5
+ * QAP-013 (Sprint 2). Per Option A (operator-confirmed during scoping):
6
+ *
7
+ * Pure helpers (matchGlob / isPathAllowed / meetsMinSeverity / DEFAULT_AUTO_FIX_CONFIG)
8
+ * live in @derwinjs/core/src/auto-fix/policy-engine.ts. THIS file wires
9
+ * those helpers + Prisma reads + the QAFixAttemptStore daily-cap query
10
+ * into one factory.
11
+ *
12
+ * Sprint 8 extension note: the Policy schema (packages/db/prisma/schema.prisma)
13
+ * gains explicit auto-fix fields in QAP-080..089 — `enabled`, `mode`,
14
+ * `pathAllowlist`, `pathBlocklist`, `minSeverity`. Until then, this impl
15
+ * reads what the schema currently has (`dailyDispatchLimit` from a
16
+ * CONCURRENCY policy row) and falls back to DEFAULT_AUTO_FIX_CONFIG for the
17
+ * rest. The contract surface is stable; only the storage backing the
18
+ * `getConfig` impl will fill in over time.
19
+ *
20
+ * Tenant isolation: every read scopes by projectId; isAutoFixAllowed reaches
21
+ * into the QAFixAttemptStore (which itself is tenant-scoped per QAP-011).
22
+ * Pattern D from docs/testing.md applies — wrong-project lookups return
23
+ * sensible defaults (no enumeration leak), not an error or someone else's
24
+ * data.
25
+ */
26
+ import type { PrismaClient } from './prisma.js';
27
+ import { type AutoFixConfig, type FixPolicy, type QAFixAttemptStore } from '@derwinjs/sdk';
28
+ export interface PrismaFixPolicyConfig {
29
+ /** Generated Prisma client. */
30
+ prisma: PrismaClient;
31
+ /**
32
+ * QAFixAttemptStore for the daily-cap query in isAutoFixAllowed. Same
33
+ * instance the dispatcher uses — sharing prevents two parallel store
34
+ * connections per project.
35
+ */
36
+ attemptStore: QAFixAttemptStore;
37
+ /**
38
+ * Optional override for the platform-wide defaults. Tests use this to pin
39
+ * a specific config without touching the database. Production wiring
40
+ * should leave this undefined; the platform defaults from
41
+ * @derwinjs/core/policy-engine apply.
42
+ */
43
+ defaultConfig?: AutoFixConfig;
44
+ }
45
+ export declare function createPrismaFixPolicy(config: PrismaFixPolicyConfig): FixPolicy;
46
+ //# sourceMappingURL=fix-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix-policy.d.ts","sourceRoot":"","sources":["../src/fix-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,KAAK,aAAa,EAGlB,KAAK,SAAS,EACd,KAAK,iBAAiB,EAEvB,MAAM,eAAe,CAAC;AASvB,MAAM,WAAW,qBAAqB;IACpC,+BAA+B;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB;;;;OAIG;IACH,YAAY,EAAE,iBAAiB,CAAC;IAChC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,SAAS,CA0H9E"}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * createPrismaFixPolicy — Prisma-backed implementation of the SDK FixPolicy
3
+ * contract introduced by QAP-012 / ADR-0014.
4
+ *
5
+ * QAP-013 (Sprint 2). Per Option A (operator-confirmed during scoping):
6
+ *
7
+ * Pure helpers (matchGlob / isPathAllowed / meetsMinSeverity / DEFAULT_AUTO_FIX_CONFIG)
8
+ * live in @derwinjs/core/src/auto-fix/policy-engine.ts. THIS file wires
9
+ * those helpers + Prisma reads + the QAFixAttemptStore daily-cap query
10
+ * into one factory.
11
+ *
12
+ * Sprint 8 extension note: the Policy schema (packages/db/prisma/schema.prisma)
13
+ * gains explicit auto-fix fields in QAP-080..089 — `enabled`, `mode`,
14
+ * `pathAllowlist`, `pathBlocklist`, `minSeverity`. Until then, this impl
15
+ * reads what the schema currently has (`dailyDispatchLimit` from a
16
+ * CONCURRENCY policy row) and falls back to DEFAULT_AUTO_FIX_CONFIG for the
17
+ * rest. The contract surface is stable; only the storage backing the
18
+ * `getConfig` impl will fill in over time.
19
+ *
20
+ * Tenant isolation: every read scopes by projectId; isAutoFixAllowed reaches
21
+ * into the QAFixAttemptStore (which itself is tenant-scoped per QAP-011).
22
+ * Pattern D from docs/testing.md applies — wrong-project lookups return
23
+ * sensible defaults (no enumeration leak), not an error or someone else's
24
+ * data.
25
+ */
26
+ import { DEFAULT_AUTO_FIX_CONFIG, isPathAllowed as pureIsPathAllowed, meetsMinSeverity as pureMeetsMinSeverity, } from '@derwinjs/core';
27
+ // ─── Factory ─────────────────────────────────────────────────────────────
28
+ export function createPrismaFixPolicy(config) {
29
+ const { prisma, attemptStore } = config;
30
+ const defaults = config.defaultConfig ?? DEFAULT_AUTO_FIX_CONFIG;
31
+ return {
32
+ async getConfig(projectId) {
33
+ // Read the CONCURRENCY policy row if it exists. The Policy model
34
+ // (Sprint 1 / QAP-005) currently tracks `dailyDispatchLimit` which
35
+ // maps directly to `maxAttemptsPerDay`. The remaining auto-fix-specific
36
+ // fields land in Sprint 8's Policy expansion; for now they come from
37
+ // defaults.
38
+ //
39
+ // Tenant scope: where { projectId, policyType: 'CONCURRENCY' } —
40
+ // findFirst rather than findUnique because the schema doesn't
41
+ // enforce one-row-per-(project, type) uniqueness yet.
42
+ const concurrencyPolicy = await prisma.policy.findFirst({
43
+ where: { projectId, policyType: 'CONCURRENCY' },
44
+ });
45
+ return {
46
+ ...defaults,
47
+ // Override only the field the schema currently models.
48
+ maxAttemptsPerDay: concurrencyPolicy?.dailyDispatchLimit ?? defaults.maxAttemptsPerDay,
49
+ };
50
+ },
51
+ async isAutoFixAllowed(projectId) {
52
+ const cfg = await this.getConfig(projectId);
53
+ // (1) Master enable gate.
54
+ if (!cfg.enabled) {
55
+ return {
56
+ allowed: false,
57
+ reason: `auto-fix disabled for project ${projectId}`,
58
+ };
59
+ }
60
+ // (2) Daily cap. maxAttemptsPerDay === 0 means "unlimited" (the SDK
61
+ // contract's note); skip the cap check in that case.
62
+ if (cfg.maxAttemptsPerDay > 0) {
63
+ const attemptsToday = await attemptStore.countAttemptsToday({ projectId });
64
+ if (attemptsToday >= cfg.maxAttemptsPerDay) {
65
+ return {
66
+ allowed: false,
67
+ reason: `daily cap reached (${String(attemptsToday)}/${String(cfg.maxAttemptsPerDay)})`,
68
+ };
69
+ }
70
+ }
71
+ return { allowed: true };
72
+ },
73
+ meetsMinSeverity(severity, cfg) {
74
+ // Delegate to the pure helper from @derwinjs/core. Re-exported here
75
+ // through the FixPolicy interface so callers don't need both deps.
76
+ return pureMeetsMinSeverity(severity, cfg);
77
+ },
78
+ isPathAllowed(path, cfg) {
79
+ return pureIsPathAllowed(path, cfg);
80
+ },
81
+ /**
82
+ * Update the project's auto-fix policy. Writes through to the Policy row
83
+ * (CONCURRENCY policyType) for the project, creating it with sensible
84
+ * defaults + operator overrides if absent. The post-write config is
85
+ * returned via getConfig so callers see the same shape they'd see on the
86
+ * next read.
87
+ *
88
+ * Sprint 8 note: the Policy schema does not yet have an `enabled` column
89
+ * (lands in QAP-080..089). Until then, the `enabled` field on the input
90
+ * is type-checked and validated, but silently no-ops at the storage
91
+ * layer. The setConfig return value reflects the post-write state from
92
+ * getConfig, which sources `enabled` from defaults until the schema
93
+ * gains the column.
94
+ */
95
+ async setConfig(projectId, input) {
96
+ validateUpdateInput(input);
97
+ // Read the current row (or null) to know whether we update or create.
98
+ const existing = await prisma.policy.findFirst({
99
+ where: { projectId, policyType: 'CONCURRENCY' },
100
+ });
101
+ if (existing) {
102
+ // Partial update — only fields the input supplies. `enabled` is
103
+ // accepted at the contract layer but no-ops here until the Sprint 8
104
+ // schema lands.
105
+ await prisma.policy.update({
106
+ where: { id: existing.id },
107
+ data: {
108
+ ...(input.maxAttemptsPerDay !== undefined && {
109
+ dailyDispatchLimit: input.maxAttemptsPerDay,
110
+ }),
111
+ updatedBy: input.updatedBy,
112
+ },
113
+ });
114
+ }
115
+ else {
116
+ // Create a new CONCURRENCY policy row with platform defaults +
117
+ // operator-supplied overrides where present.
118
+ await prisma.policy.create({
119
+ data: {
120
+ projectId,
121
+ policyType: 'CONCURRENCY',
122
+ pathRules: [],
123
+ classificationOverrides: {},
124
+ autoMergeTrustThreshold: 70,
125
+ autoMergeMediumThreshold: 85,
126
+ dailyDispatchLimit: input.maxAttemptsPerDay ?? defaults.maxAttemptsPerDay,
127
+ perTicketAttemptLimit: 1,
128
+ freezeWindowsCron: [],
129
+ escalationTriggers: {},
130
+ updatedBy: input.updatedBy,
131
+ },
132
+ });
133
+ }
134
+ // Return the post-write config via the existing getConfig path so
135
+ // callers see the same shape as the next read.
136
+ return this.getConfig(projectId);
137
+ },
138
+ };
139
+ }
140
+ // ─── Validation ───────────────────────────────────────────────────────────
141
+ /**
142
+ * Validate an AutoFixConfigUpdateInput. Throws plain Error with a
143
+ * recognizable 'FixPolicy.setConfig:' prefix — matching the existing
144
+ * FixPolicy convention of not defining a tagged error class. If FixPolicy
145
+ * gains store-style errors later (Sprint 8), this can be migrated.
146
+ */
147
+ function validateUpdateInput(input) {
148
+ if (typeof input.updatedBy !== 'string' || input.updatedBy.trim() === '') {
149
+ throw new Error('FixPolicy.setConfig: updatedBy is required');
150
+ }
151
+ if (input.maxAttemptsPerDay !== undefined) {
152
+ if (typeof input.maxAttemptsPerDay !== 'number' ||
153
+ !Number.isInteger(input.maxAttemptsPerDay) ||
154
+ input.maxAttemptsPerDay < 0) {
155
+ throw new Error('FixPolicy.setConfig: maxAttemptsPerDay must be a non-negative integer');
156
+ }
157
+ }
158
+ if (input.enabled !== undefined && typeof input.enabled !== 'boolean') {
159
+ throw new Error('FixPolicy.setConfig: enabled must be a boolean');
160
+ }
161
+ }
162
+ //# sourceMappingURL=fix-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix-policy.js","sourceRoot":"","sources":["../src/fix-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAWH,OAAO,EACL,uBAAuB,EACvB,aAAa,IAAI,iBAAiB,EAClC,gBAAgB,IAAI,oBAAoB,GACzC,MAAM,gBAAgB,CAAC;AAsBxB,4EAA4E;AAE5E,MAAM,UAAU,qBAAqB,CAAC,MAA6B;IACjE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;IACxC,MAAM,QAAQ,GAAkB,MAAM,CAAC,aAAa,IAAI,uBAAuB,CAAC;IAEhF,OAAO;QACL,KAAK,CAAC,SAAS,CAAC,SAAiB;YAC/B,iEAAiE;YACjE,mEAAmE;YACnE,wEAAwE;YACxE,qEAAqE;YACrE,YAAY;YACZ,EAAE;YACF,iEAAiE;YACjE,8DAA8D;YAC9D,sDAAsD;YACtD,MAAM,iBAAiB,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;gBACtD,KAAK,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE;aAChD,CAAC,CAAC;YAEH,OAAO;gBACL,GAAG,QAAQ;gBACX,uDAAuD;gBACvD,iBAAiB,EAAE,iBAAiB,EAAE,kBAAkB,IAAI,QAAQ,CAAC,iBAAiB;aACvF,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,gBAAgB,CAAC,SAAiB;YACtC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YAE5C,0BAA0B;YAC1B,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;gBACjB,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,iCAAiC,SAAS,EAAE;iBACrD,CAAC;YACJ,CAAC;YAED,oEAAoE;YACpE,qDAAqD;YACrD,IAAI,GAAG,CAAC,iBAAiB,GAAG,CAAC,EAAE,CAAC;gBAC9B,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC3E,IAAI,aAAa,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC;oBAC3C,OAAO;wBACL,OAAO,EAAE,KAAK;wBACd,MAAM,EAAE,sBAAsB,MAAM,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG;qBACxF,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAED,gBAAgB,CAAC,QAAkB,EAAE,GAAkB;YACrD,oEAAoE;YACpE,mEAAmE;YACnE,OAAO,oBAAoB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC;QAED,aAAa,CAAC,IAAY,EAAE,GAAkB;YAC5C,OAAO,iBAAiB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACtC,CAAC;QAED;;;;;;;;;;;;;WAaG;QACH,KAAK,CAAC,SAAS,CAAC,SAAiB,EAAE,KAA+B;YAChE,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAE3B,sEAAsE;YACtE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;gBAC7C,KAAK,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE;aAChD,CAAC,CAAC;YAEH,IAAI,QAAQ,EAAE,CAAC;gBACb,gEAAgE;gBAChE,oEAAoE;gBACpE,gBAAgB;gBAChB,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;oBACzB,KAAK,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE;oBAC1B,IAAI,EAAE;wBACJ,GAAG,CAAC,KAAK,CAAC,iBAAiB,KAAK,SAAS,IAAI;4BAC3C,kBAAkB,EAAE,KAAK,CAAC,iBAAiB;yBAC5C,CAAC;wBACF,SAAS,EAAE,KAAK,CAAC,SAAS;qBAC3B;iBACF,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,+DAA+D;gBAC/D,6CAA6C;gBAC7C,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;oBACzB,IAAI,EAAE;wBACJ,SAAS;wBACT,UAAU,EAAE,aAAa;wBACzB,SAAS,EAAE,EAAE;wBACb,uBAAuB,EAAE,EAAE;wBAC3B,uBAAuB,EAAE,EAAE;wBAC3B,wBAAwB,EAAE,EAAE;wBAC5B,kBAAkB,EAAE,KAAK,CAAC,iBAAiB,IAAI,QAAQ,CAAC,iBAAiB;wBACzE,qBAAqB,EAAE,CAAC;wBACxB,iBAAiB,EAAE,EAAE;wBACrB,kBAAkB,EAAE,EAAE;wBACtB,SAAS,EAAE,KAAK,CAAC,SAAS;qBAC3B;iBACF,CAAC,CAAC;YACL,CAAC;YAED,kEAAkE;YAClE,+CAA+C;YAC/C,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACnC,CAAC;KACF,CAAC;AACJ,CAAC;AAED,6EAA6E;AAE7E;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,KAA+B;IAC1D,IAAI,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACzE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,KAAK,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;QAC1C,IACE,OAAO,KAAK,CAAC,iBAAiB,KAAK,QAAQ;YAC3C,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,iBAAiB,CAAC;YAC1C,KAAK,CAAC,iBAAiB,GAAG,CAAC,EAC3B,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;AACH,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @derwinjs/db — Prisma schema + generated client + storage implementations.
3
+ *
4
+ * Schema lives at `packages/db/prisma/schema.prisma` (added in QAP-005).
5
+ * Models per technical spec §3 plus Sprint 2 additions (crossLinkRefs +
6
+ * dashboardUrl on QATicket per ADR-0008).
7
+ *
8
+ * Project-namespaced — every project-scoped table has projectId FK to Project.
9
+ * pgvector for RAG corpus embeddings (technical spec §14 Q2 / ADR-0007 — switch
10
+ * lands at Sprint 4 / QAP-040..047 with Profile-v0 ingestion).
11
+ *
12
+ * Storage implementations exposed here implement contracts defined in
13
+ * @derwinjs/sdk. configureQAPlatform wires them in based on the consumer's
14
+ * configuration. Today: QATicketStore (QAP-018B). More land per sprint.
15
+ */
16
+ export declare const PACKAGE_NAME: "@derwinjs/db";
17
+ export { createPrismaQATicketStore, type PrismaQATicketStoreConfig } from './qa-ticket-store.js';
18
+ export { createPrismaQAFixAttemptStore, type PrismaQAFixAttemptStoreConfig, } from './qa-fix-attempt-store.js';
19
+ export { createPrismaQARunStore, type PrismaQARunStoreConfig } from './qa-run-store.js';
20
+ export { createPrismaQAPatternStore, type PrismaQAPatternStoreConfig } from './qa-pattern-store.js';
21
+ export { createPrismaQARevertStore, type PrismaQARevertStoreConfig } from './qa-revert-store.js';
22
+ export { createPrismaQAUniformityStore, type PrismaQAUniformityStoreConfig, } from './qa-uniformity-store.js';
23
+ export { createPrismaAgentFindingsIngestor, type PrismaAgentFindingsIngestorConfig, } from './agent-findings-ingestor.js';
24
+ export { createPrismaLearningHealthReporter, type PrismaLearningHealthReporterConfig, } from './learning-health-reporter.js';
25
+ export { createPrismaCoverageGapReporter, type PrismaCoverageGapReporterConfig, } from './coverage-gap-reporter.js';
26
+ export * from './prisma.js';
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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;AA4BpC,cAAc,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @derwinjs/db — Prisma schema + generated client + storage implementations.
3
+ *
4
+ * Schema lives at `packages/db/prisma/schema.prisma` (added in QAP-005).
5
+ * Models per technical spec §3 plus Sprint 2 additions (crossLinkRefs +
6
+ * dashboardUrl on QATicket per ADR-0008).
7
+ *
8
+ * Project-namespaced — every project-scoped table has projectId FK to Project.
9
+ * pgvector for RAG corpus embeddings (technical spec §14 Q2 / ADR-0007 — switch
10
+ * lands at Sprint 4 / QAP-040..047 with Profile-v0 ingestion).
11
+ *
12
+ * Storage implementations exposed here implement contracts defined in
13
+ * @derwinjs/sdk. configureQAPlatform wires them in based on the consumer's
14
+ * configuration. Today: QATicketStore (QAP-018B). More land per sprint.
15
+ */
16
+ export const PACKAGE_NAME = '@derwinjs/db';
17
+ // ─── Storage implementations ─────────────────────────────────────────────
18
+ export { createPrismaQATicketStore } from './qa-ticket-store.js';
19
+ export { createPrismaQAFixAttemptStore, } from './qa-fix-attempt-store.js';
20
+ export { createPrismaQARunStore } from './qa-run-store.js';
21
+ export { createPrismaQAPatternStore } from './qa-pattern-store.js';
22
+ export { createPrismaQARevertStore } from './qa-revert-store.js';
23
+ export { createPrismaQAUniformityStore, } from './qa-uniformity-store.js';
24
+ export { createPrismaAgentFindingsIngestor, } from './agent-findings-ingestor.js';
25
+ export { createPrismaLearningHealthReporter, } from './learning-health-reporter.js';
26
+ export { createPrismaCoverageGapReporter, } from './coverage-gap-reporter.js';
27
+ // ─── Prisma client re-export ─────────────────────────────────────────────
28
+ //
29
+ // @derwinjs/db ships its OWN generated Prisma client (output: prisma-client/
30
+ // per the schema's generator block). Consumers MUST import PrismaClient
31
+ // from here, NOT from @prisma/client — see src/prisma.ts for the full
32
+ // rationale. Each Derwin consumer (Lifeline, Side Piece, Bolt, ...) has
33
+ // its own @prisma/client generated against its own schema; @derwinjs/db
34
+ // can't piggyback on it without breaking types.
35
+ //
36
+ // What's re-exported (full surface from the generated client):
37
+ // - PrismaClient — instantiate with { datasources: { db: { url } }} and
38
+ // pass to the store factories above.
39
+ // - Prisma — namespace containing PrismaClientKnownRequestError, validators,
40
+ // input/output types per model, etc.
41
+ // - All enums from the schema: ProjectType, ProjectMode, RunTrigger,
42
+ // RunStatus, AttemptStatus, TicketStatus, ReviewBucket, RiskTier,
43
+ // Severity, SurfaceCategory, QAPatternStatus, QAFailureClass,
44
+ // QAUniformityStatus, etc.
45
+ //
46
+ // Consumer pattern:
47
+ // import { PrismaClient, ProjectType } from '@derwinjs/db';
48
+ // const derwinPrisma = new PrismaClient({
49
+ // datasources: { db: { url: process.env.DERWIN_DATABASE_URL } },
50
+ // });
51
+ // await derwinPrisma.project.upsert({ ... });
52
+ export * from './prisma.js';
53
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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;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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * LearningHealthReporter — Prisma-backed aggregate reader over QAFixAttempt
3
+ * + QAPattern for the dashboard's "Learning Health" widget.
4
+ *
5
+ * QAP-019F (Sprint 2 Group D-3, Commit 3). Implements the
6
+ * LearningHealthReporter contract from @derwinjs/sdk. Migrated from
7
+ * Lifeline's GET /api/qa/learning-health route. No new schema — pure
8
+ * aggregate read.
9
+ *
10
+ * Response field names + null semantics mirror Lifeline so the QAP-019G
11
+ * shim is a 1:1 mapping. Five metrics:
12
+ * - mergedWithoutEditsPercent (humanEditLines === 0 share of merges)
13
+ * - regressionRatePercent (regressionDetected share of merges)
14
+ * - topImprovingClassifications (top-5 QAPatterns by fixSuccessScore,
15
+ * filtered to fixOutcomeSampleSize >= 3)
16
+ * - patternsWithSamples (count of QAPatterns with fixOutcomeSampleSize > 0)
17
+ * - dryRunOnlyFailureRatePercent (PRE_VERIFY_PASSED share of dispatches)
18
+ *
19
+ * **Schema mapping under Option β** (Lifeline → Derwin):
20
+ * - Lifeline `status: 'MERGED'` → Derwin `dispatchStatus IN
21
+ * ('AUTO_MERGED', 'HUMAN_MERGED')` (Lifeline's single MERGED is split
22
+ * in Derwin's AttemptStatus enum).
23
+ * - Lifeline `status: 'DRY_RUN_LOGGED'` → Derwin
24
+ * `dispatchStatus = 'PRE_VERIFY_PASSED'` (the closest equivalent —
25
+ * pre-verify ran successfully but operator never escalated to PR).
26
+ * - Lifeline `outcomeRecordedAt` → Derwin `mergedAt` (timestamp on
27
+ * merged attempts).
28
+ * - Lifeline `QAPatternInsight` → Derwin `QAPattern` (D-2 rename).
29
+ */
30
+ import type { PrismaClient } from './prisma.js';
31
+ import { type LearningHealthReporter } from '@derwinjs/sdk';
32
+ export interface PrismaLearningHealthReporterConfig {
33
+ /** Generated Prisma client. Pass an instance per process. */
34
+ prisma: PrismaClient;
35
+ }
36
+ export declare function createPrismaLearningHealthReporter(config: PrismaLearningHealthReporterConfig): LearningHealthReporter;
37
+ //# sourceMappingURL=learning-health-reporter.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * LearningHealthReporter — Prisma-backed aggregate reader over QAFixAttempt
3
+ * + QAPattern for the dashboard's "Learning Health" widget.
4
+ *
5
+ * QAP-019F (Sprint 2 Group D-3, Commit 3). Implements the
6
+ * LearningHealthReporter contract from @derwinjs/sdk. Migrated from
7
+ * Lifeline's GET /api/qa/learning-health route. No new schema — pure
8
+ * aggregate read.
9
+ *
10
+ * Response field names + null semantics mirror Lifeline so the QAP-019G
11
+ * shim is a 1:1 mapping. Five metrics:
12
+ * - mergedWithoutEditsPercent (humanEditLines === 0 share of merges)
13
+ * - regressionRatePercent (regressionDetected share of merges)
14
+ * - topImprovingClassifications (top-5 QAPatterns by fixSuccessScore,
15
+ * filtered to fixOutcomeSampleSize >= 3)
16
+ * - patternsWithSamples (count of QAPatterns with fixOutcomeSampleSize > 0)
17
+ * - dryRunOnlyFailureRatePercent (PRE_VERIFY_PASSED share of dispatches)
18
+ *
19
+ * **Schema mapping under Option β** (Lifeline → Derwin):
20
+ * - Lifeline `status: 'MERGED'` → Derwin `dispatchStatus IN
21
+ * ('AUTO_MERGED', 'HUMAN_MERGED')` (Lifeline's single MERGED is split
22
+ * in Derwin's AttemptStatus enum).
23
+ * - Lifeline `status: 'DRY_RUN_LOGGED'` → Derwin
24
+ * `dispatchStatus = 'PRE_VERIFY_PASSED'` (the closest equivalent —
25
+ * pre-verify ran successfully but operator never escalated to PR).
26
+ * - Lifeline `outcomeRecordedAt` → Derwin `mergedAt` (timestamp on
27
+ * merged attempts).
28
+ * - Lifeline `QAPatternInsight` → Derwin `QAPattern` (D-2 rename).
29
+ */
30
+ import { LearningHealthReporterError, } from '@derwinjs/sdk';
31
+ // ─── Constants (Lifeline parity) ─────────────────────────────────────────
32
+ const DEFAULT_WINDOW_DAYS = 30;
33
+ const TOP_PATTERNS_LIMIT = 5;
34
+ const MIN_SAMPLE_SIZE = 3; // pattern threshold below which trend is too noisy
35
+ // ─── Factory ─────────────────────────────────────────────────────────────
36
+ export function createPrismaLearningHealthReporter(config) {
37
+ const { prisma } = config;
38
+ return {
39
+ async getLearningHealth(filter) {
40
+ validateFilter(filter);
41
+ const windowDays = filter.windowDays ?? DEFAULT_WINDOW_DAYS;
42
+ const windowStart = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1000);
43
+ // ─── 1. Merged-attempt sample (clean-merge + regression rates) ────
44
+ const mergedAttempts = await prisma.qAFixAttempt.findMany({
45
+ where: {
46
+ projectId: filter.projectId,
47
+ dispatchStatus: { in: ['AUTO_MERGED', 'HUMAN_MERGED'] },
48
+ mergedAt: { gte: windowStart },
49
+ },
50
+ select: { humanEditLines: true, regressionDetected: true },
51
+ });
52
+ const sampleSize = mergedAttempts.length;
53
+ let mergedWithoutEditsPercent = null;
54
+ let regressionRatePercent = null;
55
+ if (sampleSize > 0) {
56
+ const cleanMerges = mergedAttempts.filter((a) => a.humanEditLines === 0).length;
57
+ mergedWithoutEditsPercent = Math.round((cleanMerges / sampleSize) * 100);
58
+ const regressions = mergedAttempts.filter((a) => a.regressionDetected).length;
59
+ regressionRatePercent = Math.round((regressions / sampleSize) * 100);
60
+ }
61
+ // ─── 2. Top-improving classifications ──────────────────────────────
62
+ const patterns = await prisma.qAPattern.findMany({
63
+ where: {
64
+ projectId: filter.projectId,
65
+ fixOutcomeSampleSize: { gte: MIN_SAMPLE_SIZE },
66
+ fixSuccessScore: { not: null },
67
+ },
68
+ orderBy: { fixSuccessScore: 'desc' },
69
+ take: TOP_PATTERNS_LIMIT,
70
+ select: {
71
+ classification: true,
72
+ fixSuccessScore: true,
73
+ fixOutcomeSampleSize: true,
74
+ },
75
+ });
76
+ const topImprovingClassifications = patterns.map((p) => ({
77
+ 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,
81
+ sampleSize: p.fixOutcomeSampleSize,
82
+ }));
83
+ // ─── 3. Patterns with samples (transparency metric) ────────────────
84
+ const patternsWithSamples = await prisma.qAPattern.count({
85
+ where: {
86
+ projectId: filter.projectId,
87
+ fixOutcomeSampleSize: { gt: 0 },
88
+ },
89
+ });
90
+ // ─── 4. Dry-run-only failure rate ──────────────────────────────────
91
+ //
92
+ // Counts in the same time window. Lifeline parity: numerator counts
93
+ // attempts stuck at PRE_VERIFY_PASSED (Derwin's closest analog to
94
+ // DRY_RUN_LOGGED); denominator counts those plus everything that
95
+ // moved past — PR_OPENED + the merged + REJECTED final states.
96
+ const dryRunCount = await prisma.qAFixAttempt.count({
97
+ where: {
98
+ projectId: filter.projectId,
99
+ dispatchStatus: 'PRE_VERIFY_PASSED',
100
+ attemptedAt: { gte: windowStart },
101
+ },
102
+ });
103
+ const prCount = await prisma.qAFixAttempt.count({
104
+ where: {
105
+ projectId: filter.projectId,
106
+ dispatchStatus: { in: ['PR_OPENED', 'AUTO_MERGED', 'HUMAN_MERGED', 'REJECTED'] },
107
+ attemptedAt: { gte: windowStart },
108
+ },
109
+ });
110
+ const totalDispatches = dryRunCount + prCount;
111
+ let dryRunOnlyFailureRatePercent = null;
112
+ if (totalDispatches > 0) {
113
+ dryRunOnlyFailureRatePercent = Math.round((dryRunCount / totalDispatches) * 100);
114
+ }
115
+ return {
116
+ windowDays,
117
+ sampleSize,
118
+ mergedWithoutEditsPercent,
119
+ regressionRatePercent,
120
+ topImprovingClassifications,
121
+ patternsWithSamples,
122
+ dryRunOnlyFailureRatePercent,
123
+ };
124
+ },
125
+ };
126
+ }
127
+ // ─── Validation ──────────────────────────────────────────────────────────
128
+ function validateFilter(filter) {
129
+ if (typeof filter.projectId !== 'string' || filter.projectId.length === 0) {
130
+ throw new LearningHealthReporterError('invalid_input', 'LearningHealthReporter: projectId is required');
131
+ }
132
+ if (filter.windowDays !== undefined) {
133
+ if (typeof filter.windowDays !== 'number' || !Number.isFinite(filter.windowDays)) {
134
+ throw new LearningHealthReporterError('invalid_input', 'LearningHealthReporter: windowDays must be a finite number');
135
+ }
136
+ if (filter.windowDays < 1) {
137
+ throw new LearningHealthReporterError('invalid_input', 'LearningHealthReporter: windowDays must be >= 1');
138
+ }
139
+ }
140
+ }
141
+ //# sourceMappingURL=learning-health-reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-health-reporter.js","sourceRoot":"","sources":["../src/learning-health-reporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @derwinjs/db internal re-export of the generated Prisma client.
3
+ *
4
+ * The Prisma generator emits to `packages/db/prisma-client/` (see
5
+ * `prisma/schema.prisma`'s `generator client { output = "../prisma-client" }`
6
+ * directive). This file is the single internal entrypoint for that
7
+ * generated module — every store factory inside @derwinjs/db imports
8
+ * `Prisma` and `PrismaClient` from here instead of from `@prisma/client`.
9
+ *
10
+ * **Why a Derwin-owned PrismaClient (not @prisma/client)?**
11
+ *
12
+ * Each Derwin consumer (Lifeline, Side Piece, Bolt, Financial Analyzer,
13
+ * Shackbox, Home Remodeler, Patient Communications Hub) has its own
14
+ * Prisma schema and its own generated client at `node_modules/@prisma/client`
15
+ * for ITS OWN tables. If @derwinjs/db imported `PrismaClient` from
16
+ * `@prisma/client`, consumers' tsc would resolve that to the consumer's
17
+ * client — which doesn't have Derwin's models (qAUniformity, qARun, etc).
18
+ * Type-check would fail; runtime would fail.
19
+ *
20
+ * By owning the generated client inside @derwinjs/db, we get a Derwin-shaped
21
+ * `PrismaClient` that ships in the published tarball alongside the rest
22
+ * of `dist/`. Consumers can safely instantiate `new PrismaClient(...)`
23
+ * pointed at `DERWIN_DATABASE_URL` and pass it to Derwin's store
24
+ * factories without type collisions.
25
+ *
26
+ * Consumers should import `PrismaClient` from `@derwinjs/db` (which
27
+ * re-exports it from this module) — never from `@prisma/client` for
28
+ * Derwin queries.
29
+ */
30
+ export * from '../prisma-client/index.js';
31
+ //# sourceMappingURL=prisma.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma.d.ts","sourceRoot":"","sources":["../src/prisma.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,cAAc,2BAA2B,CAAC"}
package/dist/prisma.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @derwinjs/db internal re-export of the generated Prisma client.
3
+ *
4
+ * The Prisma generator emits to `packages/db/prisma-client/` (see
5
+ * `prisma/schema.prisma`'s `generator client { output = "../prisma-client" }`
6
+ * directive). This file is the single internal entrypoint for that
7
+ * generated module — every store factory inside @derwinjs/db imports
8
+ * `Prisma` and `PrismaClient` from here instead of from `@prisma/client`.
9
+ *
10
+ * **Why a Derwin-owned PrismaClient (not @prisma/client)?**
11
+ *
12
+ * Each Derwin consumer (Lifeline, Side Piece, Bolt, Financial Analyzer,
13
+ * Shackbox, Home Remodeler, Patient Communications Hub) has its own
14
+ * Prisma schema and its own generated client at `node_modules/@prisma/client`
15
+ * for ITS OWN tables. If @derwinjs/db imported `PrismaClient` from
16
+ * `@prisma/client`, consumers' tsc would resolve that to the consumer's
17
+ * client — which doesn't have Derwin's models (qAUniformity, qARun, etc).
18
+ * Type-check would fail; runtime would fail.
19
+ *
20
+ * By owning the generated client inside @derwinjs/db, we get a Derwin-shaped
21
+ * `PrismaClient` that ships in the published tarball alongside the rest
22
+ * of `dist/`. Consumers can safely instantiate `new PrismaClient(...)`
23
+ * pointed at `DERWIN_DATABASE_URL` and pass it to Derwin's store
24
+ * factories without type collisions.
25
+ *
26
+ * Consumers should import `PrismaClient` from `@derwinjs/db` (which
27
+ * re-exports it from this module) — never from `@prisma/client` for
28
+ * Derwin queries.
29
+ */
30
+ export * from '../prisma-client/index.js';
31
+ //# sourceMappingURL=prisma.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma.js","sourceRoot":"","sources":["../src/prisma.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * QAFixAttemptStore — Prisma implementation against Derwin's QAFixAttempt table.
3
+ *
4
+ * QAP-011 (Sprint 2). Implements the QAFixAttemptStore contract from
5
+ * @derwinjs/sdk (see packages/sdk/src/types/qa-fix-attempt-store.ts) against
6
+ * the @derwinjs/db Prisma client. Mirrors createPrismaQATicketStore in
7
+ * structure: a factory taking `{ prisma }` so callers inject the client
8
+ * (per the architecture pivot's DI seam — @derwinjs/db owns persistence; the
9
+ * orchestrator wires it in via configureQAPlatform()).
10
+ *
11
+ * Tenant isolation: every method scopes by projectId in the WHERE clause.
12
+ * App-layer guards in Sprint 2 ahead of the full Supabase RLS migration
13
+ * (Sprint 3 / QAP-024). The negative path (wrong-project read) returns
14
+ * null / throws not_found rather than the wrong tenant's row — defense in
15
+ * depth against tenant enumeration.
16
+ *
17
+ * Composes with QATicketStore: a ticket id is the qaTicketId FK; the store
18
+ * does NOT validate the ticket exists pre-insert (Prisma's P2003 surfaces
19
+ * FK violations consistently).
20
+ */
21
+ import { type PrismaClient } from './prisma.js';
22
+ import { type QAFixAttemptStore } from '@derwinjs/sdk';
23
+ export interface PrismaQAFixAttemptStoreConfig {
24
+ /** Generated Prisma client. Pass an instance per process. */
25
+ prisma: PrismaClient;
26
+ }
27
+ export declare function createPrismaQAFixAttemptStore(config: PrismaQAFixAttemptStoreConfig): QAFixAttemptStore;
28
+ //# sourceMappingURL=qa-fix-attempt-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-fix-attempt-store.d.ts","sourceRoot":"","sources":["../src/qa-fix-attempt-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAOL,KAAK,iBAAiB,EACvB,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,6BAA6B;IAC5C,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AAID,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,6BAA6B,GACpC,iBAAiB,CA0MnB"}