-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Expand file tree
/
Copy pathROADMAP.html
More file actions
681 lines (615 loc) · 81.5 KB
/
Copy pathROADMAP.html
File metadata and controls
681 lines (615 loc) · 81.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
<title>Roadmap to Prisma 8 RC1</title>
<style>
:root {
--bg: oklch(0.985 0.003 220);
--surface: oklch(1 0 0);
--surface-2: oklch(0.965 0.006 215);
--ink: oklch(0.28 0.045 235);
--ink-soft: oklch(0.42 0.035 235);
--line: oklch(0.9 0.01 220);
--line-strong: oklch(0.82 0.015 220);
--accent: oklch(0.62 0.11 180);
--accent-ink: oklch(0.45 0.09 180);
--accent-tint: oklch(0.95 0.025 180);
--good: oklch(0.5 0.12 155);
--good-bg: oklch(0.94 0.045 155);
--open: oklch(0.42 0.03 235);
--open-bg: oklch(0.93 0.008 220);
--warn: oklch(0.53 0.11 70);
--warn-bg: oklch(0.95 0.04 85);
--mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
--dur: 180ms;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: oklch(0.21 0.025 235);
--surface: oklch(0.25 0.028 235);
--surface-2: oklch(0.28 0.03 235);
--ink: oklch(0.92 0.012 220);
--ink-soft: oklch(0.74 0.02 220);
--line: oklch(0.34 0.03 235);
--line-strong: oklch(0.42 0.03 235);
--accent: oklch(0.75 0.1 180);
--accent-ink: oklch(0.8 0.1 180);
--accent-tint: oklch(0.3 0.04 190);
--good: oklch(0.78 0.13 155);
--good-bg: oklch(0.32 0.05 155);
--open: oklch(0.74 0.02 220);
--open-bg: oklch(0.31 0.02 235);
--warn: oklch(0.8 0.11 80);
--warn-bg: oklch(0.33 0.04 80);
}
}
:root[data-theme="light"] {
--bg: oklch(0.985 0.003 220); --surface: oklch(1 0 0); --surface-2: oklch(0.965 0.006 215);
--ink: oklch(0.28 0.045 235); --ink-soft: oklch(0.42 0.035 235);
--line: oklch(0.9 0.01 220); --line-strong: oklch(0.82 0.015 220);
--accent: oklch(0.62 0.11 180); --accent-ink: oklch(0.45 0.09 180); --accent-tint: oklch(0.95 0.025 180);
--good: oklch(0.5 0.12 155); --good-bg: oklch(0.94 0.045 155);
--open: oklch(0.42 0.03 235); --open-bg: oklch(0.93 0.008 220);
--warn: oklch(0.53 0.11 70); --warn-bg: oklch(0.95 0.04 85);
}
:root[data-theme="dark"] {
--bg: oklch(0.21 0.025 235); --surface: oklch(0.25 0.028 235); --surface-2: oklch(0.28 0.03 235);
--ink: oklch(0.92 0.012 220); --ink-soft: oklch(0.74 0.02 220);
--line: oklch(0.34 0.03 235); --line-strong: oklch(0.42 0.03 235);
--accent: oklch(0.75 0.1 180); --accent-ink: oklch(0.8 0.1 180); --accent-tint: oklch(0.3 0.04 190);
--good: oklch(0.78 0.13 155); --good-bg: oklch(0.32 0.05 155);
--open: oklch(0.74 0.02 220); --open-bg: oklch(0.31 0.02 235);
--warn: oklch(0.8 0.11 80); --warn-bg: oklch(0.33 0.04 80);
}
* { box-sizing: border-box; }
body {
margin: 0; background: var(--bg); color: var(--ink);
font: 16px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
font-variant-numeric: tabular-nums;
padding: 52px 24px 96px;
}
.wrap { max-width: 780px; margin: 0 auto; }
a { color: var(--accent-ink); text-decoration-thickness: 1px; text-underline-offset: 2px; }
code {
font-family: var(--mono); font-size: 0.86em;
background: var(--surface-2); border: 1px solid var(--line);
border-radius: 4px; padding: 0.08em 0.35em;
}
h1 { font-size: 32px; line-height: 1.2; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 18px; text-wrap: balance; }
h2 { font-size: 20px; font-weight: 700; letter-spacing: -0.01em; margin: 0 0 10px; text-wrap: balance; }
p { margin: 0 0 14px; max-width: 72ch; text-wrap: pretty; }
.soft { color: var(--ink-soft); }
.masthead { margin-bottom: 40px; }
.masthead .org { font-family: var(--mono); font-size: 12.5px; color: var(--ink-soft); margin: 0 0 14px; }
.statusline {
display: flex; flex-wrap: wrap; gap: 10px 28px; align-items: baseline;
background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
padding: 14px 20px; margin-top: 22px;
}
.statusline .item { display: flex; gap: 8px; align-items: baseline; }
.statusline .k { font-size: 12.5px; color: var(--ink-soft); }
.statusline .v { font-family: var(--mono); font-size: 15px; font-weight: 700; }
.statusline .v.teal { color: var(--accent-ink); }
.statusline .v.ok { color: var(--good); }
.statusline .v.link { font-size: 14px; }
.progress {
background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
padding: 14px 20px 15px; margin-top: 12px;
}
.progress .cap { font-size: 12.5px; color: var(--ink-soft); margin: 0 0 8px; }
.progress .bar { display: flex; height: 12px; border-radius: 6px; overflow: hidden; background: var(--open-bg); }
.progress .bar .done { background: var(--good); }
.progress .bar .flight { background: var(--accent); }
.progress .legend { display: flex; flex-wrap: wrap; gap: 6px 20px; margin-top: 9px; font-size: 13.5px; color: var(--ink-soft); }
.progress .legend b { color: var(--ink); }
.progress .dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 6px; }
.owner {
flex: none; font-family: var(--mono); font-size: 11px; font-weight: 600;
color: var(--ink-soft); background: var(--surface-2); border: 1px solid var(--line);
border-radius: 5px; padding: 2px 8px; white-space: nowrap; align-self: center;
}
.musts { margin: 44px 0 10px; }
.musts ol { list-style: none; margin: 18px 0 0; padding: 0; display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); overflow: hidden; }
.musts li { display: flex; gap: 16px; align-items: baseline; padding: 14px 18px; border-top: 1px solid var(--line); }
.musts li:first-child { border-top: none; }
.musts .n { font-family: var(--mono); font-size: 14px; font-weight: 700; color: var(--accent-ink); flex: none; width: 16px; }
.musts .what { flex: 1 1 auto; min-width: 0; }
.musts .what a { color: var(--ink); font-weight: 650; text-decoration: none; }
.musts .what a:hover { color: var(--accent-ink); text-decoration: underline; }
.musts .what .note { display: block; font-size: 14px; color: var(--ink-soft); margin-top: 1px; }
.musts .mini { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.musts .minibar { flex: 1 1 auto; max-width: 340px; height: 6px; border-radius: 3px; overflow: hidden; display: flex; background: var(--open-bg); }
.musts .minibar .d { background: var(--good); }
.musts .minibar .f { background: var(--accent); }
.musts .minicount { font-family: var(--mono); font-size: 11px; color: var(--ink-soft); white-space: nowrap; }
.pill {
flex: none; font-size: 11px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
padding: 3px 10px; border-radius: 999px; white-space: nowrap; align-self: center;
}
.pill.flight { color: var(--good); background: var(--good-bg); }
.pill.open { color: var(--open); background: var(--open-bg); }
.pill.done { color: var(--good); background: var(--good-bg); }
.pill.decide { color: var(--warn); background: var(--warn-bg); }
section.req { margin-top: 52px; scroll-margin-top: 24px; }
section.req > p { color: var(--ink); }
section.req .reqno { font-family: var(--mono); font-size: 13px; font-weight: 700; color: var(--accent-ink); display: inline-block; margin-bottom: 4px; }
details.task {
background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
margin: 10px 0; overflow: hidden;
}
details.task[open] { border-color: var(--line-strong); }
details.task > summary {
display: flex; gap: 12px; align-items: center; padding: 13px 16px;
cursor: pointer; list-style: none; user-select: none;
transition: background-color var(--dur) cubic-bezier(0.22, 1, 0.36, 1);
}
details.task > summary::-webkit-details-marker { display: none; }
details.task > summary:hover { background: var(--surface-2); }
details.task > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 10px; }
details.task > summary .chev {
flex: none; width: 16px; height: 16px; color: var(--ink-soft);
transition: transform var(--dur) cubic-bezier(0.22, 1, 0.36, 1);
}
details.task[open] > summary .chev { transform: rotate(90deg); }
details.task > summary .t { flex: 1 1 auto; font-weight: 650; font-size: 15px; min-width: 0; }
details.task .body { padding: 2px 18px 16px 44px; }
details.task .body p, details.task .body li { font-size: 15px; color: var(--ink); }
details.task .body ul { margin: 0 0 12px; padding-left: 20px; display: flex; flex-direction: column; gap: 7px; max-width: 70ch; }
.crit { font-family: var(--mono); font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em; color: var(--accent-ink); background: var(--accent-tint); border-radius: 4px; padding: 3px 7px; flex: none; }
.meter { margin: 14px 0 6px; }
.meter .bar { display: flex; height: 12px; border-radius: 6px; overflow: hidden; background: var(--open-bg); }
.meter .seg1 { background: var(--accent); }
.meter .seg2 { background: var(--warn-bg); border-left: 1px solid var(--bg); }
.meter .seg2d { background: var(--warn); opacity: 0.45; }
.meter .legend { display: flex; flex-wrap: wrap; gap: 6px 20px; margin-top: 10px; font-size: 13.5px; color: var(--ink-soft); }
.meter .legend b { color: var(--ink); font-variant-numeric: tabular-nums; }
.meter .dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 6px; vertical-align: baseline; }
.landed { margin-top: 56px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 20px 24px 8px; }
.landed ul { margin: 6px 0 16px; padding-left: 20px; display: flex; flex-direction: column; gap: 9px; max-width: 70ch; }
.landed li { font-size: 15px; }
footer { margin-top: 44px; font-size: 13.5px; color: var(--ink-soft); max-width: 72ch; }
@media (prefers-reduced-motion: reduce) {
details.task > summary, details.task > summary .chev { transition: none; }
}
@media (max-width: 560px) {
body { padding: 32px 16px 72px; }
.musts li { flex-wrap: wrap; }
.musts .what { flex-basis: 100%; order: 3; }
}
</style>
<div class="wrap">
<header class="masthead">
<p class="org">Prisma Engineering</p>
<h1>Roadmap to Prisma 8 RC1</h1>
<p>Prisma Next — the contract-first rewrite of Prisma — ships as <strong>Prisma 8</strong>. On <strong>July 31</strong> we publish <strong><code>prisma@8.0.0-rc.1</code></strong> from the <code>prisma/prisma</code> repository: the same repository and the same npm package Prisma users already know. The release candidate is published under a pre-release tag, so <code>npm install prisma</code> keeps installing Prisma 7 until 8.0.0 final ships.</p>
<p>Prisma 8 carries <strong>PostgreSQL to general availability</strong> — and that is all: <strong>MongoDB ships in early access</strong>, and <strong>SQLite is a proof of concept</strong> at this stage. A release candidate freezes the public API; it does not promise Prisma 7 feature parity. Its promise is different: <strong>everything it ships works and is proven by a test</strong>, everything experimental is labeled, and everything absent is named rather than silently missing.</p>
<div class="statusline">
<span class="item"><span class="k">Ships</span> <span class="v teal">July 31</span></span>
<span class="item"><span class="k">Health</span> <span class="v ok">On track</span></span>
<span class="item"><span class="k">Updated</span> <span class="v">August 5</span></span>
<span class="item"><span class="k">Scoreboard</span> <span class="v link"><a href="scorecard.md">416 proven · 488 unproven · 12 experimental · 244 not in 8.0</a></span></span>
</div>
<div class="progress">
<p class="cap">Work on this page: <b>44 tasks</b> — 14 done, 9 in flight, 21 not started</p>
<div class="bar" role="img" aria-label="44 tasks: 14 done, 9 in flight, 21 not started">
<div class="done" style="width: 31.8%"></div>
<div class="flight" style="width: 20.5%"></div>
</div>
<div class="legend">
<span><span class="dot" style="background: var(--good)"></span><b>14</b> done</span>
<span><span class="dot" style="background: var(--accent)"></span><b>9</b> in flight</span>
<span><span class="dot" style="background: var(--open-bg); outline: 1px solid var(--line-strong); outline-offset: -1px;"></span><b>21</b> not started</span>
</div>
<p class="cap" style="margin-top: 16px;"><a href="scorecard.md">Feature scoreboard</a>: <b>1,160 verdict cells</b> (593 features × 3 databases, minus n/a) — 416 proven, 488 unproven, 12 experimental, 244 not in 8.0</p>
<div class="bar" role="img" aria-label="Scoreboard: 416 cells proven, 488 unproven, 12 experimental, 244 not in 8.0">
<div style="width: 35.9%; background: var(--accent);"></div>
<div style="width: 42.1%; background: var(--warn); opacity: 0.45;"></div>
<div style="width: 1.0%; background: var(--line-strong);"></div>
<div style="width: 21.0%; background: var(--open); opacity: 0.35;"></div>
</div>
<div class="legend">
<span><span class="dot" style="background: var(--accent)"></span><b>416</b> proven by a named test</span>
<span><span class="dot" style="background: var(--warn); opacity: 0.45"></span><b>488</b> unproven — the test-writing queue</span>
<span><span class="dot" style="background: var(--line-strong)"></span><b>12</b> experimental</span>
<span><span class="dot" style="background: var(--open); opacity: 0.35"></span><b>244</b> not in 8.0 (named absences)</span>
</div>
</div>
</header>
<section class="musts" aria-labelledby="musts-h">
<h2 id="musts-h">What needs to happen to release v8-RC1</h2>
<p class="soft">Six things must be true on release day. Everything on this page belongs to one of them.</p>
<ol>
<li>
<span class="n">1</span>
<span class="what"><a href="#req1">Queries must return correct values</a>
<span class="note">The relation-loading codec defect is fixed and verified, and aggregates now decode through codecs; two type/runtime mismatches remain.</span><span class="mini" aria-hidden="false"><span class="minibar" role="img" aria-label="5 tasks: 3 done · 2 in flight"><span class="d" style="width: 60.0%"></span><span class="f" style="width: 40.0%"></span></span><span class="minicount">3 done · 2 in flight</span></span></span>
<span class="owner">Alexey</span>
<span class="pill flight">In progress</span>
</li>
<li>
<span class="n">2</span>
<span class="what"><a href="#req2">The schema language must reach its final form</a>
<span class="note">Whatever syntax the RC ships is permanent for the life of v8; two language projects are running.</span><span class="mini" aria-hidden="false"><span class="minibar" role="img" aria-label="5 tasks: 1 done · 2 in flight · 2 not started"><span class="d" style="width: 20.0%"></span><span class="f" style="width: 40.0%"></span></span><span class="minicount">1 done · 2 in flight · 2 not started</span></span></span>
<span class="owner">Serhii</span>
<span class="pill flight">In flight</span>
</li>
<li>
<span class="n">3</span>
<span class="what"><a href="#req3">Every name and format users depend on must be final</a>
<span class="note">Error codes, hashes, the migration snapshot layout, and the config-key rename are done; the name sweep remains.</span><span class="mini" aria-hidden="false"><span class="minibar" role="img" aria-label="6 tasks: 4 done · 2 not started"><span class="d" style="width: 66.7%"></span></span><span class="minicount">4 done · 2 not started</span></span></span>
<span class="owner">Will</span>
<span class="pill flight">In progress</span>
</li>
<li>
<span class="n">4</span>
<span class="what"><a href="#req4">The release's claims must be proven</a>
<span class="note">"It works" and "you can migrate incrementally" each need a runnable receipt.</span><span class="mini" aria-hidden="false"><span class="minibar" role="img" aria-label="8 tasks: 2 done · 3 in flight · 3 not started"><span class="d" style="width: 25.0%"></span><span class="f" style="width: 37.5%"></span></span><span class="minicount">2 done · 3 in flight · 3 not started</span></span></span>
<span class="owner">Everyone</span>
<span class="pill flight">Scoreboard merged</span>
</li>
<li>
<span class="n">5</span>
<span class="what"><a href="#req5">The code must move into prisma/prisma</a>
<span class="note">The code is in prisma/prisma and the v7 branch runs its own CI; the package-name takeover and v7 issue triage remain.</span><span class="mini" aria-hidden="false"><span class="minibar" role="img" aria-label="7 tasks: 3 done · 1 in flight · 3 not started"><span class="d" style="width: 42.9%"></span><span class="f" style="width: 14.3%"></span></span><span class="minicount">3 done · 1 in flight · 3 not started</span></span></span>
<span class="owner">Alexey</span>
<span class="pill flight">In progress</span>
</li>
<li>
<span class="n">6</span>
<span class="what"><a href="#req6">The rough edges users hit on day one must be gone</a>
<span class="note">Small fixes that would be embarrassing under announcement-day attention.</span><span class="mini" aria-hidden="false"><span class="minibar" role="img" aria-label="13 tasks: 1 done · 1 in flight · 11 not started"><span class="d" style="width: 7.7%"></span><span class="f" style="width: 7.7%"></span></span><span class="minicount">1 done · 1 in flight · 11 not started</span></span></span>
<span class="owner">Everyone</span>
<span class="pill open">Open</span>
</li>
</ol>
<p class="soft" style="margin-top: 16px;">Two dated decisions still bound the work. One is now overdue: the minimum supported Postgres version, whose <strong>July 22</strong> target has passed and still blocks final scoreboard verdicts until it is set. One is imminent: the polymorphism stable-or-experimental call (<strong>July 24</strong>, decided by whether its bug stream has flattened). A third is already made and delivered: error codes standardize on dotted namespace codes (like <code>ORM.DECODE_FAILED</code>), and the consolidation has landed. July 24 is also the day the scoreboard verdicts freeze and scope stops moving. There is no other internal schedule: we work these sections as fast as they'll go and ship when they're done.</p>
</section>
<section class="req" id="req1">
<span class="reqno">Requirement 1</span>
<span class="owner" style="margin-left: 8px;">Alexey</span>
<h2>Queries must return correct values</h2>
<p class="soft">Prisma 8's core promise at the RC is that the query paths it ships are correct. The one significant defect class — relation-loading bypassing type codecs — is fixed as of July 31, and aggregate decoding followed on August 5; what remains is the type/runtime mismatches and the polymorphism call.</p>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Values read through relation-loading bypass their type codecs — big numbers silently corrupt, date columns throw</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>When a query loads a relation (say, a post together with its author), Postgres assembles the nested rows into JSON inside the database, using its <code>json_agg</code> function. JSON numbers cannot represent everything a database column can hold: a 64-bit integer or arbitrary-precision decimal got silently rounded to the nearest JavaScript-representable number before Prisma's type codecs ever saw it, and date/time values arrived in a format the decoder rejects — so a plain <code>DateTime</code> column read through <code>.include()</code> threw.</p>
<p>The fix landed July 31: every type codec states an explicit <em>lossless</em> canonical JSON form (big numbers travel as decimal strings, binary as base64), and the SQL we generate produces that form inside the database. It shipped as three pull requests in strict sequence — the projection AST foundations (<a href="https://linear.app/prisma-company/issue/TML-3062">TML-3062</a>, <a href="https://github.com/prisma/prisma-next/pull/1023">#1023</a>), the per-database codec descriptors (<a href="https://linear.app/prisma-company/issue/TML-3061">TML-3061</a>, <a href="https://github.com/prisma/prisma-next/pull/1051">#1051</a>), and the switch-over carrying the per-codec projections and their database-backed conformance harness (<a href="https://linear.app/prisma-company/issue/TML-3100">TML-3100</a>, <a href="https://linear.app/prisma-company/issue/TML-3063">TML-3063</a>, <a href="https://github.com/prisma/prisma/pull/29844">#29844</a>). The switch-over is the promised breaking change: users regenerate their contract files, nine codecs change their JSON form on the read path, and zone-less timestamps now read as UTC. Integration tests prove each renderer produces the canonical form against a real database.</p>
<p>One remainder was accepted knowingly and later closed: aggregate values now decode through codecs (<a href="https://linear.app/prisma-company/issue/TML-3064">TML-3064</a>, landed August 5 as <a href="https://github.com/prisma/prisma/pull/29867">#29867</a>). The other stands: <code>pg/geometry@1</code> keeps its non-canonical form until its SRID representation is decided and a PostGIS-capable test database exists (<a href="https://linear.app/prisma-company/issue/TML-3105">TML-3105</a>).</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t"><code>date</code> columns fail at runtime when read through relation-loading</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>The codec that correctly handles Postgres <code>date</code> values exists and is strict (it rejects impossible dates like February 31st rather than silently normalizing them), but nothing connected the <code>date</code> column type to it — so reading a <code>date</code> column through <code>.include()</code> threw at decode time, because the column inherited the <code>timestamptz</code> codec, which rejects the bare <code>YYYY-MM-DD</code> that <code>json_agg</code> renders. <code>@db.Date</code> now binds to <code>pg/date@1</code>, and a test proves an included <code>date</code> column comes back as a <code>Date</code> (<a href="https://linear.app/prisma-company/issue/TML-3086">TML-3086</a>, landed as <a href="https://github.com/prisma/prisma-next/pull/1038">#1038</a>).</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Binary columns read through relation-loading return hex text instead of bytes</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>Same disease as the big one above, concrete instance: a <code>Bytes</code> column selected inside <code>.include()</code> came back as the raw hexadecimal text Postgres uses in JSON (<code>\x48656c6c6f</code>) while the TypeScript types promise a <code>Uint8Array</code>. Fixed by the lossless-JSON switch-over: <code>pg/bytea@1</code>'s canonical JSON form is base64, and an integration test reads an included <code>bytea</code> column back as its exact bytes (<a href="https://linear.app/prisma-company/issue/TML-2990">TML-2990</a>, landed as part of <a href="https://github.com/prisma/prisma/pull/29844">#29844</a>).</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Places where the TypeScript types and the runtime disagree</span><span class="pill flight">In flight</span></summary>
<div class="body">
<p>Two known mismatches remain, both "the type signature promises one thing, the running code returns another":</p>
<ul>
<li><code>Timestamp</code>/<code>Timestamptz</code> columns: the declared output type is a branded string, but the codec actually returns a JavaScript <code>Date</code> (<a href="https://linear.app/prisma-company/issue/TML-2391">TML-2391</a>, in progress).</li>
<li>Projects that use the schema types directly without running contract emission (<code>typeof contract</code>) get types that ignore per-instance codec parameters — enum value sets are fixed (<a href="https://linear.app/prisma-company/issue/TML-2960">TML-2960</a>, <a href="https://github.com/prisma/prisma-next/pull/958">#958</a>), the codec-parameter half is tracked as <a href="https://linear.app/prisma-company/issue/TML-3014">TML-3014</a>.</li>
</ul>
<p>A third is resolved: aggregate values now decode through target-declared aggregate codecs, so the type an aggregate declares is the value the runtime hands back. <code>count()</code> reads as a <code>number</code> and refuses a tally outside ±(2^53 − 1) rather than rounding it, with <code>countBigInt()</code> as the lossless form. Delivered with the public target testkits for extensions (<a href="https://linear.app/prisma-company/issue/TML-3064">TML-3064</a>, landed August 5 as <a href="https://github.com/prisma/prisma/pull/29867">#29867</a>); the native-number defaults are <a href="https://linear.app/prisma-company/issue/TML-3165">TML-3165</a>.</p>
<p>A type that lies is a correctness bug with a delay on it; all must be resolved (or the type corrected to tell the truth) before the types freeze.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Finish the polymorphism bug tail — then decide: stable or experimental</span><span class="pill flight">In flight</span></summary>
<div class="body">
<p>Polymorphism means models that inherit from a base model, stored across joined tables (multi-table inheritance). It has been the source of most of Prisma 8's recent correctness bugs. The encouraging signal: recent fixes are narrow edge cases rather than missing capabilities, and no known-broken or skipped tests remain in the area. The open list, so the tail is visible rather than vibes:</p>
<ul>
<li>Explicit <code>.select(...)</code> on a polymorphic include doesn't restrict variant-table columns (<a href="https://linear.app/prisma-company/issue/TML-2783">TML-2783</a> — the runtime fix landed in <a href="https://github.com/prisma/prisma-next/pull/984">#984</a>; the typed <code>.select()</code> surface still offers base-model fields only).</li>
<li>Variant lookup is namespace-flat, so two variants with the same name in different namespaces can't be addressed (<a href="https://linear.app/prisma-company/issue/TML-2841">TML-2841</a>, in progress).</li>
<li>The model accessor's return type isn't variant-aware (<a href="https://linear.app/prisma-company/issue/TML-2847">TML-2847</a>, in progress).</li>
<li>The shorthand <code>.where({priority: 1})</code> form rejects variant fields that the callback form accepts (<a href="https://linear.app/prisma-company/issue/TML-2982">TML-2982</a>, open).</li>
<li>Bulk <code>createAll()</code> on a variant silently drops write annotations (<a href="https://linear.app/prisma-company/issue/TML-2600">TML-2600</a>, open).</li>
<li>A variant model declaring a column that collides with a base-table column silently merges instead of failing validation (<a href="https://linear.app/prisma-company/issue/TML-2827">TML-2827</a>, open).</li>
</ul>
<p>On July 24 we decide from this list and the discovery rate, not from hope: if it's shrinking and nothing new is appearing, polymorphism ships inside the stability promise; otherwise it ships clearly labeled experimental and stabilization continues after the RC without blocking it.</p>
</div>
</details>
</section>
<section class="req" id="req2">
<span class="reqno">Requirement 2</span>
<span class="owner" style="margin-left: 8px;">Serhii</span>
<h2>The schema language must reach its final form</h2>
<p class="soft">Users write their data model in Prisma Schema Language (PSL) files. Whatever syntax the RC accepts is the syntax v8 supports forever — so every planned change to the language must land before July 31 or be abandoned. Four language changes are planned — mixins, native column types, directional relations, and tagged SQL fences — plus one item that follows from them: removing <code>@dbgenerated()</code> builds on the tagged fences.</p>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Mixins: reusable, named sets of fields</span><span class="crit">CRITICAL PATH</span><span class="pill flight">Design in progress</span></summary>
<div class="body">
<p>The long-standing ask — share <code>createdAt</code>/<code>updatedAt</code>/tenant-id fields across many models without copy-paste — gets a first-class answer: define the fields once in a named <code>mixin</code> block, include them with <code>@@include(WithTimestamps)</code>. Mixins deliberately take no parameters (variations get their own names), and they replace two existing mechanisms that grew complicated trying to solve the same problem: <em>field presets</em> (pack-shipped field templates with an argument system) and <em>type aliases</em>. Both retire.</p>
<p>Decided by the team on July 20; design in progress. Tracked as <a href="https://linear.app/prisma-company/issue/TML-3055/psl-mixins-named-field-set-reuse-retire-field-presets-type-aliases-and">TML-3055</a>. This is the largest single pre-release work item.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Native column types move onto type constructors; <code>@db.*</code> attributes are deleted</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>Prisma 7 spelled database-native column types with attributes: <code>email String @db.VarChar(255)</code>. Prisma 8 replaces that spelling with the type written directly in the type position: <code>email VarChar(255)</code>, <code>id Uuid</code>, <code>payload Jsonb</code>. The type says what the column is; no attribute needed. All <code>@db.*</code> attribute support is deleted from the language before the freeze — shipping both spellings would freeze both forever.</p>
<p>Both halves have landed. The scalar-type unification — every scalar becomes a zero-argument type constructor under one contribution mechanism, with the Postgres native constructors exposed — landed first (<a href="https://linear.app/prisma-company/issue/TML-2986">TML-2986</a>, <a href="https://github.com/prisma/prisma-next/pull/1022">#1022</a>). The <code>@db.*</code> channel itself is now deleted (<a href="https://linear.app/prisma-company/issue/TML-2988">TML-2988</a>, landed as <a href="https://github.com/prisma/prisma-next/pull/1054">#1054</a>): writing a <code>@db.*</code> attribute fails with a diagnostic that spells out the replacement, e.g. <code>@db.Uuid is no longer supported; use Uuid in type position</code>. Only the bare-type spelling survives the freeze.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Relations get a directional spelling; <code>@relation(name:)</code> retires</span><span class="pill flight">In flight</span></summary>
<div class="body">
<p>Prisma 7 expressed relations with paired fields on both models and disambiguated with <code>@relation(name: "...")</code> strings — a spelling users routinely get wrong. Prisma 8 replaces it with directional syntax: a foreign key declares where it points (<code>from</code>/<code>to</code>), many-to-many goes through an explicit junction (<code>through: Junction</code>) or an implicit one synthesized for you, and multi-hop paths spell the route out (<code>a -> J.b -> J.c -> T.d</code>). Five slices, all in flight (<a href="https://linear.app/prisma-company/issue/TML-2940">TML-2940</a> through <a href="https://linear.app/prisma-company/issue/TML-2944">TML-2944</a>). This is frozen-surface work on exactly the same clock as mixins: whatever relation spelling the RC accepts is the spelling for the life of v8.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">SQL embedded in schemas gets proper fences instead of escaped strings</span><span class="pill open">Open</span></summary>
<div class="body">
<p>Schemas sometimes need to carry a piece of literal SQL: a view definition, a partial-index condition, a row-level-security policy expression, a database-computed default. Today those travel as ordinary quoted strings, with all the escaping pain that implies. The accepted design (<a href="https://github.com/prisma/prisma/blob/main/docs/architecture%20docs/adrs/ADR%20129%20-%20Template-Tagged%20Literals%20for%20Extensions.md">ADR 129</a>) is a tagged backtick fence — <code>pg.sql`SELECT 1`</code> — with no string interpolation, cleanly handed to the extension that owns it. It is not implemented yet; if it doesn't land, the quoted-string form freezes as the API.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t"><code>@dbgenerated()</code> is removed; database-computed defaults become tagged fences</span><span class="pill open">Open</span></summary>
<div class="body">
<p>Prisma 7 spelled "the database computes this default" as an attribute wrapping a SQL string: <code>@default(dbgenerated("gen_random_uuid()"))</code> — a quoted string with escaping problems and no ownership story. Prisma 8 removes <code>@dbgenerated()</code> entirely: a raw SQL default is written as a tagged backtick fence (the mechanism above), so the same one syntax carries every piece of embedded SQL in a schema. This depends on the tagged-fence implementation landing first. It also reaches beyond the parser: the Postgres and SQLite default-handling code and the introspection path (which meets <code>dbgenerated</code>-shaped defaults in every real existing database, and must <em>emit</em> tagged fences for them) all change with it.</p>
</div>
</details>
</section>
<section class="req" id="req3">
<span class="reqno">Requirement 3</span>
<span class="owner" style="margin-left: 8px;">Will</span>
<h2>Every name and format users depend on must be final</h2>
<p class="soft">Users write <code>catch</code> blocks against error codes, commit generated contract and migration files to their repositories, and write config files against our keys. All of that becomes permanent API at the RC. Five changes must land first — sequenced together, because several of them alter the same generated files and users should see one change, not five.</p>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">One error-code scheme instead of four</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>Prisma 8 grew four separate error systems with two incompatible code formats — about 46 codes shaped like <code>PN-CLI-4001</code> and about 89 shaped like <code>RUNTIME.DECODE_FAILED</code> — plus roughly sixteen error classes carrying no code at all. That's over: every published error is now a structural envelope with a dotted <code>NAMESPACE.SUBCODE</code> code, recognized by a type predicate instead of <code>instanceof</code> (<a href="https://linear.app/prisma-company/issue/TML-3067">TML-3067</a>); the ORM's and the contract-authoring plane's formerly codeless throws carry structured <code>ORM.*</code> / <code>CONTRACT.*</code> codes (<a href="https://linear.app/prisma-company/issue/TML-3070">TML-3070</a>, <a href="https://linear.app/prisma-company/issue/TML-3075">TML-3075</a>); and the reference page documenting all 221 published codes ships in-repo with a CI check that fails any change adding an undocumented code (<a href="https://linear.app/prisma-company/issue/TML-3071">TML-3071</a>). The old→new crosswalk is published in ADR 239 and feeds the v8 upgrade guide. What continues after the freeze is non-breaking by construction: sweeping the adapter and extension planes' remaining codeless throws onto the same scheme only <em>adds</em> codes. Prisma 7's <code>P1001</code>-style codes are deliberately not carried over — the upgrade guide will include a translation table for migrating monitoring rules and runbooks.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Rename the <code>extensionPacks</code> config key to <code>extensions</code></span><span class="pill done">Landed</span></summary>
<div class="body">
<p>A simple rename with a deep reach: the key lived in user config files, in the generated contract document's schema, and in the code that canonicalizes and hashes contracts. It is now <code>extensions</code> everywhere, a guard rejects the old key, and every contract hash, migration, and snapshot was regenerated. The config-format sweep rode along — <code>contract.source.sourceFormat</code> became <code>format</code> and the sugar <code>outputPath</code> became <code>output</code> — with the ADRs and the consumer and extension-author upgrade recipes updated to match. (<a href="https://linear.app/prisma-company/issue/TML-2462">TML-2462</a>, <a href="https://github.com/prisma/prisma-next/pull/1032">#1032</a>)</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Hashes lose their <code>sha256:</code> prefix</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>Prisma 8 identifies contracts and migrations by content hash, and every hash used to be written with an algorithm prefix: <code>"storageHash": "sha256:9f49…"</code>. The prefix added nothing (the algorithm isn't going to vary per hash) and it appeared everywhere users see a hash — generated contract files, migration manifests, the bookkeeping tables Prisma maintains in the user's database. The textual form of hashes freezes at the RC, so the prefix was dropped now, in one sweep across the source plus regenerated examples (<a href="https://linear.app/prisma-company/issue/TML-2756">TML-2756</a>, <a href="https://github.com/prisma/prisma-next/pull/1033">#1033</a>).</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Store each contract snapshot once instead of copying it into every migration</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>Every migration folder used to carry full copies of the data contract it goes from and to — so a project with N migrations stored roughly 2N copies of N+1 distinct documents. They now live in a single <code>migrations/snapshots/<hash>/</code> store, one file per distinct contract, named by its content hash; migration folders already record which hashes they go from and to, so they need no new linking files. A migration's identity hash deliberately doesn't cover the snapshots, so converting the layout invalidated no existing migration (<a href="https://linear.app/prisma-company/issue/TML-3059">TML-3059</a>, <a href="https://github.com/prisma/prisma-next/pull/1018">#1018</a>), and a one-shot migrator converts existing projects' committed migration trees. A follow-up folded the last full-contract copies — the ref-paired snapshots — into the same store, so a ref is now a pure <code>{hash, invariants}</code> pointer and "snapshot" is a single concept (<a href="https://linear.app/prisma-company/issue/TML-3072">TML-3072</a>, <a href="https://github.com/prisma/prisma-next/pull/1024">#1024</a>). This closes the migrations-folder layout ahead of the freeze — users commit these folders to their repositories.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Sweep out the old <code>prisma-next</code> name everywhere it's baked in</span><span class="pill open">Open</span></summary>
<div class="body">
<p>After the package rename (requirement 5), the old name survives in places that are easy to forget and hard to change later: the project templates that <code>prisma-next init</code> writes for new users, the agent skills it installs into user projects, the documentation links embedded inside error messages (which must resolve to real pages on release day), and internal-looking names that are actually permanent — environment variable names, the per-user config file path, telemetry identifiers. Each gets an explicit keep-or-rename decision before the freeze makes the choice for us.</p>
</div>
</details>
</section>
<section class="req" id="req4">
<span class="reqno">Requirement 4</span>
<span class="owner" style="margin-left: 8px;">Everyone</span>
<h2>The release's claims must be proven</h2>
<p class="soft">The announcement will make two big claims: <em>everything Prisma 8 ships works</em>, and <em>you can run Prisma 7 and Prisma 8 side by side and migrate incrementally</em>. With early-access adoption having been thin, tests have to do the confidence-building work that production feedback normally would. Each claim gets a runnable receipt.</p>
<details class="task" open>
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">The feature scoreboard: 593 features × 3 databases, every "works" backed by a named test</span><span class="pill flight">In flight</span></summary>
<div class="body">
<p>A matrix of every feature against every supported database (Postgres, SQLite, MongoDB). Each cell holds a verdict: <strong>works</strong> (and names the test suite that proves it), <strong>unproven</strong> (reachable, but no test demonstrates it yet), <strong>experimental</strong> (shipped, outside the stability promise), or <strong>not in 8.0</strong> (a deliberate, written-down absence — nothing is allowed to be silently missing). The rows come from two directions: everything Prisma 8's public surface exposes, crossed with every notable Prisma 7 capability, so absences are named rather than discovered.</p>
<div class="meter">
<div class="bar" role="img" aria-label="Of 916 availability-claiming cells: 416 proven, 488 unproven, 12 experimental">
<div class="seg1" style="width: 45.4%"></div>
<div class="seg2d" style="width: 53.3%"></div>
</div>
<div class="legend">
<span><span class="dot" style="background: var(--accent)"></span><b>416</b> proven by a named test</span>
<span><span class="dot" style="background: var(--warn); opacity: 0.45"></span><b>488</b> unproven — the test-writing queue</span>
<span><span class="dot" style="background: var(--open-bg); outline: 1px solid var(--line-strong); outline-offset: -1px;"></span><b>12</b> experimental</span>
</div>
</div>
<p>A further <strong>244</strong> cells are deliberate, named absences ("not in 8.0"). The scorecard is merged in-repo — <a href="scorecard.md">scorecard.md</a> plus 19 category files — and is updated as gaps are found (most recently eight compatibility gaps, <a href="https://github.com/prisma/prisma/pull/29881">#29881</a>). The unproven column is literally the remaining test-writing queue, and the rendered matrix ships publicly with the RC — progress from here on is cells flipping from unproven to proven. No CI job renders or checks the scorecard yet.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Capabilities still landing before the verdicts freeze on July 24</span><span class="pill flight">In flight</span></summary>
<div class="body">
<p>Several features are mid-flight; their scoreboard cells can't get final verdicts until they land or get cut:</p>
<ul>
<li><strong>Native scalar arrays</strong> — <code>String[]</code>, <code>Int[]</code> and friends as real Postgres array columns, end-to-end from schema authoring through querying, filtering, and mutation. Slices 2 and 3 in flight (<a href="https://linear.app/prisma-company/issue/TML-2912">TML-2912</a>, <a href="https://linear.app/prisma-company/issue/TML-2913">TML-2913</a>).</li>
<li><strong>Enums on every database</strong> — the plan to treat enums as an application-level concept so they work uniformly on Postgres, SQLite, and MongoDB rather than only where the database has native enums (<a href="https://linear.app/prisma-company/issue/TML-2815">TML-2815</a>, planning in progress).</li>
<li><strong>Polymorphism in the TypeScript authoring path</strong> — schemas written in TypeScript (instead of PSL) can't declare inheritance yet; the PSL path can (<a href="https://linear.app/prisma-company/issue/TML-2228">TML-2228</a>, open). Until it lands, the scoreboard carries the asymmetry explicitly.</li>
</ul>
<p>Anything on this list that misses July 24 gets its cells stamped as they actually are — unproven, experimental, or not in 8.0 — rather than holding the freeze.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Raw query support</span><span class="pill open">Open</span></summary>
<div class="body">
<p>An ORM needs an escape hatch: when the query builder can't express something, users drop to raw SQL (Prisma 7's <code>$queryRaw</code>/<code>$executeRaw</code>) or raw database commands. Prisma 8's pieces exist but are unproven and incomplete: the <code>rawSql</code> expression inside the typed builder is proven on Postgres and SQLite, but the statement-level <code>raw</code> SQL tag (<code>client.raw</code>) and the raw Mongo client have no proving integration test, and Prisma 7's composition surface — <code>Prisma.sql</code>/<code>Prisma.join</code>/<code>Prisma.raw</code>/<code>Prisma.empty</code> fragments, typed fragment generics, TypedSQL — is currently marked <em>not in 8.0</em>. Migrating users reach for the escape hatch on day one, so the existing surfaces need proving tests and the fragment-composition story needs an explicit ship-or-name-the-absence decision before the freeze makes "not in 8.0" permanent. Current state: <a href="scorecard/13-raw-and-typed-sql.md">scorecard/13-raw-and-typed-sql.md</a>.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">The side-by-side proof: both versions, one database, migrating incrementally</span><span class="crit">CRITICAL PATH</span><span class="pill open">Open</span></summary>
<div class="body">
<p>The incremental-migration story is: keep Prisma 7 running and owning your database schema; install Prisma 8 alongside it in the same project; let Prisma 8 <em>adopt</em> the database read-only (it derives a schema from the live database, verifies the database matches, and records that fact — without touching Prisma 7's migration state); move code over gradually; cut over once at the end. Every individual mechanism in that story exists and is tested. <strong>The whole story has never been run end-to-end</strong> — a planned real-world evaluation never happened — which makes it the release's biggest untested claim.</p>
<p>So we build it as a permanent test: one project with both versions installed, one Postgres database, Prisma 7 running its migrations and Prisma 8 adopting, querying, and re-adopting after schema changes — run under each of npm, pnpm, Yarn, and Bun, because installing two versions side by side is exactly where package managers differ. Must be green by July 24, or the announcement's migration claim gets scaled back to what's actually proven. The upgrade guide's code samples get lifted from this project, so the documentation is executable by construction.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">TypeScript performance measured before the types freeze</span><span class="pill open">Open</span></summary>
<div class="body">
<p>Prisma 8 leans heavily on advanced TypeScript types, which is exactly the pattern that can make a big project's type-checking slow. We measure now — generated projects of 10, 100, and 500 models, checked with both today's TypeScript and the new Go-based TypeScript 7 compiler — because if the numbers are bad, the types can only be fixed while they're still allowed to change. Results publish to a public dashboard, and pull requests fail if they make type-checking meaningfully more expensive (measured by the compiler's deterministic work counters, not by flaky wall-clock time on shared CI runners).</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Port Prisma 7's accumulated edge-case tests against the unproven cells</span><span class="pill flight">In flight</span></summary>
<div class="body">
<p>Prisma 7's functional test suite encodes years of database and query edge cases. Converting it wholesale would take months and mostly port API details that no longer exist — so we mine it instead: for each scoreboard cell that says "works" without a proving test, find the Prisma 7 tests covering that feature and port just those scenarios. Where comparing against Prisma 7's behavior is cheaper than porting assertions, the side-by-side project doubles as the comparison harness. The port is underway — 1,423 of 6,304 in-scope scenarios accounted across five waves (<a href="https://github.com/prisma/prisma-next/pull/1035">#1035</a>, <a href="https://github.com/prisma/prisma-next/pull/1042">#1042</a>, <a href="https://github.com/prisma/prisma/pull/29832">#29832</a>, <a href="https://github.com/prisma/prisma/pull/29912">#29912</a>); the three functional checklists are complete at 1,423 of 1,423, the engines corpus untouched. The per-test ledger lives in <code>projects/port-all-tests/checklists/</code>. This is a stream, not a step; it continues past the RC, visibly, on the public scoreboard.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Expression, partial, and unique indexes — authorable, name-identified, adoptable</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>Prisma 8 can now author the indexes real Postgres databases actually carry: expression indexes (<code>@@index(expression: "eql_v3.eq_term(email)", name: "users_email_eq")</code> — the exact shape Cipherstash's encrypted-search EQL extension needs), partial (<code>where:</code>) and unique variants, access methods, and storage options — in PSL and the TypeScript authoring path alike. Indexes and row-level-security policies became name-identified entities: a wire-named object's physical name ends in a content hash, so a body edit converges as create + drop while a pure rename converges as a single <code>ALTER INDEX … RENAME</code>; <code>map:</code> adopts an existing physical name verbatim. <code>contract infer</code> emits every live index and policy at full fidelity, so an existing database can be adopted and signed exactly as it stands — and converted to wire naming later by nothing but renames. (<a href="https://github.com/prisma/prisma-next/pull/1047">#1047</a>, <a href="https://github.com/prisma/prisma-next/pull/1048">#1048</a>, <a href="https://github.com/prisma/prisma-next/pull/1050">#1050</a>, <a href="https://github.com/prisma/prisma/pull/29808">#29808</a>)</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Adopting an existing database round-trips cleanly</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>The adoption path had a credibility problem: deriving a schema from a live database produced output that Prisma 8's own tooling then rejected or flagged as drifted — a user had independently written a 260-line repair script to fix our output, and it matched the workaround script in our own repository. Seven distinct defects were fixed, and the whole loop (read the database → derive the schema → emit the contract → verify the database matches) now runs as an automated test against live databases. This is the foundation the side-by-side proof builds on.</p>
</div>
</details>
</section>
<section class="req" id="req5">
<span class="reqno">Requirement 5</span>
<span class="owner" style="margin-left: 8px;">Alexey</span>
<h2>The code must move into prisma/prisma</h2>
<p class="soft">Prisma 8 has so far been developed in a separate repository, <code>prisma/prisma-next</code>. Before release, everything moves into <code>prisma/prisma</code> — the repository users already watch, star, and file issues against — so Prisma 8 arrives as the main line of Prisma, not a side project. Moving is much more than copying code: the two repositories' git histories have to be joined, CI has to run green in its new home, the npm publishing pipeline has to serve v8 and v7 side by side, thousands of open v7 issues and pull requests need a decision, the automation in other repositories that points at prisma/prisma has to keep working afterward, and the old prisma-next repository has to be visibly retired. Prisma 7 doesn't stop: it continues from a <code>v7</code> branch in the same repository, with bug fixes promised for 12 months after 8.0.0 final ships.</p>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Move the code into prisma/prisma</span><span class="pill done">Landed · plan revised</span></summary>
<div class="body">
<p>The move happened July 27–28: this repository <em>is</em> prisma/prisma, v8 is <code>main</code>, and everything since lands under prisma/prisma PR numbers (<a href="https://github.com/prisma/prisma/pull/29825">#29825</a>, <a href="https://github.com/prisma/prisma/pull/29826">#29826</a>). The originally planned history graft was dropped: <code>main</code> carries prisma-next's history only and shares no ancestor with the <code>v7</code> branch, so <code>git log</code>/<code>git blame</code> on <code>main</code> do not reach 7.x. The old 5.x/6.x/7.x tags still resolve, and a signpost on the default branch points Prisma 7 users at the <code>v7</code> branch.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Rewire the publishing pipeline — inside prisma/prisma and in the repositories connected to it</span><span class="pill flight">In flight</span></summary>
<div class="body">
<p>The in-repo half is done: <code>publish.yml</code> publishes v8 from <code>main</code> via OIDC trusted publishing with provenance (unchanged version → <code>dev</code> dist-tag, bumped version → <code>latest</code> plus a GitHub Release), and five <code>v7-*</code> registration stubs on <code>main</code> dispatch to the real workflows on the <code>v7</code> branch, so neither pipeline disturbs the other (<a href="https://github.com/prisma/prisma/pull/29803">#29803</a>, <a href="https://github.com/prisma/prisma/pull/29823">#29823</a>, <a href="https://github.com/prisma/prisma/pull/29840">#29840</a>, <a href="https://github.com/prisma/prisma/pull/29880">#29880</a>, <a href="https://github.com/prisma/prisma/pull/29884">#29884</a>, <a href="https://github.com/prisma/prisma/pull/29886">#29886</a>). What remains is the cross-repository half: the written inventory of workflows in other repositories wired into prisma/prisma's publishing, and re-pointing each of them. That inventory doesn't exist yet.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Take over the <code>prisma</code> package name — carefully</span><span class="pill open">Open</span></summary>
<div class="body">
<p>The <code>prisma</code> package becomes Prisma 8's command-line tool, published under a pre-release tag so <code>npm install prisma</code> keeps giving people Prisma 7 until 8.0.0 final. The three per-database packages users import get new names: <code>@prisma/postgres</code>, <code>@prisma/sqlite</code>, <code>@prisma/mongo</code> (checked for collisions against the many <code>@prisma/*</code> names Prisma 7 already publishes). Only those four packages rename — the ~60 internal packages that arrive automatically as dependencies keep their <code>@internal/*</code> names and are explicitly not part of the supported surface. <em>(The package naming here is superseded by the namespace restructure below — facades are now spelled like <code>@prisma/orm-postgres</code>, and the internal packages do move.)</em> The v8 tool installs a single command, <code>prisma-next</code> — deliberately <em>not</em> <code>prisma</code>, so in a project that has both versions installed, <code>prisma</code> always unambiguously means Prisma 7, on every package manager. (Whether v8 ever claims the bare <code>prisma</code> command is deferred; adding a command later breaks nothing.) The old <code>prisma-next</code> package gets a deprecation notice pointing at its new home.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Restructure the npm package namespaces</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>Delivered, with one revision to the plan: no second namespace exists. 17 packages are published — 16 under the single <code>@prisma</code> scope plus the unscoped <code>prisma-next</code> bin shim: three database facades (<code>@prisma/orm-postgres</code>, <code>@prisma/orm-sqlite</code>, <code>@prisma/orm-mongo</code>; an application depends on exactly one), six extension packs, seven platform packages the facades depend on, and the shim (<a href="https://github.com/prisma/prisma/blob/main/docs/architecture%20docs/adrs/ADR%20242%20-%20Public%20npm%20surface%20-%20single%20%40prisma%20scope%20with%20consolidated%20publish%20packages.md">ADR 242</a>). The ~60 internal implementation packages are not published at all — they are <code>private: true</code> and their code reaches npm bundled inside the platform packages, so the planned <code>@prisma-orm</code> namespace (and the deprecation sweep it would have required) became unnecessary. CI enforces the shape: publishability is a directory property (<code>packages/9-public/</code> and nothing else), every publishable manifest must declare the canonical repository (npm provenance verification depends on it), and the legacy <code>@prisma-next</code> name is lint-banned outside historical documents. All 17 packages publish via OIDC trusted publishing — no long-lived npm tokens — with provenance attestations, configured per package on npmjs.com.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Deprecate the old prisma-next repository</span><span class="pill open">Open</span></summary>
<div class="body">
<p>Development has moved here, but <a href="https://github.com/prisma/prisma-next">prisma/prisma-next</a> still exists with its issues, PRs, and watchers — and nothing tells a visitor it's dead. Before the announcement: archive the repository, point its README at prisma/prisma, and decide what happens to anything still open there (open items move here or get closed with a pointer). Links into the old repo — including the <code>#10xx</code> PR references on this page — keep resolving after archival, so nothing breaks; the goal is just that nobody lands there and thinks it's where Prisma 8 lives.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Decide the fate of every open v7 issue and pull request</span><span class="pill open">Open</span></summary>
<div class="body">
<p>prisma/prisma has years of open issues and PRs written against Prisma 7. When v8 becomes <code>main</code>, we close everything except genuine v7 bug reports (which stay open against the <code>v7</code> branch), post a pinned issue explaining what happened and why, and answer follow-ups with a saved reply pointing at it. This deliberately happens at merge time, not earlier — closing thousands of issues weeks before there's an announcement to point at would produce weeks of confusion. Issue templates get a version chooser at the same time, so new reports arrive sorted into v7 vs v8.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">The <code>v7</code> maintenance branch, with working CI</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>The <code>v7</code> branch exists with Prisma 7's code, tests, and release automation, and its CI actually works there — test, publish, benchmark, and auxiliary workflows all run on the branch, with dispatch stubs registered on <code>main</code>, CodeRabbit reviews enabled, and the 7.x docs pointed at it (<a href="https://github.com/prisma/prisma/pull/29803">#29803</a>, <a href="https://github.com/prisma/prisma/pull/29822">#29822</a>, <a href="https://github.com/prisma/prisma/pull/29827">#29827</a>, <a href="https://github.com/prisma/prisma/pull/29828">#29828</a>). This branch is where 12 months of promised bug fixes ship from.</p>
</div>
</details>
</section>
<section class="req" id="req6">
<span class="reqno">Requirement 6</span>
<span class="owner" style="margin-left: 8px;">Everyone</span>
<h2>The rough edges users hit on day one must be gone</h2>
<p class="soft">None of these block anything technically. All of them are what a skeptical engineer meets in their first hour, under announcement-day attention. The items marked <em>verified July 28</em> are dogfooding gotchas that were re-checked against <code>main</code> on July 28 and confirmed still present — and the migration-tooling ones among them risk real data loss, not just embarrassment.</p>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">A dropped database connection can crash the host process</span><span class="pill open">Open</span></summary>
<div class="body">
<p>When an idle pooled connection drops (a database restart, a network blip), the error has no listener attached and crashes the whole Node.js process. A production-readiness bug, not housekeeping — fixed before anyone's production meets it. (<a href="https://linear.app/prisma-company/issue/TML-2655">TML-2655</a>)</p>
<p>Re-verified August 5: now <em>three</em> places build a <code>pg.Pool</code> with no <code>'error'</code> handler — the postgres driver's <code>url</code> binding, the postgres extension runtime, and the supabase extension — and the <code>db.ts</code> that <code>prisma-next init</code> scaffolds still uses exactly that path, so every scaffolded app deployed behind a connection pooler is exposed. A production app on Prisma Compute already hit this; the whole process died on each idle-connection drop. (<a href="https://linear.app/prisma-company/issue/TML-2842">TML-2842</a>)</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t"><code>migration plan</code> can silently generate a destructive baseline</span><span class="pill open">Open</span></summary>
<div class="body">
<p><em>Verified July 28 · data-loss risk.</em> With no <code>--from</code>, <code>migration plan</code> picks its origin from the refs index, not from the latest on-disk migration — and a ref pointing at a non-tip node is explicitly accepted, with no warning. On an empty migration graph it auto-writes a <code>baseline</code> package anchored at whatever the ref says, so a stale or destination-pointing ref yields a plan containing operations like <code>dropTable</code> toward origin. There is no dirty-ref detection and no baseline-specific destructive-operation warning, only the generic per-op <code>(destructive)</code> marker at render time. (<a href="https://linear.app/prisma-company/issue/TML-3097">TML-3097</a>)</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t"><code>migration new --from <hash></code> silently records <code>from: null</code></span><span class="pill open">Open</span></summary>
<div class="body">
<p><em>Verified July 28.</em> When the app's migrations directory is empty, the entire <code>--from</code> resolution is skipped: the flag is accepted, the scaffolded package records <code>from: null</code>, and nothing warns that the supplied hash was ignored. On a non-empty graph the flag works (and a bad hash errors properly) — the silent path is exactly the first-migration case. (<a href="https://linear.app/prisma-company/issue/TML-3096">TML-3096</a>)</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">A corrupted contract snapshot loads without complaint</span><span class="pill open">Open</span></summary>
<div class="body">
<p><em>Verified July 28.</em> No code path recomputes a loaded snapshot's storage hash and compares it to the persisted value. The snapshot store reads with a plain <code>JSON.parse</code>, the deserializer copies <code>storageHash</code> through untouched, and the migration-check codes only string-compare hash <em>fields</em> against each other. Hand-edit a snapshot's content while leaving its <code>storageHash</code> field alone and <code>migration plan</code> reports a clean <code>noOp: true</code>. The one existing recompute helper (<code>assertDescriptorSelfConsistency</code>) runs only on in-memory extension descriptors, never on disk loads. (<a href="https://linear.app/prisma-company/issue/TML-2566">TML-2566</a>)</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t"><code>.delete()</code> with a multi-row predicate deletes exactly one row</span><span class="pill open">Open</span></summary>
<div class="body">
<p><em>Verified July 28.</em> <code>.where({id: q.in([1,2,3])}).delete()</code> type-checks, deletes one row, and returns it. The single-row scoping is deliberate and test-pinned, and multi-row forms exist (<code>deleteAll()</code>, <code>deleteAndCount()</code>) — but nothing in the type system stops a multi-row predicate on <code>.delete()</code>, and the doc comment ("delete matching rows and return the first deleted row") reads as if it batches. A user who meant to delete three rows silently keeps two. Either the types constrain the predicate, or the name/docs make the one-row semantics impossible to miss. (<a href="https://linear.app/prisma-company/issue/TML-3093">TML-3093</a>)</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">PSL <code>Json</code> is Postgres <code>json</code>; Prisma 7's <code>Json</code> is <code>jsonb</code></span><span class="pill open">Open</span></summary>
<div class="body">
<p><em>Verified July 28.</em> Anyone porting a <code>schema.prisma</code> keeps writing <code>Json</code> and silently gets <code>json</code> columns where Prisma 7 gave them <code>jsonb</code>. Emit and check both pass; only <code>db verify</code> catches it, and it caught a real project three wrong columns late. The PSL diagnostic model currently has no warning severity to hang a "did you mean <code>Jsonb</code>?" advisory on, and the divergence is documented only in Prisma-Next-internal upgrade recipes, not in porting guidance. An emit-time warning or an explicit porting-docs callout must exist before day one, because day one is exactly when the ported schemas arrive. (<a href="https://linear.app/prisma-company/issue/TML-3102">TML-3102</a>)</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t"><code>prisma-next init --no-skill</code> deletes an installed agent-skill file</span><span class="pill open">Open</span></summary>
<div class="body">
<p><em>Verified July 28.</em> Init queues deletion of <code>.agents/skills/prisma-next/SKILL.md</code> unconditionally as "legacy cleanup" — the same path a genuinely installed router skill occupies. In the default run the subsequent skill install masks the delete by rewriting the file; with <code>--no-skill</code> the install never runs, so init destroys the user's installed skill and reports it only in the JSON <code>filesDeleted</code> list. (<a href="https://linear.app/prisma-company/issue/TML-2637">TML-2637</a>)</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">A deprecation warning prints on every single database connection</span><span class="pill done">Landed</span></summary>
<div class="body">
<p>Resolved: the query-overlap <code>DeprecationWarning</code> was closed by <a href="https://linear.app/prisma-company/issue/TML-3108">TML-3108</a> (<a href="https://github.com/prisma/prisma/pull/29839">#29839</a>) — the driver now serializes queries per pinned pg client, with a regression test asserting no warning — and no per-connection deprecation exists in the pg 8.22 APIs the driver uses. <a href="https://linear.app/prisma-company/issue/TML-2628">TML-2628</a> is closed.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Open security alerts on dependencies</span><span class="pill open">Open</span></summary>
<div class="body">
<p>The announcement puts many eyes on the repository; a visible backlog of automated vulnerability alerts on day one is a bad look and a support-ticket magnet. Cleared before the merge. (<a href="https://linear.app/prisma-company/issue/TML-2789">TML-2789</a>)</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">The npm page and editor experience for the packages people actually open</span><span class="pill open">Open</span></summary>
<div class="body">
<p>The <code>prisma</code> package's README becomes Prisma 8's face on npm. The four public packages' exported functions and types are what users see when they hover in their editor — those documentation comments get an audit. The ~60 internal packages get a short standard notice identifying them as implementation detail. (<a href="https://linear.app/prisma-company/issue/TML-1799">TML-1799</a>)</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">First-class editor support for the schema language</span><span class="pill flight">In flight</span></summary>
<div class="body">
<p>A language users write by hand deserves an editor that helps. Most of this has landed: the language server ships formatting, keyword and model-type completions, semantic-token coloring, folding, and interpreter-backed diagnostics, served via <code>prisma-next lsp --stdio</code> on the new syntax-tree parser (<a href="https://linear.app/prisma-company/issue/TML-2929">TML-2929</a>, <a href="https://linear.app/prisma-company/issue/TML-2947">TML-2947</a>, <a href="https://linear.app/prisma-company/issue/TML-2948">TML-2948</a> all landed). What remains: tracking the schema-language changes in requirement 2 as they land — or the editor will underline the new syntax as errors — and the VS Code extension packaging, which lives outside this repository.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">The editor doesn't fight itself in a two-version project</span><span class="pill open">Open</span></summary>
<div class="body">
<p>Users migrating incrementally will have Prisma 7's VS Code extension installed <em>and</em> Prisma 8's language server in the same project. Nobody has verified they coexist peacefully over schema files. Checked — and fixed or documented — before the announcement invites everyone into exactly that setup.</p>
</div>
</details>
<details class="task">
<summary><svg class="chev" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="t">Claims we haven't verified get verified or softened</span><span class="pill open">Open</span></summary>
<div class="body">
<p>Support statements that end up in the announcement get checked first: Windows, Bun, and Deno support levels; the telemetry first-run notice's wording; and whether the telemetry backend survives announcement-scale traffic.</p>
</div>
</details>
</section>
<section class="landed">
<h2>Recently landed</h2>
<ul>
<li><strong>The code moved into prisma/prisma</strong> — v8 is <code>main</code>, all work lands under prisma/prisma PR numbers, and the <code>v7</code> branch carries Prisma 7 with its own working CI (requirement 5).</li>
<li><strong>Expression, partial, and unique indexes landed end-to-end</strong> — authorable in PSL and TypeScript, name-identified (a wire name carries a content-hash suffix; <code>map:</code> adopts the live name verbatim), and emitted at full fidelity by <code>contract infer</code> so existing databases adopt cleanly (requirement 4).</li>
<li><strong>Relation-loading now reads every value losslessly through its type codec</strong> — nested JSON is canonical per codec: big integers arrive as <code>bigint</code>, decimals as exact strings, <code>Bytes</code> as bytes; a breaking change that regenerates contracts and changes nine codecs' JSON form (requirement 1).</li>
<li><strong>One error-code scheme, delivered end-to-end</strong> — every published error is a structural envelope with a dotted code; the ORM and contract-authoring planes' codeless throws were swept onto it; the 221-code reference page ships with a CI check that keeps it complete (requirement 3).</li>
<li><strong>Contract snapshots deduplicated into one content-addressed store</strong> — migration folders stopped carrying full contract copies, ref-paired snapshots folded in too, closing the migrations-folder layout ahead of the freeze (requirement 3).</li>
<li><strong>Hashes lost their <code>sha256:</code> prefix</strong> — the textual form of every content hash froze without the redundant algorithm tag (requirement 3).</li>
<li><strong><code>date</code> columns read through <code>.include()</code> now decode correctly</strong> — the <code>@db.Date</code> codec binding that had been missing (requirement 1).</li>
<li><strong>Scalar-type unification landed</strong> — every scalar is a zero-argument type constructor, with Postgres native constructors exposed (requirement 2).</li>
<li><strong>Adopting an existing database round-trips cleanly</strong> — seven defects fixed, proven against live databases (details in requirement 4).</li>
<li><strong>The feature scoreboard is merged in-repo</strong> — 593 features enumerated and verdict-ed across all three databases (<a href="scorecard.md">scorecard.md</a>).</li>
</ul>
</section>
<footer>
Detailed working docs: <a href="https://github.com/prisma/prisma-next/pull/986">the release project</a> · tracking: <a href="https://linear.app/prisma-company/project/prisma-8-rc1-7592265f700c">Linear — Prisma 8 RC1</a> · launch communications are planned separately and not covered here. This page is updated as work lands; the URL stays stable.
</footer>
</div>