Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion ROADMAP.html
Original file line number Diff line number Diff line change
Expand Up @@ -541,12 +541,55 @@ <h2>The code must move into prisma/prisma</h2>
<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.</p>
<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 July 28: both places that build a <code>pg.Pool</code> from a <code>url</code> binding still attach no <code>'error'</code> handler, 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 &lt;hash&gt;</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>

Expand Down
36 changes: 34 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,43 @@ Prisma 7's code, tests, and release automation move to a `v7` branch in prisma/p

## 6. The rough edges users hit on day one must be gone

None of these block anything technically. All of them are what a skeptical engineer meets in their first hour, under announcement-day attention.
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 *verified July 28* are dogfooding gotchas that were re-checked against `main` on July 28 and confirmed still present — and the migration-tooling ones among them risk real data loss, not just embarrassment.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use release-status wording that preserves the documented severity.

Both copies say the items do not block anything technically, although the section explicitly records a host-process crash and real data-loss risk. Replace the sentence in both files with wording such as “None are currently release blockers” to distinguish roadmap status from runtime impact.

  • ROADMAP.md#L221-L221: update the introductory status sentence.
  • ROADMAP.html#L544-L544: apply the same wording to keep the Markdown and HTML copies synchronized.

As per coding guidelines, keep documentation wording current and unambiguous.

📍 Affects 2 files
  • ROADMAP.md#L221-L221 (this comment)
  • ROADMAP.html#L544-L544
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ROADMAP.md` at line 221, Replace the introductory status sentence in
ROADMAP.md at lines 221-221 and ROADMAP.html at lines 544-544 with
release-status wording such as “None are currently release blockers,” preserving
the documented runtime severity and keeping both copies synchronized.

Source: Coding guidelines


<details><summary>⬜ <b>A dropped database connection can crash the host process</b></summary>
<details><summary>⬜ <b>A dropped database connection can crash the host process</b> · verified July 28</summary>

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. ([TML-2655](https://linear.app/prisma-company/issue/TML-2655))

Re-verified July 28: both places that build a `pg.Pool` from a `url` binding still attach no `'error'` handler, and the `db.ts` that `prisma-next init` 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. ([TML-2842](https://linear.app/prisma-company/issue/TML-2842))
</details>

<details><summary>⬜ <b>`migration plan` can silently generate a destructive baseline</b> · verified July 28 · data-loss risk</summary>

With no `--from`, `migration plan` 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 `baseline` package anchored at whatever the ref says, so a stale or destination-pointing ref yields a plan containing operations like `dropTable` toward origin. There is no dirty-ref detection and no baseline-specific destructive-operation warning, only the generic per-op `(destructive)` marker at render time. ([TML-3097](https://linear.app/prisma-company/issue/TML-3097))
</details>

<details><summary>⬜ <b>`migration new --from <hash>` silently records `from: null`</b> · verified July 28</summary>

When the app's migrations directory is empty, the entire `--from` resolution is skipped: the flag is accepted, the scaffolded package records `from: null`, 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. ([TML-3096](https://linear.app/prisma-company/issue/TML-3096))
</details>

<details><summary>⬜ <b>A corrupted contract snapshot loads without complaint</b> · verified July 28</summary>

No code path recomputes a loaded snapshot's storage hash and compares it to the persisted value. The snapshot store reads with a plain `JSON.parse`, the deserializer copies `storageHash` through untouched, and the migration-check codes only string-compare hash *fields* against each other. Hand-edit a snapshot's content while leaving its `storageHash` field alone and `migration plan` reports a clean `noOp: true`. The one existing recompute helper (`assertDescriptorSelfConsistency`) runs only on in-memory extension descriptors, never on disk loads. ([TML-2566](https://linear.app/prisma-company/issue/TML-2566))
</details>

<details><summary>⬜ <b>`.delete()` with a multi-row predicate deletes exactly one row</b> · verified July 28</summary>

`.where({id: q.in([1,2,3])}).delete()` type-checks, deletes one row, and returns it. The single-row scoping is deliberate and test-pinned, and multi-row forms exist (`deleteAll()`, `deleteAndCount()`) — but nothing in the type system stops a multi-row predicate on `.delete()`, 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. ([TML-3093](https://linear.app/prisma-company/issue/TML-3093))
</details>

<details><summary>⬜ <b>PSL `Json` is Postgres `json`; Prisma 7's `Json` is `jsonb`</b> · verified July 28</summary>

Anyone porting a `schema.prisma` keeps writing `Json` and silently gets `json` columns where Prisma 7 gave them `jsonb`. Emit and check both pass; only `db verify` 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 `Jsonb`?" 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. ([TML-3102](https://linear.app/prisma-company/issue/TML-3102))
</details>

<details><summary>⬜ <b>`prisma-next init --no-skill` deletes an installed agent-skill file</b> · verified July 28</summary>

Init queues deletion of `.agents/skills/prisma-next/SKILL.md` 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 `--no-skill` the install never runs, so init destroys the user's installed skill and reports it only in the JSON `filesDeleted` list. ([TML-2637](https://linear.app/prisma-company/issue/TML-2637))
</details>

<details><summary>⬜ <b>A deprecation warning prints on every single database connection</b></summary>
Expand Down
Loading