Skip to content

TML-2748: migration status overlays applied and pending on the shared migration tree#705

Merged
wmadden-electric merged 12 commits into
mainfrom
tml-2748-migration-status-tree-overlay
Jun 3, 2026
Merged

TML-2748: migration status overlays applied and pending on the shared migration tree#705
wmadden-electric merged 12 commits into
mainfrom
tml-2748-migration-status-tree-overlay

Conversation

@wmadden-electric

@wmadden-electric wmadden-electric commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

At a-glance

Connected database with one migration still to run:

$ prisma-next migration status --no-color
app:
○   3b2d98d                      (contract) (main)
│↑  20260305_add_avatar    73e3abe → 3b2d98d   ⧗ pending
○   73e3abe                      (db)
│✓  20260303_add_phone     ef9de27 → 73e3abe   ✓ applied
○   ef9de27
│✓  20260301_init          ∅ → ef9de27         ✓ applied
○   ∅

1 pending — run `prisma-next migrate --to 3b2d98d`

Hypothetical origin (--from drops applied glyphs and the (db) marker; pending is still the shortest path from that origin to the target):

$ prisma-next migration status --no-color --from ef9de27 --to 3b2d98d
app:
○   3b2d98d                      (contract) (main)
│↑  20260305_add_avatar    73e3abe → 3b2d98d   ⧗ pending
○   73e3abe
│↑  20260303_add_phone     ef9de27 → 73e3abe   ⧗ pending
○   ef9de27
│↑  20260301_init          ∅ → ef9de27
○   ∅

2 pending — run `prisma-next migrate --to 3b2d98d`

(Representative output — same tree renderer and overlay rules exercised in CLI unit tests and integration journeys.)

The decision

migration status now overlays applied and pending state on the shared migration graph tree, giving you one picture of every on-disk migration's relationship to the database. Applied means a ledger row exists for that migration hash (green ). Pending means the edge sits on the shortest path from the DB marker (or --from origin) to the app contract and is not yet applied (yellow ). Everything else stays plain — the full on-disk graph, not a pruned subgraph. The old summary-only view and the dagre renderer are deleted; migration graph defaults to this tree (the experimental --tree flag is gone).

How we got here

One tree renderer for the read family

migration graph already renders contract topology as a condensed annotated tree (buildMigrationGraphRowsbuildMigrationGraphLayoutrenderMigrationGraphTree). list and status are meant to draw that same map with different overlays — package facts vs DB state — not maintain parallel layout code.

status used to look different

Previously, migration status fed a dagre layout and a compact summary that did not match graph or list. Applied edges were inferred from a graph walk from ∅ to the marker instead of the ledger, which could disagree with what actually ran.

Overlay on the shared renderer

Status computation builds edgeAnnotationsByHash (applied / pending) and passes them into the same tree renderer graph uses. The (db) marker reuses the existing dbHash node overlay. Multi-space projects get one tree section per space (with a spaceId: heading when there is more than one), matching list / graph.

--from for hypotheticals

--from <hash> overrides the path origin so you can ask offline: "what if my DB were at this contract?" Applied overlays are suppressed (they only make sense against the real DB); pending still follows the shortest path from the hypothetical origin to the target (--to or the app contract).

Dagre removed; tree is the default

With status on the shared tree, dagre had no remaining consumer. migration graph always renders the tree; --ascii, --legend, --dot, and --json remain. @dagrejs/dagre and its mapper/types/tests are removed.

What this PR does not change

  • --json wire shape — still mirrors migration list plus per-migration status, with markerHash / targetHash per space (documented in the slice spec).
  • migration list — separate slice (#706); this PR only shares the renderer hook list will populate later.
  • migration log — separate slice (#704); flat ledger history, not tree-shaped.

Linked issue

Refs TML-2748 (resolves applied-from-ledger TML-2130).

Testing performed

  • pnpm --filter @prisma-next/cli build
  • pnpm --filter @prisma-next/cli typecheck
  • pnpm --filter @prisma-next/cli test (status overlay, graph default-tree, dagre removal)
  • rg 'dagre|graphRenderer|migrationGraphToRenderInput' packages/1-framework/3-tooling/cli/ → empty
  • pnpm lint:deps

Checklist

  • All commits are signed off (git commit -s)
  • I read CONTRIBUTING.md and the change is scoped to one logical concern
  • Tests are updated
  • PR title is TML-2748: …
  • n/a — internal CLI surface; skill update not required for this slice

Alternatives considered

  • Keep dagre as a --graph alternative renderer — rejected. Two renderers split the family visually; dagre never matched the tree's information density for branching histories.
  • Three states (applied / pending / unreachable) — rejected. Two states cover every real workflow; unreachable edges stay plain on the full list.
  • Reimplement layout inside status — rejected. Share graph / list layout via the existing engine and differ only in overlays.

Summary by CodeRabbit

  • New Features

    • Added applied/pending status indicators to migration visualizations.
  • Bug Fixes

    • Improved migration status output with per-space reporting and clearer status summaries.
  • Chores

    • Removed unused dependency.
    • Simplified migration graph rendering pipeline.
    • Removed --tree CLI option; graph now renders in optimized format by default.

wmadden added 4 commits June 2, 2026 18:38
Introduce MigrationEdgeAnnotation and edgeAnnotationsByHash on the tree
renderer so applied (green check) and pending (yellow hourglass) glyphs
render on migration rows. Add ledger-sourced deriveStatusEdgeAnnotations
for status computation (replacing graph-walk applied detection).

Signed-off-by: Will Madden <madden@prisma.io>
Render the full per-space migration tree with applied/pending annotations
from the ledger and shortest-path pending set. Require a database unless
--from supplies the origin; emit list-shaped JSON with per-migration
status plus markerHash/targetHash per space. Replace the verbose footer
with a lean headline and missing-invariants line only.

Signed-off-by: Will Madden <madden@prisma.io>
Delete the dagre layout pipeline and @dagrejs/dagre dependency. The
condensed tree is now the only human renderer for migration graph; drop
the experimental --tree flag while keeping --ascii, --legend, --dot, and
--json.

Signed-off-by: Will Madden <madden@prisma.io>
Record the TML-2748 slice design for the shared-tree status command,
ledger-sourced applied set, and dagre retirement.

Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric wmadden-electric requested a review from a team as a code owner June 2, 2026 16:39
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 463bf11b-401f-4754-a279-162ad5878a5c

📥 Commits

Reviewing files that changed from the base of the PR and between 4379813 and 0facf95.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • packages/1-framework/3-tooling/cli/src/commands/migration-list.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-status.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migration-graph-tree-render.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/migration-graph-tree-render.test.ts
  • packages/1-framework/3-tooling/prisma-next/package.json
💤 Files with no reviewable changes (1)
  • packages/1-framework/3-tooling/prisma-next/package.json
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/1-framework/3-tooling/cli/src/commands/migration-list.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/migration-graph-tree-render.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migration-graph-tree-render.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-status.ts

📝 Walkthrough

Walkthrough

This PR removes the DAGRE flat-graph renderer, makes migration graph CLI commands render trees only, introduces per-edge applied/pending annotations derived from ledger and marker data, and updates command output types, tests, and e2e helpers to the new per-space JSON shape.

Changes

Per-Space Migration Status with Tree Rendering

Layer / File(s) Summary
Migration status edge-annotation layer
packages/1-framework/3-tooling/cli/src/commands/migration-status-overlay.ts, packages/1-framework/3-tooling/cli/test/commands/migration-status-overlay.test.ts
Adds deriveStatusEdgeAnnotations, appliedHashesFromLedger, and statusForMigrationHash to compute per-edge applied/pending annotations from ledger/marker data.
Migration status command per-space refactor
packages/1-framework/3-tooling/cli/src/commands/migration-status.ts, packages/1-framework/3-tooling/cli/test/commands/format-status-summary.test.ts, packages/1-framework/3-tooling/cli/test/commands/migration-invariants.test.ts, packages/1-framework/3-tooling/cli/test/output.json-shapes.test.ts
Rewrites migration status to operate per contract-space: load aggregate, resolve per-space target, optionally read DB markers/ledgers, derive edge annotations, render per-space tree sections, compute pending totals and summary, and emit simplified JSON (ok, spaces, summary, diagnostics, optional missingInvariantsLine).
Tree rendering with status annotations
packages/1-framework/3-tooling/cli/src/utils/formatters/migration-graph-tree-render.ts, packages/1-framework/3-tooling/cli/test/utils/formatters/migration-graph-tree-render.test.ts
Adds MigrationEdgeAnnotation and edgeAnnotationsByHash option; appends colored ✓ applied / ⧗ pending (or ASCII) suffixes to edge output and updates legend snapshots and tests.
Graph command and list utility updates
packages/1-framework/3-tooling/cli/src/commands/migration-graph.ts, packages/1-framework/3-tooling/cli/src/commands/migration-list.ts, packages/1-framework/3-tooling/cli/test/commands/migration-graph.test.ts
Removes --tree option and legacy flat-graph rendering imports/branch; migration-graph now always renders trees. Exports listRefsByContractHash. Legend-rendering tests adjusted to check new markers.
Renderer & types removal
packages/1-framework/3-tooling/cli/src/utils/formatters/graph-render.ts, packages/1-framework/3-tooling/cli/src/utils/formatters/graph-types.ts, packages/1-framework/3-tooling/cli/src/utils/formatters/graph-migration-mapper.ts
Deletes DAGRE-based renderer, related graph types and mapper; removes their exports and associated tests.
Dependency cleanup and test configuration
packages/1-framework/3-tooling/cli/package.json, packages/1-framework/3-tooling/prisma-next/package.json, packages/1-framework/3-tooling/cli/vitest.config.ts
Removes @dagrejs/dagre from package dependencies and updates Vitest coverage exclusions to reflect deleted formatter modules.
Tests, mocks, and e2e helper updates
packages/1-framework/3-tooling/cli/test/commands/*, test/integration/test/cli-journeys/*.e2e.test.ts, test/integration/test/utils/journey-test-helpers.ts
Expands family/driver mocks for marker/ledger reads, removes old graph-renderer tests, adds overlay unit tests, and updates many e2e tests to use parseMigrationStatusJson and migrationStatusAppSpace for the new per-space status JSON shape.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • wmadden

"🐰
I hopped through trees now simple and neat,
Applied in green, pending in gold,
Ledger paths traced every migration's beat,
Tests updated, old maps turned cold—
A carrot snack for the new status fold."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: adding migration status overlays (applied/pending) to the shared migration tree rendering, which is the primary objective of this substantial refactoring.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tml-2748-migration-status-tree-overlay

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-new Bot commented Jun 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

@prisma-next/extension-author-tools

npm i https://pkg.pr.new/@prisma-next/extension-author-tools@705

@prisma-next/mongo-runtime

npm i https://pkg.pr.new/@prisma-next/mongo-runtime@705

@prisma-next/family-mongo

npm i https://pkg.pr.new/@prisma-next/family-mongo@705

@prisma-next/sql-runtime

npm i https://pkg.pr.new/@prisma-next/sql-runtime@705

@prisma-next/family-sql

npm i https://pkg.pr.new/@prisma-next/family-sql@705

@prisma-next/extension-arktype-json

npm i https://pkg.pr.new/@prisma-next/extension-arktype-json@705

@prisma-next/middleware-cache

npm i https://pkg.pr.new/@prisma-next/middleware-cache@705

@prisma-next/mongo

npm i https://pkg.pr.new/@prisma-next/mongo@705

@prisma-next/extension-paradedb

npm i https://pkg.pr.new/@prisma-next/extension-paradedb@705

@prisma-next/extension-pgvector

npm i https://pkg.pr.new/@prisma-next/extension-pgvector@705

@prisma-next/extension-postgis

npm i https://pkg.pr.new/@prisma-next/extension-postgis@705

@prisma-next/postgres

npm i https://pkg.pr.new/@prisma-next/postgres@705

@prisma-next/sql-orm-client

npm i https://pkg.pr.new/@prisma-next/sql-orm-client@705

@prisma-next/sqlite

npm i https://pkg.pr.new/@prisma-next/sqlite@705

@prisma-next/target-mongo

npm i https://pkg.pr.new/@prisma-next/target-mongo@705

@prisma-next/adapter-mongo

npm i https://pkg.pr.new/@prisma-next/adapter-mongo@705

@prisma-next/driver-mongo

npm i https://pkg.pr.new/@prisma-next/driver-mongo@705

@prisma-next/contract

npm i https://pkg.pr.new/@prisma-next/contract@705

@prisma-next/utils

npm i https://pkg.pr.new/@prisma-next/utils@705

@prisma-next/config

npm i https://pkg.pr.new/@prisma-next/config@705

@prisma-next/errors

npm i https://pkg.pr.new/@prisma-next/errors@705

@prisma-next/framework-components

npm i https://pkg.pr.new/@prisma-next/framework-components@705

@prisma-next/operations

npm i https://pkg.pr.new/@prisma-next/operations@705

@prisma-next/ts-render

npm i https://pkg.pr.new/@prisma-next/ts-render@705

@prisma-next/contract-authoring

npm i https://pkg.pr.new/@prisma-next/contract-authoring@705

@prisma-next/ids

npm i https://pkg.pr.new/@prisma-next/ids@705

@prisma-next/psl-parser

npm i https://pkg.pr.new/@prisma-next/psl-parser@705

@prisma-next/psl-printer

npm i https://pkg.pr.new/@prisma-next/psl-printer@705

@prisma-next/cli

npm i https://pkg.pr.new/@prisma-next/cli@705

@prisma-next/cli-telemetry

npm i https://pkg.pr.new/@prisma-next/cli-telemetry@705

@prisma-next/emitter

npm i https://pkg.pr.new/@prisma-next/emitter@705

@prisma-next/migration-tools

npm i https://pkg.pr.new/@prisma-next/migration-tools@705

prisma-next

npm i https://pkg.pr.new/prisma-next@705

@prisma-next/vite-plugin-contract-emit

npm i https://pkg.pr.new/@prisma-next/vite-plugin-contract-emit@705

@prisma-next/mongo-codec

npm i https://pkg.pr.new/@prisma-next/mongo-codec@705

@prisma-next/mongo-contract

npm i https://pkg.pr.new/@prisma-next/mongo-contract@705

@prisma-next/mongo-value

npm i https://pkg.pr.new/@prisma-next/mongo-value@705

@prisma-next/mongo-contract-psl

npm i https://pkg.pr.new/@prisma-next/mongo-contract-psl@705

@prisma-next/mongo-contract-ts

npm i https://pkg.pr.new/@prisma-next/mongo-contract-ts@705

@prisma-next/mongo-emitter

npm i https://pkg.pr.new/@prisma-next/mongo-emitter@705

@prisma-next/mongo-schema-ir

npm i https://pkg.pr.new/@prisma-next/mongo-schema-ir@705

@prisma-next/mongo-query-ast

npm i https://pkg.pr.new/@prisma-next/mongo-query-ast@705

@prisma-next/mongo-orm

npm i https://pkg.pr.new/@prisma-next/mongo-orm@705

@prisma-next/mongo-query-builder

npm i https://pkg.pr.new/@prisma-next/mongo-query-builder@705

@prisma-next/mongo-lowering

npm i https://pkg.pr.new/@prisma-next/mongo-lowering@705

@prisma-next/mongo-wire

npm i https://pkg.pr.new/@prisma-next/mongo-wire@705

@prisma-next/sql-contract

npm i https://pkg.pr.new/@prisma-next/sql-contract@705

@prisma-next/sql-errors

npm i https://pkg.pr.new/@prisma-next/sql-errors@705

@prisma-next/sql-operations

npm i https://pkg.pr.new/@prisma-next/sql-operations@705

@prisma-next/sql-schema-ir

npm i https://pkg.pr.new/@prisma-next/sql-schema-ir@705

@prisma-next/sql-contract-psl

npm i https://pkg.pr.new/@prisma-next/sql-contract-psl@705

@prisma-next/sql-contract-ts

npm i https://pkg.pr.new/@prisma-next/sql-contract-ts@705

@prisma-next/sql-contract-emitter

npm i https://pkg.pr.new/@prisma-next/sql-contract-emitter@705

@prisma-next/sql-lane-query-builder

npm i https://pkg.pr.new/@prisma-next/sql-lane-query-builder@705

@prisma-next/sql-relational-core

npm i https://pkg.pr.new/@prisma-next/sql-relational-core@705

@prisma-next/sql-builder

npm i https://pkg.pr.new/@prisma-next/sql-builder@705

@prisma-next/target-postgres

npm i https://pkg.pr.new/@prisma-next/target-postgres@705

@prisma-next/target-sqlite

npm i https://pkg.pr.new/@prisma-next/target-sqlite@705

@prisma-next/adapter-postgres

npm i https://pkg.pr.new/@prisma-next/adapter-postgres@705

@prisma-next/adapter-sqlite

npm i https://pkg.pr.new/@prisma-next/adapter-sqlite@705

@prisma-next/driver-postgres

npm i https://pkg.pr.new/@prisma-next/driver-postgres@705

@prisma-next/driver-sqlite

npm i https://pkg.pr.new/@prisma-next/driver-sqlite@705

commit: 0facf95

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

size-limit report 📦

Path Size
postgres / no-emit 137.37 KB (0%)
postgres / emit 108.83 KB (0%)
mongo / no-emit 75.85 KB (0%)
mongo / emit 70.78 KB (0%)
cf-worker / no-emit 166.35 KB (0%)
cf-worker / emit 134.51 KB (0%)

wmadden added 2 commits June 2, 2026 19:07
Update journey assertions for the new status JSON envelope and offline
--from/--db requirements.

Signed-off-by: Will Madden <madden@prisma.io>
Use per-space contract hash for target resolution, compute edge
annotations once, and rely on typed readAllMarkers.

Signed-off-by: Will Madden <madden@prisma.io>

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/1-framework/3-tooling/cli/src/utils/formatters/migration-graph-tree-render.ts (1)

781-790: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Legend status colors should respect opts.colorize
renderMigrationGraphLegend uses colorette’s top-level green/yellow helpers for the ✓/⧗ status line, which follow colorette’s ambient color detection instead of opts.colorize, so ANSI can appear even with --no-color.

Suggested fix
 export function renderMigrationGraphLegend(opts: RenderMigrationGraphLegendOptions): string {
   const palette = paletteFor(opts.glyphMode ?? 'unicode');
   const style = createAnsiMigrationListStyler({ useColor: opts.colorize });
+  const statusColors = createColors({ useColor: opts.colorize });
   const node = palette.node.trimEnd();
   const sampleArrow = `${style.sourceHash('aaaaaa')} ${style.glyph(palette.forwardArrow)} ${style.destHash('bbbbbb')}`;
   return [
     'Legend:',
     `  ${style.kind(node)} contract   ${style.kind(palette.edgeArrow.forward)} forward   ${style.kind(palette.edgeArrow.rollback)} rollback`,
     `  ${style.kind(palette.edgeArrow.self)} migration without schema change`,
-    `  ${green('✓')} applied   ${yellow('⧗')} pending`,
+    `  ${statusColors.green('✓')} applied   ${statusColors.yellow('⧗')} pending`,
     `  ${style.glyph(palette.emptySource)} empty database (baseline)`,
     `  ${style.refs(['refs'])} ${DB_MARKER_NAME} / ${CONTRACT_MARKER_NAME} markers`,
     `  ${sampleArrow}   migration from contract aaaaaa to bbbbbb`,
   ].join('\n');
 }
🤖 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
`@packages/1-framework/3-tooling/cli/src/utils/formatters/migration-graph-tree-render.ts`
around lines 781 - 790, renderMigrationGraphLegend currently uses colorette's
top-level green/yellow which ignore opts.colorize; change the status symbols to
use the ANSI styler created by createAnsiMigrationListStyler so they respect
opts.colorize — replace green('✓') and yellow('⧗') with the styler methods (e.g.
style.success('✓') and style.pending('⧗') or add equivalent methods to the
styler) so the check and pending glyphs are colored only when opts.colorize is
true.
🤖 Prompt for all review comments with 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.

Inline comments:
In `@packages/1-framework/3-tooling/cli/src/commands/migration-status.ts`:
- Around line 444-465: The code is overwriting headlineTargetHash for every
space in scopedSpaces so the final suggested "migrate --to" hint points to the
last space rather than the app-level target; change the assignment in the loop
(where aggregate.space(...), member.graph(), resolveTargetHashForSpace(...) are
used) to only set headlineTargetHash if it is not already set (i.e. set it once
when headlineTargetHash is undefined) so the footer remains pinned to the
first/app target; apply the same guard to the other occurrence around the
resolveTargetHashForSpace block at lines ~566-573.
- Around line 452-463: In the targetHash === undefined branch inside
migration-status.ts, you currently push a MIGRATION.DIVERGED diagnostic and
continue, but you must also mark that this space is not up-to-date so the footer
doesn't report success; after pushing the diagnostic (in the same block where
targetHash is undefined) increment the shared totalPending counter (or set the
per-space pending flag that contributes to totalPending) so the overall summary
reflects unresolved targets; apply the same change to the analogous branch
around the later block (lines ~565-593) where a non-unique target is detected.

In
`@packages/1-framework/3-tooling/cli/src/utils/formatters/migration-graph-tree-render.ts`:
- Around line 527-543: formatEdgeStatusSuffix currently hardcodes Unicode glyphs
(✓ / ⧗); change it to honor the CLI ascii flag on the options object (e.g.
opts.ascii or similar) by selecting ASCII alternatives when that flag is true:
read the overlay annotation via opts.edgeAnnotationsByHash.get(migrationHash) as
now, then compute glyph = status === 'applied' ? (opts.ascii ? 'v' : '✓') :
(opts.ascii ? '>' : '⧗'); keep the existing colorization code (styler =
green/yellow and opts.colorize) and return the same padded string but using the
chosen glyph so both migration graph and migration status respect --ascii.

---

Outside diff comments:
In
`@packages/1-framework/3-tooling/cli/src/utils/formatters/migration-graph-tree-render.ts`:
- Around line 781-790: renderMigrationGraphLegend currently uses colorette's
top-level green/yellow which ignore opts.colorize; change the status symbols to
use the ANSI styler created by createAnsiMigrationListStyler so they respect
opts.colorize — replace green('✓') and yellow('⧗') with the styler methods (e.g.
style.success('✓') and style.pending('⧗') or add equivalent methods to the
styler) so the check and pending glyphs are colored only when opts.colorize is
true.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 0ce66516-0943-411c-a219-d56524147fc6

📥 Commits

Reviewing files that changed from the base of the PR and between 27d8631 and 4379813.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/migration-graph-rendering/slices/status-db-overlay/spec.md is excluded by !projects/**
📒 Files selected for processing (35)
  • packages/1-framework/3-tooling/cli/package.json
  • packages/1-framework/3-tooling/cli/src/commands/migration-graph.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-list.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-status-overlay.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-status.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/graph-migration-mapper.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/graph-render.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/graph-types.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migration-graph-tree-render.ts
  • packages/1-framework/3-tooling/cli/test/commands/cross-consumer-integrity.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/derive-edge-statuses.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/format-status-summary.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-graph.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-invariants.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-status-aggregate-spaces.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-status-overlay.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-tamper.test.ts
  • packages/1-framework/3-tooling/cli/test/output.json-shapes.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/graph-migration-mapper.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/graph-render.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/migration-graph-tree-render.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/test-graphs.ts
  • packages/1-framework/3-tooling/cli/vitest.config.ts
  • test/integration/test/cli-journeys/adopt-migrations.e2e.test.ts
  • test/integration/test/cli-journeys/diamond-convergence.e2e.test.ts
  • test/integration/test/cli-journeys/divergence-and-refs.e2e.test.ts
  • test/integration/test/cli-journeys/drift-deleted-root.e2e.test.ts
  • test/integration/test/cli-journeys/interleaved-db-update.e2e.test.ts
  • test/integration/test/cli-journeys/invariant-routing.e2e.test.ts
  • test/integration/test/cli-journeys/invariant-routing.mongo.e2e.test.ts
  • test/integration/test/cli-journeys/migration-status-diagnostics.e2e.test.ts
  • test/integration/test/cli-journeys/plan-to-rollback.e2e.test.ts
  • test/integration/test/cli-journeys/ref-routing.e2e.test.ts
  • test/integration/test/cli-journeys/schema-evolution-migrations.e2e.test.ts
  • test/integration/test/utils/journey-test-helpers.ts
💤 Files with no reviewable changes (10)
  • packages/1-framework/3-tooling/cli/test/commands/derive-edge-statuses.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/graph-render.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/graph-types.ts
  • packages/1-framework/3-tooling/cli/package.json
  • packages/1-framework/3-tooling/cli/test/commands/migration-status-aggregate-spaces.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/graph-migration-mapper.ts
  • packages/1-framework/3-tooling/cli/vitest.config.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/graph-render.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/graph-migration-mapper.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/test-graphs.ts

Comment thread packages/1-framework/3-tooling/cli/src/commands/migration-status.ts
Comment thread packages/1-framework/3-tooling/cli/src/commands/migration-status.ts
wmadden added 2 commits June 3, 2026 11:51
Resolve migration-graph-tree-render legend conflict; keep applied/pending
legend and main's dimmed summary labels.

Signed-off-by: Will Madden <madden@prisma.io>
Honor CodeRabbit review: keep migrate --to on the app target, avoid
"up to date" when every space has an ambiguous target, and type JSON
diagnostics hints in integration helpers.

Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric wmadden-electric changed the title TML-2748: migration status renders the shared tree with a DB-state overlay; delete dagre TML-2748: migration status overlays applied and pending on the shared migration tree Jun 3, 2026
wmadden added 2 commits June 3, 2026 12:05
lint-sync requires the prisma-next package.json to mirror @prisma-next/cli
after removing the dagre renderer.

Signed-off-by: Will Madden <madden@prisma.io>
wmadden-electric pushed a commit that referenced this pull request Jun 3, 2026
Keep topology classifier tests and Tier-2 entry surface from main
after #704/#705 landed; restore classifyMigrationListGraphTopology
for shared rollback-peel coverage.

Signed-off-by: Will Madden <madden@prisma.io>
wmadden added 2 commits June 3, 2026 13:55
Combine status overlay suffixes from TML-2748 with operation-count and
invariant suffixes landed on main via TML-2770 in one D11 formatter.

Signed-off-by: Will Madden <madden@prisma.io>
…atus-tree-overlay

Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric wmadden-electric merged commit 449f4fb into main Jun 3, 2026
21 checks passed
@wmadden-electric wmadden-electric deleted the tml-2748-migration-status-tree-overlay branch June 3, 2026 12:36
medz pushed a commit to medz/prisma-next that referenced this pull request Jun 5, 2026
…ble (prisma#704)

## At a glance

_Representative output (multi-space ledger; column alignment from
unit-test golden on this branch). At the terminal the divider row is
dim; timestamps below use local time with offset._

```
$ prisma-next migration log

 Applied at                      Space  Migration              Change                   Ops
─────────────────────────────── ────── ────────────────────── ──────────────────────── ───────
 2026-06-01 10:00:00 +02:00     app    20260301_init          ∅ → ef9de27              5 ops
 2026-06-01 10:00:02 +02:00     audit  20260301_init          ∅ → 9a1c2f3              3 ops
 2026-06-02 10:30:00 +02:00     app    20260303_add_phone     ef9de27 → 73e3abe        2 ops
 2026-06-03 11:00:00 +02:00     app    20260305_rollback      73e3abe → ef9de27        2 ops
```

## The decision

`migration log` now reads the per-migration ledger journal directly from
the connected database and presents it as a single flat chronological
table — every applied migration across every space, ordered by
`appliedAt` (oldest first). Human output on a TTY renders local time
with a numeric timezone offset; `--utc` switches human output to UTC;
`--json`, non-TTY pipes, and other machine paths emit ISO-8601 UTC
(`…Z`) for stable tooling. This replaces the previous `migration log`
behaviour wholesale: no on-disk graph, no `findPath` reconstruction, no
per-space sections.

## Narrative

### Ledger journal (TML-2769, merged)

The on-apply ledger was restructured in
[prisma#665](prisma#665) into a
per-migration journal: one row per applied edge with `space`,
`migrationName`, `migrationHash`, `from` / `to`, `operationCount`, and
`appliedAt`. That shape is what `status` matches against and what `log`
is meant to surface.

### `migration log` as the human-facing journal view

`log` answers “what actually ran against this database, and when?” It
calls `readLedger()` with no space filter so the adapter returns the
whole table, sorts globally by `appliedAt`, and prints aligned rows
(`Applied at` · optional `Space` · `Migration` · `Change` · `Ops`). The
ledger is conceptually flat, so the command stays flat too — not
space-scoped like `list` / `graph` / `status`. The `Space` column
appears only when more than one space contributes rows. Rollbacks and
re-applies are repeated uniform rows; `from → to` (with `∅` for a null
origin) carries the story without classifying event kinds.

### Timestamp formatting

TTY humans get local time plus offset (`2026-06-01 10:00:00 +02:00`).
`--utc` is human-only and prints UTC with a `Z` suffix. Machine output
(`--json`, or any non-TTY pipe) is always ISO-8601 UTC regardless of
`--utc`, so scripts never inherit the operator’s timezone.

### Styling

`from → to` uses the shared migration-list colour palette so hash
transitions read the same way as in `migration graph` and `migration
status`. Column layout is a dedicated flat table renderer (not the
shared tree).

## What this PR does not change

- **Ledger schema or `readLedger` contract** — already landed in
TML-2769 ([prisma#665](prisma#665)); this
PR only widens the read to be space-optional and wires `log` to it.
- **`migration list`** — separate slice
([prisma#706](prisma#706)).
- **`migration status`** — separate slice
([prisma#705](prisma#705)).
- **Ledger writes** — the migrate runner that appends rows is untouched.

## Alternatives considered

1. **Per-space sections with headings (like `graph` / `list` /
`status`)** — rejected. The ledger is a flat table; sectioning would
re-group flat data and break global chronological ordering across
spaces.
2. **Render via the shared tree renderer with a chronological pivot** —
rejected. The tree’s value is structural topology; for apply history
ordered by time, a table is the right shape.
3. **Default to UTC everywhere** — rejected. Humans benefit from local
time at the terminal; tooling gets stable `Z` ISO timestamps on `--json`
/ pipes.

## Linked issue

Refs [TML-2770](https://linear.app/prisma-company/issue/TML-2770).
Builds on ledger journal
[TML-2769](https://linear.app/prisma-company/issue/TML-2769)
([prisma#665](prisma#665)).

## Testing performed

- `pnpm --filter @prisma-next/cli... build`
- `pnpm --filter @prisma-next/cli typecheck`
- CLI: `migration-log-table`, `migration-log`, `readLedger` client, JSON
golden tests
- Adapter unscoped reads: SQLite `runner.ledger`, Mongo `marker-ledger`
- `pnpm lint:deps`
- Full CI (pending on PR)

## Skill update

n/a — internal CLI behaviour change; no published skill documents
`migration log` table layout yet.

## Checklist

- [x] All commits are signed off (`git commit -s`)
- [x] I read CONTRIBUTING.md and the change is scoped to one logical
concern
- [x] Tests are updated
- [x] PR title uses `TML-2770: …` form
- [x] Skill update section filled in


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Migration log command now reads data directly from the database ledger
  * Added UTC timestamp formatting option for migration log display
* Enhanced migration log output with improved table rendering and
formatting

* **Changes**
* Ledger read operations now return entries for all spaces when the
space parameter is omitted

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Will Madden <madden@prisma.io>
Co-authored-by: Will Madden <madden@prisma.io>
medz pushed a commit to medz/prisma-next that referenced this pull request Jun 5, 2026
## At a glance

Interactive `migration list` (TTY) now draws the same condensed graph
tree as `migration graph` and `migration status`, with per-package facts
on migration rows (`N ops`, `{invariants}`) and refs on contract nodes.
Machine output is unchanged.

Single contract space (no `app:` heading when there is only one space):

```
$ prisma-next migration list
○   55bada2
│↑  20260422T0742_migration  4cb4256 → 55bada2  1 ops
○   4cb4256
│↑  20260422T0720_initial    ∅       → 4cb4256  1 ops
∅

2 migration(s) on disk
```

Multiple contract spaces (`spaceId:` section headings, two-space tree
indent):

```
$ prisma-next migration list
app:
  ○   804e018                           (db)
  │↑  20260518T1701_namespaces_bookend  55bada2 → 804e018  1 ops
  ○   55bada2                           (production)
  │↑  20260422T0742_migration           4cb4256 → 55bada2  1 ops
  ○   4cb4256
  │↑  20260422T0720_initial             ∅       → 4cb4256  1 ops
  ∅

postgis:
  ○   9aabbcc                                  (db)
  │↑  20260601T0000_install_postgis_extension  ∅       → 9aabbcc  1 ops
  ∅

4 migration(s) across 2 contract space(s)
```

Piping or `--json` still emits the flat package array
(`MigrationListResult`); the tree never appears in machine formats.

## The decision

`migration list` now renders the on-disk migration graph as a tree in
human (pretty / TTY) output — contracts as nodes, packages as annotated
edges — using the shared renderer the read-command family already uses
for `graph` and (soon) `status`. Package facts (`operationCount`,
`providedInvariants`) ride a new shared edge-annotation overlay on that
renderer; refs stay on destination contract nodes. `migration list
--json`, non-TTY stdout, and the flat sort order stay byte-identical for
scripts and tooling.

## Why this shape

### One renderer for on-disk topology

`list`, `graph`, and `status` all answer questions about **on-disk**
contract-space history. They now share one condensed tree engine for
human output and differ only in overlays: `list` adds package facts on
edges, `graph` emphasizes contract topology and `(contract)` / `(refs)`
node labels, and `status` (follow-up in prisma#705) will add applied/pending
markers. One code path to maintain; one mental model for operators.

### Flat rows were the wrong default for humans

The old human output was a flat table sorted by migration directory
name. That order is lexicographic, not chronological, and it hides
branching — for anything beyond a linear chain you had to run `list` and
`graph` together to see relationships. The tree is the readable default
now that the family shares a renderer; machine consumers still get the
faithful flat package inventory in JSON.

### Human vs machine stays split

The tree is rendered only on the pretty/TTY path. Piping a read command
already selects JSON via `resolveOutputFormat`, so scripts never
accidentally parse box-drawing. This PR also drops the misleading
“latest first” wording in the command description; flat JSON order is
unchanged (still lexicographic by `dirName`).

## What this PR does not change

- **`migration list --json`** — `MigrationListResult` shape, field
names, and flat sort order (golden tests pin byte-identical JSON).
- **`migration graph`** — separate command, separate `{ nodes, edges }`
JSON contract; not modified here.
- **`migration list --graph`** — already removed earlier in the
migration-graph-rendering project; not touched.
- **`migration status` DB overlay** — applied/pending glyphs and `(db)`
marker land in prisma#705 (`tml-2748-migration-status-db-overlay`); this PR
only introduces the shared `edgeAnnotationsByHash` field that `status`
extends with a `status` key.
- **Ledger / `migration log`** — out of scope.

## Alternatives considered

- **Keep flat rows as the default, add `--tree` on `list`.** Rejected:
the tree is the right human default now that `graph` and `status` share
one renderer; an opt-in flag would preserve the unreadable path most
people would still hit.
- **Have `migration status` drive `list` rendering (status wraps
list).** Rejected: both commands consume the same tree library; neither
owns the other. `list` populates package edge annotations; `status` adds
DB-state keys on the same overlay type.

## Linked issue

Refs [TML-2768](https://linear.app/prisma-company/issue/TML-2768).
Related: [TML-2697](https://linear.app/prisma-company/issue/TML-2697)
(original list readability ask). DB overlay follow-up: prisma#705.

## Testing performed

- `pnpm --filter @prisma-next/cli... build`
- `pnpm --filter @prisma-next/cli typecheck`
- CLI package vitest (tree render golden, `--json` byte-identical,
`--space`, `--ascii`, multi-space headings)
- `pnpm lint:deps`

## Skill update

n/a — CLI behaviour change is user-visible but covered by existing
migration-command skills; no new flags.

## Checklist

- [x] All commits are signed off (`git commit -s`) per the DCO.
- [x] I read CONTRIBUTING.md and the change is scoped to one logical
concern.
- [x] Tests are updated.
- [x] The PR title is in `TML-NNNN: <sentence-case title>` form.
- [x] Skill update section filled in (`n/a — internal only` above).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Migration edges now display operation counts and invariants for
improved visibility into migration details.
  * Added colorization support for enhanced terminal output readability.

* **Improvements**
  * Enhanced migration list visualization with improved formatting.
  * Updated migration list command description.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/prisma/prisma-next/pull/706?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Will Madden <madden@prisma.io>
Co-authored-by: Will Madden <madden@prisma.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants