@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,375 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * QAP-014 / QAP-015 smoke — exercises the OutcomeRecorder + TrustScoreUpdater
4
+ * + ranker against the real local Postgres. Parity reference: Lifeline's
5
+ * scripts/qa-learning-backfill.ts (QLL-035).
6
+ *
7
+ * Run: pnpm --filter @derwinjs/db smoke:learning-loop
8
+ *
9
+ * Prereqs:
10
+ * - Local Postgres running on port 5433 (per Sprint 1 docker setup)
11
+ * - DATABASE_URL set in packages/db/.env
12
+ * - Migrations applied
13
+ * - Seed run (Lifeline project exists at slug='lifeline')
14
+ *
15
+ * Self-cleaning: deletes its own test rows in a finally block. Re-runs
16
+ * idempotently.
17
+ *
18
+ * Prints "QAP-014/015 LEARNING LOOP READY ✓" on success. Exits 1 on failure.
19
+ */
20
+ import { PrismaClient } from '../prisma.js';
21
+ import { createOutcomeRecorder, createTrustScoreUpdater, rankCandidates, } from '@derwinjs/core';
22
+ import { createPrismaQATicketStore } from '../qa-ticket-store.js';
23
+ import { createPrismaQAFixAttemptStore } from '../qa-fix-attempt-store.js';
24
+ import { createPrismaClassificationTrustStore } from '../classification-trust-store.js';
25
+ const SMOKE_MARKER = '[SMOKE-QAP-015]';
26
+ const DASHBOARD_BASE_URL = 'http://localhost:3000';
27
+ const prisma = new PrismaClient();
28
+ const ticketStore = createPrismaQATicketStore({ prisma, dashboardBaseUrl: DASHBOARD_BASE_URL });
29
+ const attemptStore = createPrismaQAFixAttemptStore({ prisma });
30
+ const trustStore = createPrismaClassificationTrustStore({ prisma });
31
+ let createdRunId;
32
+ const createdTicketIds = [];
33
+ const createdAttemptIds = [];
34
+ let lifelineProjectId;
35
+ const seededTickets = [];
36
+ async function main() {
37
+ // ─── Setup: find Lifeline + create synthetic QARun + 6 tickets + 6 attempts ─
38
+ const lifeline = await prisma.project.findUnique({ where: { slug: 'lifeline' } });
39
+ if (!lifeline) {
40
+ throw new Error('Lifeline project not found. Run `pnpm db:seed` first.');
41
+ }
42
+ lifelineProjectId = lifeline.id;
43
+ console.log(`✓ Found Lifeline (id=${lifeline.id})`);
44
+ const run = await prisma.qARun.create({
45
+ data: {
46
+ projectId: lifeline.id,
47
+ triggeredBy: SMOKE_MARKER,
48
+ triggerType: 'OPERATOR_ON_DEMAND',
49
+ scope: { specs: ['smoke/learning-loop.spec.ts'], note: SMOKE_MARKER },
50
+ signalsRaised: 6,
51
+ ticketsCreated: 6,
52
+ },
53
+ });
54
+ createdRunId = run.id;
55
+ console.log(`✓ Created synthetic QARun (id=${run.id})`);
56
+ // Create 6 tickets: 3 PRODUCT_BUG/UI_UX_INTEGRITY + 3 SELECTOR/UI_UX_INTEGRITY.
57
+ for (let i = 0; i < 3; i++) {
58
+ const t = await ticketStore.createQATicket({
59
+ projectId: lifeline.id,
60
+ qaRunId: run.id,
61
+ title: `${SMOKE_MARKER} PRODUCT_BUG ticket ${String(i + 1)}`,
62
+ surface: 'UI_UX_INTEGRITY',
63
+ classification: 'PRODUCT_BUG',
64
+ severity: 'HIGH',
65
+ riskTier: 'HIGH',
66
+ reproSteps: [{ step: 1, action: 'smoke step' }],
67
+ suspectedRootCause: 'smoke',
68
+ blastRadius: { affectedFiles: [], affectedTests: [], affectedPages: [] },
69
+ proposedFixApproach: 'smoke fix',
70
+ });
71
+ createdTicketIds.push(t.ticket.id);
72
+ seededTickets.push({ id: t.ticket.id, classification: 'PRODUCT_BUG' });
73
+ }
74
+ for (let i = 0; i < 3; i++) {
75
+ const t = await ticketStore.createQATicket({
76
+ projectId: lifeline.id,
77
+ qaRunId: run.id,
78
+ title: `${SMOKE_MARKER} SELECTOR ticket ${String(i + 1)}`,
79
+ surface: 'UI_UX_INTEGRITY',
80
+ classification: 'SELECTOR',
81
+ severity: 'MEDIUM',
82
+ riskTier: 'MEDIUM',
83
+ reproSteps: [{ step: 1, action: 'smoke step' }],
84
+ suspectedRootCause: 'smoke',
85
+ blastRadius: { affectedFiles: [], affectedTests: [], affectedPages: [] },
86
+ proposedFixApproach: 'smoke fix',
87
+ });
88
+ createdTicketIds.push(t.ticket.id);
89
+ seededTickets.push({ id: t.ticket.id, classification: 'SELECTOR' });
90
+ }
91
+ console.log(`✓ Created 6 tickets (3 PRODUCT_BUG + 3 SELECTOR, all UI_UX_INTEGRITY)`);
92
+ // Create 6 attempts with predetermined outcomes — pre-scored so the updater
93
+ // picks them up directly (bypassing OutcomeRecorder; that's a separate step
94
+ // below). All within last 7 days so they fall inside the 30-day rolling
95
+ // window used by TrustScoreUpdater.
96
+ const now = Date.now();
97
+ const recentMergedAt = new Date(now - 3 * 86_400_000); // 3 days ago
98
+ const productBugOutcomes = [
99
+ { type: 'mergedClean' },
100
+ { type: 'mergedClean' },
101
+ { type: 'mergedWithEdits', humanEditLines: 15 },
102
+ ];
103
+ const selectorOutcomes = [
104
+ { type: 'mergedClean' },
105
+ { type: 'regressed' },
106
+ { type: 'reverted' },
107
+ ];
108
+ const productBugTickets = seededTickets.filter((t) => t.classification === 'PRODUCT_BUG');
109
+ const selectorTickets = seededTickets.filter((t) => t.classification === 'SELECTOR');
110
+ // Zip ticket + outcome arrays — each entry is { ticket, outcome, idx }.
111
+ const productBugSeed = productBugTickets.map((ticket, idx) => ({
112
+ ticket,
113
+ outcome: productBugOutcomes[idx],
114
+ idx,
115
+ }));
116
+ for (const { ticket, outcome, idx } of productBugSeed) {
117
+ if (!outcome)
118
+ continue;
119
+ await seedAttempt(ticket.id, outcome, recentMergedAt, lifeline.id, idx);
120
+ }
121
+ const selectorSeed = selectorTickets.map((ticket, idx) => ({
122
+ ticket,
123
+ outcome: selectorOutcomes[idx],
124
+ idx,
125
+ }));
126
+ for (const { ticket, outcome, idx } of selectorSeed) {
127
+ if (!outcome)
128
+ continue;
129
+ await seedAttempt(ticket.id, outcome, recentMergedAt, lifeline.id, idx);
130
+ }
131
+ console.log(`✓ Seeded 6 attempts with pre-scored outcomes`);
132
+ // ─── Step 1: Run TrustScoreUpdater ─────────────────────────────────
133
+ console.log('--- Step 1: TrustScoreUpdater ---');
134
+ const updater = createTrustScoreUpdater({ attemptStore, ticketStore, trustStore });
135
+ const updateResult = await updater.recomputeAll({ projectId: lifeline.id });
136
+ console.log(` classificationsUpdated=${String(updateResult.classificationsUpdated)}`);
137
+ console.log(` perClassificationCounts=${JSON.stringify(updateResult.perClassificationCounts)}`);
138
+ if (updateResult.classificationsUpdated !== 2) {
139
+ throw new Error(`Expected classificationsUpdated=2, got ${String(updateResult.classificationsUpdated)}`);
140
+ }
141
+ // Verify the rows landed correctly.
142
+ const pbRow = await trustStore.getTrust({
143
+ projectId: lifeline.id,
144
+ classification: 'PRODUCT_BUG',
145
+ surface: 'UI_UX_INTEGRITY',
146
+ });
147
+ if (!pbRow)
148
+ throw new Error('PRODUCT_BUG/UI_UX_INTEGRITY trust row missing after upsert');
149
+ // Expected: mergedClean=2, mergedWithEdits=1, regressed=0, reverted=0, total=3
150
+ // weightedSum = 2 + 0.5 = 2.5; successScore ≈ 0.833; trustPercent = round(91.667) = 92
151
+ if (pbRow.mergedClean !== 2 ||
152
+ pbRow.mergedWithEdits !== 1 ||
153
+ pbRow.regressed !== 0 ||
154
+ pbRow.reverted !== 0) {
155
+ throw new Error(`PRODUCT_BUG bucket counts wrong: ${JSON.stringify({
156
+ mergedClean: pbRow.mergedClean,
157
+ mergedWithEdits: pbRow.mergedWithEdits,
158
+ regressed: pbRow.regressed,
159
+ reverted: pbRow.reverted,
160
+ })}`);
161
+ }
162
+ if (pbRow.trustPercent !== 92) {
163
+ throw new Error(`PRODUCT_BUG trustPercent expected 92, got ${String(pbRow.trustPercent)}`);
164
+ }
165
+ console.log(` ✓ PRODUCT_BUG: mergedClean=2, mergedWithEdits=1, trustPercent=${String(pbRow.trustPercent)}`);
166
+ const selRow = await trustStore.getTrust({
167
+ projectId: lifeline.id,
168
+ classification: 'SELECTOR',
169
+ surface: 'UI_UX_INTEGRITY',
170
+ });
171
+ if (!selRow)
172
+ throw new Error('SELECTOR/UI_UX_INTEGRITY trust row missing after upsert');
173
+ // Expected: mergedClean=1, mergedWithEdits=0, regressed=1, reverted=1, total=3
174
+ // weightedSum = 1 - 0.5 - 1 = -0.5; successScore ≈ -0.167; trustPercent = round(41.667) = 42
175
+ if (selRow.mergedClean !== 1 ||
176
+ selRow.mergedWithEdits !== 0 ||
177
+ selRow.regressed !== 1 ||
178
+ selRow.reverted !== 1) {
179
+ throw new Error(`SELECTOR bucket counts wrong: ${JSON.stringify({
180
+ mergedClean: selRow.mergedClean,
181
+ mergedWithEdits: selRow.mergedWithEdits,
182
+ regressed: selRow.regressed,
183
+ reverted: selRow.reverted,
184
+ })}`);
185
+ }
186
+ if (selRow.trustPercent !== 42) {
187
+ throw new Error(`SELECTOR trustPercent expected 42, got ${String(selRow.trustPercent)}`);
188
+ }
189
+ console.log(` ✓ SELECTOR: mergedClean=1, regressed=1, reverted=1, trustPercent=${String(selRow.trustPercent)}`);
190
+ // ─── Step 2: Run ranker ─────────────────────────────────────────────
191
+ console.log('--- Step 2: ranker ---');
192
+ // Build candidate list. The ranker's contract is purely by-trust-then-
193
+ // severity-then-age, so PRODUCT_BUG (trustPercent 92) should always come
194
+ // before SELECTOR (trustPercent 42) regardless of severity.
195
+ const candidates = [
196
+ {
197
+ id: 'cand_sel_high',
198
+ classification: 'SELECTOR',
199
+ surface: 'UI_UX_INTEGRITY',
200
+ severity: 'HIGH',
201
+ createdAt: new Date(now - 5 * 86_400_000),
202
+ },
203
+ {
204
+ id: 'cand_pb_low',
205
+ classification: 'PRODUCT_BUG',
206
+ surface: 'UI_UX_INTEGRITY',
207
+ severity: 'LOW',
208
+ createdAt: new Date(now - 1 * 86_400_000),
209
+ },
210
+ {
211
+ id: 'cand_pb_high_old',
212
+ classification: 'PRODUCT_BUG',
213
+ surface: 'UI_UX_INTEGRITY',
214
+ severity: 'HIGH',
215
+ createdAt: new Date(now - 10 * 86_400_000),
216
+ },
217
+ {
218
+ id: 'cand_unknown_crit',
219
+ classification: 'NEVER_SEEN_CLASS',
220
+ surface: 'UI_UX_INTEGRITY',
221
+ severity: 'CRITICAL',
222
+ createdAt: new Date(now - 2 * 86_400_000),
223
+ },
224
+ ];
225
+ // Build trust lookup: a single listTrust call indexed into a Map.
226
+ const trustList = await trustStore.listTrust({ projectId: lifeline.id });
227
+ const trustByKey = new Map();
228
+ for (const t of trustList.trusts) {
229
+ trustByKey.set(`${t.classification}::${t.surface}`, t.trustPercent);
230
+ }
231
+ const trustLookup = (key) => trustByKey.get(`${key.classification ?? ''}::${key.surface}`) ?? 0;
232
+ const ranked = rankCandidates(candidates, trustLookup);
233
+ const rankedIds = ranked.map((c) => c.id);
234
+ console.log(` ranked order: ${rankedIds.join(' → ')}`);
235
+ // Expected order (per ranker contract):
236
+ // 1. cand_pb_high_old (PRODUCT_BUG=92, HIGH severity)
237
+ // 2. cand_pb_low (PRODUCT_BUG=92, LOW severity)
238
+ // 3. cand_sel_high (SELECTOR=42, HIGH severity)
239
+ // 4. cand_unknown_crit (unknown classification → trust 0)
240
+ const expectedOrder = ['cand_pb_high_old', 'cand_pb_low', 'cand_sel_high', 'cand_unknown_crit'];
241
+ if (rankedIds.join(',') !== expectedOrder.join(',')) {
242
+ throw new Error(`Ranker order wrong. Expected: ${expectedOrder.join(',')}; got: ${rankedIds.join(',')}`);
243
+ }
244
+ console.log(` ✓ ranker preferred PRODUCT_BUG (trust=92) over SELECTOR (trust=42) over unknown`);
245
+ // ─── Step 3: OutcomeRecorder smoke (lightweight) ────────────────────
246
+ console.log('--- Step 3: OutcomeRecorder (sanity, all attempts already scored) ---');
247
+ // All seeded attempts are pre-scored, so the recorder should find nothing
248
+ // pending. Still wire it up to prove the factory composes against the real
249
+ // stores end-to-end.
250
+ const stubRepo = {
251
+ openPR: () => {
252
+ throw new Error('smoke: openPR not exercised');
253
+ },
254
+ mergePR: () => {
255
+ throw new Error('smoke: mergePR not exercised');
256
+ },
257
+ revertPR: () => {
258
+ throw new Error('smoke: revertPR not exercised');
259
+ },
260
+ describeRepo: () => {
261
+ throw new Error('smoke: describeRepo not exercised');
262
+ },
263
+ fetchPRDiff: () => Promise.resolve(null),
264
+ };
265
+ const stubRegressionDetector = () => Promise.resolve(false);
266
+ const recorder = createOutcomeRecorder({
267
+ attemptStore,
268
+ ticketStore,
269
+ repo: stubRepo,
270
+ regressionDetector: stubRegressionDetector,
271
+ });
272
+ const recorderResult = await recorder.recordPendingOutcomes({ projectId: lifeline.id });
273
+ console.log(` attemptsScanned=${String(recorderResult.attemptsScanned)} outcomesRecorded=${String(recorderResult.outcomesRecorded)}`);
274
+ if (recorderResult.outcomesRecorded !== 0) {
275
+ throw new Error(`Expected outcomesRecorded=0 (all attempts pre-scored), got ${String(recorderResult.outcomesRecorded)}`);
276
+ }
277
+ console.log(` ✓ recorder is a no-op when all attempts are already scored`);
278
+ console.log('\nQAP-014/015 LEARNING LOOP READY ✓');
279
+ }
280
+ /**
281
+ * Insert a QAFixAttempt with outcome fields baked-in (bypassing OutcomeRecorder).
282
+ * Includes the fixSuccessScore that OutcomeRecorder.scoreOutcome would have
283
+ * computed, so TrustScoreUpdater (which only consumes scored attempts) picks
284
+ * them up.
285
+ */
286
+ async function seedAttempt(qaTicketId, outcome, mergedAt, projectId, attemptIdx) {
287
+ let humanEditLines = 0;
288
+ let regressionDetected = false;
289
+ let autoRevertedAt = null;
290
+ let fixSuccessScore = 1.0;
291
+ switch (outcome.type) {
292
+ case 'mergedClean':
293
+ humanEditLines = 0;
294
+ fixSuccessScore = 1.0;
295
+ break;
296
+ case 'mergedWithEdits':
297
+ humanEditLines = outcome.humanEditLines;
298
+ // 15 ≤ MAJOR_EDIT_THRESHOLD (20) → +0.5
299
+ fixSuccessScore = 0.5;
300
+ break;
301
+ case 'regressed':
302
+ humanEditLines = 0;
303
+ regressionDetected = true;
304
+ fixSuccessScore = -0.5;
305
+ break;
306
+ case 'reverted':
307
+ humanEditLines = 0;
308
+ autoRevertedAt = new Date(mergedAt.getTime() + 86_400_000);
309
+ fixSuccessScore = -1.0;
310
+ break;
311
+ }
312
+ // Use createAttempt then updateAttempt to thread the post-merge fields,
313
+ // since createAttempt's input shape doesn't accept them all directly.
314
+ const created = await attemptStore.createAttempt({
315
+ qaTicketId,
316
+ projectId,
317
+ attemptNumber: attemptIdx + 1,
318
+ promptText: `${SMOKE_MARKER} attempt ${String(attemptIdx + 1)}`,
319
+ diff: '--- a/x\n+++ b/x\n+const x = 1;',
320
+ diffSizeBytes: 30,
321
+ branchName: `smoke/learning-${String(attemptIdx)}`,
322
+ prNumber: 90000 + attemptIdx,
323
+ dispatchStatus: 'AUTO_MERGED',
324
+ });
325
+ createdAttemptIds.push(created.attempt.id);
326
+ await attemptStore.updateAttempt(created.ref, {
327
+ mergedAt,
328
+ humanEditLines,
329
+ regressionDetected,
330
+ autoRevertedAt,
331
+ fixSuccessScore,
332
+ });
333
+ }
334
+ async function cleanup() {
335
+ // QAFixAttempt has Cascade on qaTicketId, so deleting tickets would also
336
+ // delete attempts — but be explicit to keep cleanup grep-friendly.
337
+ if (createdAttemptIds.length > 0) {
338
+ await prisma.qAFixAttempt.deleteMany({
339
+ where: { id: { in: createdAttemptIds } },
340
+ });
341
+ }
342
+ if (createdTicketIds.length > 0) {
343
+ await prisma.qATicket.deleteMany({
344
+ where: { id: { in: createdTicketIds } },
345
+ });
346
+ }
347
+ if (createdRunId) {
348
+ await prisma.qARun.delete({ where: { id: createdRunId } });
349
+ }
350
+ // Trust rows aren't FK-cascaded with tickets; clean up the two we wrote.
351
+ if (lifelineProjectId) {
352
+ await prisma.classificationTrust.deleteMany({
353
+ where: {
354
+ projectId: lifelineProjectId,
355
+ classification: { in: ['PRODUCT_BUG', 'SELECTOR'] },
356
+ surface: 'UI_UX_INTEGRITY',
357
+ },
358
+ });
359
+ }
360
+ }
361
+ main()
362
+ .catch((err) => {
363
+ console.error('\n✗ Smoke failed:', err);
364
+ process.exitCode = 1;
365
+ })
366
+ .finally(async () => {
367
+ try {
368
+ await cleanup();
369
+ }
370
+ catch (cleanupErr) {
371
+ console.error(' (cleanup error, may need manual rows pruning):', cleanupErr);
372
+ }
373
+ await prisma.$disconnect();
374
+ });
375
+ //# sourceMappingURL=smoke-learning-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke-learning-loop.js","sourceRoot":"","sources":["../../src/scripts/smoke-learning-loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Phase 4 orchestration smoke — wires QAP-018B (store) + QAP-018 (cross-link
3
+ * adapter) together to validate the architecture pivot end-to-end.
4
+ *
5
+ * Run: pnpm --filter @derwinjs/db smoke:orchestration
6
+ *
7
+ * Prereqs (env):
8
+ * DATABASE_URL — local Postgres on port 5433 (loaded from packages/db/.env)
9
+ * GH_AUTOFIX_TOKEN — Fine-grained PAT (use $(gh auth token))
10
+ * GH_AUTOFIX_REPO — Target repo, defaults to RoryLYN/derwin
11
+ *
12
+ * What this proves (the architecture pivot's load-bearing claim):
13
+ * 1. Store creates the rich Derwin-side ticket and returns dashboardUrl
14
+ * 2. Adapter posts a stub to GitHub Issues with the dashboardUrl embedded
15
+ * in the body (orchestrator's responsibility to embed)
16
+ * 3. Cross-link ref from the stub gets persisted on the Derwin ticket
17
+ * 4. Operator marking PASS on the Derwin ticket cascades to closing the
18
+ * GitHub stub via the adapter
19
+ *
20
+ * If this goes green, ADR-0008 is validated end-to-end and the rest of
21
+ * Sprint 2 (QLL migration tickets QAP-010..017, QAP-019..021) unblocks
22
+ * with the architectural foundation proven.
23
+ *
24
+ * Design note: this script implements the orchestration pattern inline
25
+ * rather than extracting a real orchestrator class. The orchestrator
26
+ * (`@derwinjs/core`) lands in Sprint 6 (QAP-060 FixIterator + co.). This
27
+ * smoke proves the pattern works; the orchestrator implementation cleanly
28
+ * inherits the verified pattern.
29
+ *
30
+ * Self-cleaning: deletes Derwin-side rows in finally. GitHub stub stays as
31
+ * a closed issue (issues can't be deleted via REST, only via GraphQL admin
32
+ * mutation). Periodic prune via `gh issue list --state closed --label derwin-qa`.
33
+ */
34
+ export {};
35
+ //# sourceMappingURL=smoke-orchestration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke-orchestration.d.ts","sourceRoot":"","sources":["../../src/scripts/smoke-orchestration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG"}
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Phase 4 orchestration smoke — wires QAP-018B (store) + QAP-018 (cross-link
3
+ * adapter) together to validate the architecture pivot end-to-end.
4
+ *
5
+ * Run: pnpm --filter @derwinjs/db smoke:orchestration
6
+ *
7
+ * Prereqs (env):
8
+ * DATABASE_URL — local Postgres on port 5433 (loaded from packages/db/.env)
9
+ * GH_AUTOFIX_TOKEN — Fine-grained PAT (use $(gh auth token))
10
+ * GH_AUTOFIX_REPO — Target repo, defaults to RoryLYN/derwin
11
+ *
12
+ * What this proves (the architecture pivot's load-bearing claim):
13
+ * 1. Store creates the rich Derwin-side ticket and returns dashboardUrl
14
+ * 2. Adapter posts a stub to GitHub Issues with the dashboardUrl embedded
15
+ * in the body (orchestrator's responsibility to embed)
16
+ * 3. Cross-link ref from the stub gets persisted on the Derwin ticket
17
+ * 4. Operator marking PASS on the Derwin ticket cascades to closing the
18
+ * GitHub stub via the adapter
19
+ *
20
+ * If this goes green, ADR-0008 is validated end-to-end and the rest of
21
+ * Sprint 2 (QLL migration tickets QAP-010..017, QAP-019..021) unblocks
22
+ * with the architectural foundation proven.
23
+ *
24
+ * Design note: this script implements the orchestration pattern inline
25
+ * rather than extracting a real orchestrator class. The orchestrator
26
+ * (`@derwinjs/core`) lands in Sprint 6 (QAP-060 FixIterator + co.). This
27
+ * smoke proves the pattern works; the orchestrator implementation cleanly
28
+ * inherits the verified pattern.
29
+ *
30
+ * Self-cleaning: deletes Derwin-side rows in finally. GitHub stub stays as
31
+ * a closed issue (issues can't be deleted via REST, only via GraphQL admin
32
+ * mutation). Periodic prune via `gh issue list --state closed --label derwin-qa`.
33
+ */
34
+ import { PrismaClient } from '../prisma.js';
35
+ import { LifelineTicketAdapter } from '@derwinjs/adapters';
36
+ import { createPrismaQATicketStore } from '../qa-ticket-store.js';
37
+ const SMOKE_MARKER = '[SMOKE-ORCH]';
38
+ const DASHBOARD_BASE_URL = 'http://localhost:3000';
39
+ const TOKEN = process.env.GH_AUTOFIX_TOKEN;
40
+ const REPO = process.env.GH_AUTOFIX_REPO ?? 'RoryLYN/derwin';
41
+ if (!TOKEN) {
42
+ console.error('✗ GH_AUTOFIX_TOKEN env var not set. Run with: GH_AUTOFIX_TOKEN=$(gh auth token) pnpm ...');
43
+ process.exit(1);
44
+ }
45
+ const prisma = new PrismaClient();
46
+ const store = createPrismaQATicketStore({ prisma, dashboardBaseUrl: DASHBOARD_BASE_URL });
47
+ const adapter = new LifelineTicketAdapter({
48
+ github: { token: TOKEN, repo: REPO },
49
+ });
50
+ let createdRunId;
51
+ const createdTicketIds = [];
52
+ async function main() {
53
+ console.log(`Smoke target: store=local-postgres · adapter=${REPO}`);
54
+ console.log('---');
55
+ // ─── Setup: Lifeline + synthetic QARun ──────────────────────────────
56
+ const lifeline = await prisma.project.findUnique({ where: { slug: 'lifeline' } });
57
+ if (!lifeline) {
58
+ throw new Error('Lifeline project not found. Run `pnpm db:seed` first.');
59
+ }
60
+ const run = await prisma.qARun.create({
61
+ data: {
62
+ projectId: lifeline.id,
63
+ triggeredBy: SMOKE_MARKER,
64
+ triggerType: 'OPERATOR_ON_DEMAND',
65
+ scope: { note: SMOKE_MARKER },
66
+ signalsRaised: 1,
67
+ ticketsCreated: 1,
68
+ },
69
+ });
70
+ createdRunId = run.id;
71
+ console.log(`✓ Setup: Lifeline + synthetic QARun ${run.id}`);
72
+ // ─── Step 1: Store creates the rich Derwin ticket ──────────────────
73
+ const createInput = {
74
+ projectId: lifeline.id,
75
+ qaRunId: run.id,
76
+ title: `${SMOKE_MARKER} Orchestration end-to-end test`,
77
+ surface: 'UI_UX_INTEGRITY',
78
+ classification: 'TIMING',
79
+ severity: 'HIGH',
80
+ riskTier: 'HIGH',
81
+ reproSteps: [
82
+ { step: 1, action: 'Trigger orchestration smoke' },
83
+ { step: 2, action: 'Verify store + adapter compose correctly' },
84
+ ],
85
+ suspectedRootCause: 'Orchestration smoke validating QAP-018 + QAP-018B compose end-to-end',
86
+ blastRadius: {
87
+ affectedFiles: [
88
+ 'packages/db/src/qa-ticket-store.ts',
89
+ 'packages/adapters/src/ticket/lifeline.ts',
90
+ ],
91
+ affectedTests: [],
92
+ affectedPages: [],
93
+ },
94
+ proposedFixApproach: 'Verify the architecture pivot (ADR-0008) holds end-to-end',
95
+ };
96
+ const stored = await store.createQATicket(createInput);
97
+ createdTicketIds.push(stored.ticket.id);
98
+ console.log(`✓ Step 1 · store.createQATicket → derwinId=${stored.ticket.id}`);
99
+ console.log(` dashboardUrl=${stored.dashboardUrl}`);
100
+ // ─── Step 2: Adapter posts a stub with dashboardUrl embedded ────────
101
+ // Orchestrator's responsibility: embed the dashboardUrl in the body.
102
+ // Adapter accepts pre-rendered body content per ADR-0008 design choice.
103
+ const stubBody = [
104
+ `**TIMING** classification · HIGH risk tier`,
105
+ '',
106
+ 'Orchestration smoke test — synthetic ticket. The Derwin-side ticket is the rich record; this stub is the cross-link.',
107
+ '',
108
+ `🔗 **[Open the rich record in Derwin dashboard →](${stored.dashboardUrl})**`,
109
+ ].join('\n');
110
+ const stub = await adapter.createQATicket({
111
+ title: stored.ticket.title,
112
+ body: stubBody,
113
+ labels: [
114
+ 'bucket:FAIL',
115
+ 'classification:TIMING',
116
+ SMOKE_MARKER.toLowerCase().replace(/[^a-z0-9-]/g, '-'),
117
+ ],
118
+ severity: 'HIGH',
119
+ surface: 'UI_UX_INTEGRITY',
120
+ riskTier: 'HIGH',
121
+ originatingRef: 'gh:smoke/orchestration#0',
122
+ });
123
+ console.log(`✓ Step 2 · adapter.createQATicket → ghRef=${stub.ref}`);
124
+ console.log(` url=${stub.url}`);
125
+ // ─── Step 3: Persist cross-link back to Derwin ticket ──────────────
126
+ const ghRefMatch = /^gh:([^/]+\/[^#]+)#(\d+)$/.exec(stub.ref);
127
+ if (!ghRefMatch?.[1] || !ghRefMatch[2]) {
128
+ throw new Error(`Couldn't parse adapter ref: ${stub.ref}`);
129
+ }
130
+ const crossLink = {
131
+ system: 'github',
132
+ repo: ghRefMatch[1],
133
+ issueNumber: parseInt(ghRefMatch[2], 10),
134
+ url: stub.url,
135
+ state: 'open',
136
+ };
137
+ const linked = await store.updateQATicket({ id: stored.ticket.id, projectId: lifeline.id }, { crossLinkRefs: [crossLink] });
138
+ if (linked.crossLinkRefs.length !== 1) {
139
+ throw new Error('crossLinkRefs not persisted');
140
+ }
141
+ if (linked.crossLinkRefs[0]?.url !== stub.url) {
142
+ throw new Error('crossLinkRef URL mismatch');
143
+ }
144
+ console.log(`✓ Step 3 · store.updateQATicket(crossLinkRefs) → persisted`);
145
+ // ─── Step 4: Verify the dashboardUrl made it into the GH stub body ──
146
+ const stubReadback = await adapter.getTicket(stub.ref);
147
+ if (!stubReadback) {
148
+ throw new Error('Could not read back the stub from GitHub');
149
+ }
150
+ if (!stubReadback.description.includes(stored.dashboardUrl)) {
151
+ throw new Error(`GH stub body does not contain the Derwin dashboardUrl. body=${stubReadback.description.slice(0, 200)}...`);
152
+ }
153
+ console.log(`✓ Step 4 · GH stub body contains dashboardUrl (${stored.dashboardUrl})`);
154
+ // ─── Step 5: Mark PASS — orchestrator pattern ───────────────────────
155
+ // (a) Store: mark finalBucket PASS — auto-populates closedAt
156
+ const passed = await store.updateQATicket({ id: stored.ticket.id, projectId: lifeline.id }, { finalBucket: 'PASS', bucketReason: 'orchestration smoke complete' });
157
+ if (passed.finalBucket !== 'PASS') {
158
+ throw new Error('store finalBucket transition failed');
159
+ }
160
+ if (passed.closedAt === null) {
161
+ throw new Error('store closedAt should auto-populate');
162
+ }
163
+ console.log(`✓ Step 5a · store marked PASS, auto-closed at ${passed.closedAt.toISOString()}`);
164
+ // (b) Adapter: cascade PASS to all crossLinkRefs (closes the GH stubs).
165
+ // CrossLinkRef.system is a literal 'github' today; if/when other systems
166
+ // are added, this loop expands with branching adapters per system.
167
+ for (const link of passed.crossLinkRefs) {
168
+ const ghRef = `gh:${link.repo}#${String(link.issueNumber)}`;
169
+ await adapter.updateQATicket(ghRef, { finalBucket: 'PASS' });
170
+ }
171
+ console.log(`✓ Step 5b · adapter cascaded PASS to ${String(passed.crossLinkRefs.length)} cross-link(s)`);
172
+ // ─── Step 6: Verify both sides closed ───────────────────────────────
173
+ const stubAfter = await adapter.getTicket(stub.ref);
174
+ if (!stubAfter) {
175
+ throw new Error('GH stub should still be readable after close');
176
+ }
177
+ if (stubAfter.status !== 'closed') {
178
+ throw new Error(`GH stub should be closed, got ${stubAfter.status}`);
179
+ }
180
+ if (!stubAfter.labels.includes('bucket:PASS')) {
181
+ throw new Error(`GH stub should have bucket:PASS, got: ${stubAfter.labels.join(', ')}`);
182
+ }
183
+ console.log(`✓ Step 6 · GH stub closed with bucket:PASS label`);
184
+ console.log('\n──────────────────────────────────────────');
185
+ console.log('ORCHESTRATION READY ✓ — architecture pivot validated end-to-end');
186
+ console.log(` Derwin ticket: ${stored.ticket.id} (closed, finalBucket=PASS)`);
187
+ console.log(` GH stub: ${stub.url} (closed, bucket:PASS)`);
188
+ console.log(` Cross-link: embedded both directions`);
189
+ console.log('──────────────────────────────────────────');
190
+ }
191
+ async function cleanup() {
192
+ if (createdTicketIds.length > 0) {
193
+ await prisma.qATicket.deleteMany({
194
+ where: { id: { in: createdTicketIds } },
195
+ });
196
+ }
197
+ if (createdRunId) {
198
+ await prisma.qARun.delete({ where: { id: createdRunId } });
199
+ }
200
+ }
201
+ main()
202
+ .catch((err) => {
203
+ console.error('\n✗ Orchestration smoke failed:', err);
204
+ process.exitCode = 1;
205
+ })
206
+ .finally(async () => {
207
+ try {
208
+ await cleanup();
209
+ }
210
+ catch (cleanupErr) {
211
+ console.error(' (cleanup error, may need manual prune):', cleanupErr);
212
+ }
213
+ await prisma.$disconnect();
214
+ });
215
+ //# sourceMappingURL=smoke-orchestration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke-orchestration.js","sourceRoot":"","sources":["../../src/scripts/smoke-orchestration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAElE,MAAM,YAAY,GAAG,cAAc,CAAC;AACpC,MAAM,kBAAkB,GAAG,uBAAuB,CAAC;AACnD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,gBAAgB,CAAC;AAE7D,IAAI,CAAC,KAAK,EAAE,CAAC;IACX,OAAO,CAAC,KAAK,CACX,0FAA0F,CAC3F,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;AAClC,MAAM,KAAK,GAAG,yBAAyB,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,CAAC,CAAC;AAC1F,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC;IACxC,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE;CACrC,CAAC,CAAC;AAEH,IAAI,YAAgC,CAAC;AACrC,MAAM,gBAAgB,GAAa,EAAE,CAAC;AAEtC,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,CAAC,gDAAgD,IAAI,EAAE,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAEnB,uEAAuE;IACvE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;IAClF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QACpC,IAAI,EAAE;YACJ,SAAS,EAAE,QAAQ,CAAC,EAAE;YACtB,WAAW,EAAE,YAAY;YACzB,WAAW,EAAE,oBAAoB;YACjC,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;YAC7B,aAAa,EAAE,CAAC;YAChB,cAAc,EAAE,CAAC;SAClB;KACF,CAAC,CAAC;IACH,YAAY,GAAG,GAAG,CAAC,EAAE,CAAC;IACtB,OAAO,CAAC,GAAG,CAAC,uCAAuC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;IAE7D,sEAAsE;IACtE,MAAM,WAAW,GAAwB;QACvC,SAAS,EAAE,QAAQ,CAAC,EAAE;QACtB,OAAO,EAAE,GAAG,CAAC,EAAE;QACf,KAAK,EAAE,GAAG,YAAY,gCAAgC;QACtD,OAAO,EAAE,iBAAiB;QAC1B,cAAc,EAAE,QAAQ;QACxB,QAAQ,EAAE,MAAM;QAChB,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE;YACV,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,6BAA6B,EAAE;YAClD,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,0CAA0C,EAAE;SAChE;QACD,kBAAkB,EAAE,sEAAsE;QAC1F,WAAW,EAAE;YACX,aAAa,EAAE;gBACb,oCAAoC;gBACpC,0CAA0C;aAC3C;YACD,aAAa,EAAE,EAAE;YACjB,aAAa,EAAE,EAAE;SAClB;QACD,mBAAmB,EAAE,2DAA2D;KACjF,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IACvD,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,8CAA8C,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9E,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IAErD,uEAAuE;IACvE,qEAAqE;IACrE,wEAAwE;IACxE,MAAM,QAAQ,GAAG;QACf,4CAA4C;QAC5C,EAAE;QACF,sHAAsH;QACtH,EAAE;QACF,qDAAqD,MAAM,CAAC,YAAY,KAAK;KAC9E,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC;QACxC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK;QAC1B,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE;YACN,aAAa;YACb,uBAAuB;YACvB,YAAY,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SACvD;QACD,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,iBAAiB;QAC1B,QAAQ,EAAE,MAAM;QAChB,cAAc,EAAE,0BAA0B;KAC3C,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,6CAA6C,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAEjC,sEAAsE;IACtE,MAAM,UAAU,GAAG,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9D,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,SAAS,GAAiB;QAC9B,MAAM,EAAE,QAAQ;QAChB,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;QACnB,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACxC,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,KAAK,EAAE,MAAM;KACd,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,cAAc,CACvC,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE,EAChD,EAAE,aAAa,EAAE,CAAC,SAAS,CAAC,EAAE,CAC/B,CAAC;IACF,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;IAE1E,uEAAuE;IACvE,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CACb,+DAA+D,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAC3G,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,kDAAkD,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC;IAEtF,uEAAuE;IACvE,6DAA6D;IAC7D,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,cAAc,CACvC,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE,EAChD,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,8BAA8B,EAAE,CACtE,CAAC;IACF,IAAI,MAAM,CAAC,WAAW,KAAK,MAAM,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,iDAAiD,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAE9F,wEAAwE;IACxE,yEAAyE;IACzE,mEAAmE;IACnE,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5D,MAAM,OAAO,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,CAAC,GAAG,CACT,wCAAwC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,gBAAgB,CAC5F,CAAC;IAEF,uEAAuE;IACvE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,iCAAiC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,yCAAyC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1F,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;IAEhE,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,CAAC,oBAAoB,MAAM,CAAC,MAAM,CAAC,EAAE,6BAA6B,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,CAAC,GAAG,wBAAwB,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;AAC5D,CAAC;AAED,KAAK,UAAU,OAAO;IACpB,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;YAC/B,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE;SACxC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC;AAED,IAAI,EAAE;KACH,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IACtB,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC;KACD,OAAO,CAAC,KAAK,IAAI,EAAE;IAClB,IAAI,CAAC;QACH,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;IAAC,OAAO,UAAmB,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,UAAU,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;AAC7B,CAAC,CAAC,CAAC"}