Skip to content

TML-2770: migration log reads the ledger as one flat chronological table#704

Merged
wmadden-electric merged 11 commits into
mainfrom
tml-2770-migration-log-reads-ledger
Jun 3, 2026
Merged

TML-2770: migration log reads the ledger as one flat chronological table#704
wmadden-electric merged 11 commits into
mainfrom
tml-2770-migration-log-reads-ledger

Conversation

@wmadden-electric

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

Copy link
Copy Markdown
Contributor

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 #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 (#665); this PR only widens the read to be space-optional and wires log to it.
  • migration list — separate slice (#706).
  • migration status — separate slice (#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. Builds on ledger journal TML-2769 (#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

  • 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 uses TML-2770: … form
  • Skill update section filled in

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

wmadden added 3 commits June 2, 2026 18:37
Omitting space returns the whole ledger table from SQL and Mongo
adapters. The control client no longer defaults to APP_SPACE_ID when
readLedger() is called with no argument.

Signed-off-by: Will Madden <madden@prisma.io>
Sorts ledger rows by appliedAt with deterministic tie-breaks, formats
local/UTC/ISO timestamps, and renders optional space columns.

Signed-off-by: Will Madden <madden@prisma.io>
Drop findPath/on-disk reconstruction. migration log calls readLedger()
unscoped, prints a flat chronological table (local time, --utc for human
UTC, ISO-UTC JSON array), and shows a space column only when multiple
spaces contribute rows.

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:38
@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: 3a25a16d-f192-41ba-a884-47829a599865

📥 Commits

Reviewing files that changed from the base of the PR and between 016dc5c and b3cf920.

📒 Files selected for processing (6)
  • packages/1-framework/3-tooling/cli/src/control-api/client.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migration-log-table.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/migration-log-table.test.ts
  • packages/2-sql/9-family/src/core/control-adapter.ts
  • packages/2-sql/9-family/src/core/control-instance.ts
  • packages/3-targets/6-adapters/postgres/src/core/control-adapter.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/2-sql/9-family/src/core/control-instance.ts
  • packages/1-framework/3-tooling/cli/src/control-api/client.ts
  • packages/2-sql/9-family/src/core/control-adapter.ts
  • packages/3-targets/6-adapters/postgres/src/core/control-adapter.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/migration-log-table.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migration-log-table.ts

📝 Walkthrough

Walkthrough

This PR makes readLedger(space?) optional across control interfaces and adapters, implements all-space ledger reads in Mongo/Postgres/SQLite adapters, rewrites the CLI migration-log to read ledger entries directly, and adds formatter utilities plus tests for sorting, rendering, and JSON output.

Changes

Ledger-based migration log refactoring

Layer / File(s) Summary
Core API contract: optional space parameter
packages/1-framework/1-core/framework-components/src/control/control-instances.ts, packages/2-mongo-family/9-family/src/core/control-adapter.ts, packages/2-sql/9-family/src/core/control-adapter.ts, packages/2-sql/9-family/src/core/control-instance.ts
readLedger signatures and docs changed to make space optional, enabling callers to omit it to receive ledger rows for all spaces.
Storage adapter implementations: optional space handling
packages/3-mongo-target/2-mongo-adapter/src/core/marker-ledger.ts, packages/3-mongo-target/2-mongo-adapter/src/core/mongo-control-adapter.ts, packages/3-targets/6-adapters/postgres/src/core/control-adapter.ts, packages/3-targets/6-adapters/sqlite/src/core/control-adapter.ts
Adapters now build conditional queries that filter by space only when provided and extract space from returned rows/documents; Mongo aggregate match stages and SQL query strings were made dynamic.
CLI client and ledger formatting utilities
packages/1-framework/3-tooling/cli/src/control-api/client.ts, packages/1-framework/3-tooling/cli/src/utils/formatters/migration-log-table.ts
Control client forwards optional space. New formatter module adds deterministic sorting, timestamp modes (iso/utc/local), hash transition formatting/styling, fixed-width table rendering with dynamic column widths, JSON serialization, and an empty-state message constant.
Migration log command: ledger-based refactoring
packages/1-framework/3-tooling/cli/src/commands/migration-log.ts
migration log now reads ledger entries via readLedger() (returns LedgerEntryRecord[]), removes on-disk graph/marker reconstruction, updates help/examples, and renders output via the new utilities (table or --json) with --utc support.
Comprehensive test coverage
packages/1-framework/3-tooling/cli/test/commands/migration-log.test.ts, packages/1-framework/3-tooling/cli/test/utils/formatters/migration-log-table.test.ts, packages/1-framework/3-tooling/cli/test/control-api/client.test.ts, packages/1-framework/3-tooling/cli/test/commands/read-commands-json-golden.test.ts, packages/3-mongo-target/2-mongo-adapter/test/marker-ledger.test.ts, packages/3-targets/6-adapters/sqlite/test/migrations/runner.ledger.test.ts
Tests added/updated to verify missing-DB error handling, empty ledger, unscoped/all-space reads (omitted space), ledger sorting, timestamp formatting modes, table golden outputs, ANSI styling, JSON serialization, and multi-space adapter reads.

Sequence Diagram

sequenceDiagram
  participant CLI as Migration Log CLI
  participant Client as Control API Client
  participant Adapter as Storage Adapter
  participant DB as Database

  CLI->>Client: executeMigrationLogCommand()
  activate Client
  Client->>Adapter: readLedger(driver, undefined) // omitted space => all spaces
  activate Adapter
  Adapter->>DB: Query ledger rows (space filter conditional)
  activate DB
  DB-->>Adapter: LedgerEntryRecord[]
  deactivate DB
  Adapter-->>Client: LedgerEntryRecord[]
  deactivate Adapter
  Client-->>CLI: LedgerEntryRecord[]
  deactivate Client

  CLI->>CLI: sortLedgerEntries & formatLedgerAppliedAt
  CLI->>CLI: renderMigrationLogTable or serializeLedgerEntriesForJson
  CLI-->>User: formatted table or JSON
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • prisma/prisma-next#665: Introduces the initial readLedger API and related ledger plumbing that this PR modifies to make space optional.
  • prisma/prisma-next#644: Earlier changes touching migration-log command behavior and related CLI plumbing.

Suggested reviewers

  • aqrln

Poem

🐰 I hopped through ledgers, left no space behind,

Rows from every corner, in order aligned.
Tables and JSON, timestamps all neat,
The migration log sings — every entry I greet.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.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 title accurately describes the main change: the migration log command now reads the ledger as a single flat chronological table instead of reconstructing via graph walking.
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-2770-migration-log-reads-ledger

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@704

@prisma-next/mongo-runtime

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

@prisma-next/family-mongo

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

@prisma-next/sql-runtime

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

@prisma-next/family-sql

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

@prisma-next/extension-arktype-json

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

@prisma-next/middleware-cache

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

@prisma-next/mongo

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

@prisma-next/extension-paradedb

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

@prisma-next/extension-pgvector

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

@prisma-next/extension-postgis

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

@prisma-next/postgres

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

@prisma-next/sql-orm-client

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

@prisma-next/sqlite

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

@prisma-next/target-mongo

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

@prisma-next/adapter-mongo

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

@prisma-next/driver-mongo

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

@prisma-next/contract

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

@prisma-next/utils

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

@prisma-next/config

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

@prisma-next/errors

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

@prisma-next/framework-components

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

@prisma-next/operations

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

@prisma-next/ts-render

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

@prisma-next/contract-authoring

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

@prisma-next/ids

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

@prisma-next/psl-parser

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

@prisma-next/psl-printer

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

@prisma-next/cli

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

@prisma-next/cli-telemetry

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

@prisma-next/emitter

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

@prisma-next/migration-tools

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

prisma-next

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

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

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

@prisma-next/mongo-codec

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

@prisma-next/mongo-contract

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

@prisma-next/mongo-value

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

@prisma-next/mongo-contract-psl

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

@prisma-next/mongo-contract-ts

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

@prisma-next/mongo-emitter

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

@prisma-next/mongo-schema-ir

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

@prisma-next/mongo-query-ast

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

@prisma-next/mongo-orm

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

@prisma-next/mongo-query-builder

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

@prisma-next/mongo-lowering

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

@prisma-next/mongo-wire

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

@prisma-next/sql-contract

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

@prisma-next/sql-errors

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

@prisma-next/sql-operations

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

@prisma-next/sql-schema-ir

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

@prisma-next/sql-contract-psl

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

@prisma-next/sql-contract-ts

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

@prisma-next/sql-contract-emitter

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

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

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

@prisma-next/sql-relational-core

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

@prisma-next/sql-builder

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

@prisma-next/target-postgres

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

@prisma-next/target-sqlite

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

@prisma-next/adapter-postgres

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

@prisma-next/adapter-sqlite

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

@prisma-next/driver-postgres

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

@prisma-next/driver-sqlite

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

commit: b3cf920

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

size-limit report 📦

Path Size
postgres / no-emit 137.3 KB (0%)
postgres / emit 108.81 KB (0%)
mongo / no-emit 75.78 KB (0%)
mongo / emit 70.78 KB (0%)
cf-worker / no-emit 166.31 KB (0%)
cf-worker / emit 134.52 KB (0%)

wmadden added 2 commits June 2, 2026 18:53
…reads

Signed-off-by: Will Madden <madden@prisma.io>
Wire MigrationListStyler into the ledger table renderer so migration
log human output matches graph/list token colors, with width math on
unstyled strings and identity styler as the default for plain output.

Signed-off-by: Will Madden <madden@prisma.io>
wmadden added 3 commits June 3, 2026 11:33
… node hashes

Signed-off-by: Will Madden <madden@prisma.io>
- Drop the clack '│ ' prefix by emitting via ui.output instead of ui.log
- Add 'Applied at / Space / Migration / Change / Ops' heading row + dim
  divider; column widths include heading text
- Pull palette back: only the migration name is bold; from→to colors
  match the graph palette; everything else is bright default-fg

Signed-off-by: Will Madden <madden@prisma.io>
Pad each cell with a leading space and reduce inter-column gap from three
spaces to one so the table matches the migration list layout density.

Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric wmadden-electric changed the title TML-2770: migration log reads the DB ledger as a flat apply history TML-2770: migration log reads the ledger as one flat chronological table Jun 3, 2026

@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: 1

🧹 Nitpick comments (1)
packages/1-framework/3-tooling/cli/src/control-api/client.ts (1)

454-458: ⚡ Quick win

Consider using ifDefined for conditional property spread.

Line 457 uses a ternary to conditionally include the space property. Per codebase patterns, prefer ifDefined from @prisma-next/utils/defined:

♻️ Refactor to use ifDefined
+import { ifDefined } from '`@prisma-next/utils/defined`';
+
 /** Reads the per-migration journal; omit `space` to return every space. */
 async readLedger(space?: string): Promise<readonly LedgerEntryRecord[]> {
   const { driver, familyInstance } = await this.ensureConnected();
-  return familyInstance.readLedger(space === undefined ? { driver } : { driver, space });
+  return familyInstance.readLedger({ driver, ...ifDefined('space', space) });
 }

Based on learnings: prefer ifDefined from prisma-next/utils/defined for conditional object spreads.

🤖 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/control-api/client.ts` around lines
454 - 458, The readLedger method should use the ifDefined helper to
conditionally spread the space property instead of the ternary; import ifDefined
from '`@prisma-next/utils/defined`' and change the call to
familyInstance.readLedger to pass an object like { driver, ...ifDefined('space',
space) } (or equivalent usage per the helper's API) so the space key is only
included when defined; keep the await this.ensureConnected() and the rest of
readLedger unchanged.
🤖 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/utils/formatters/migration-log-table.ts`:
- Around line 98-100: columnWidth currently uses value.length which
miscalculates visual widths for Unicode; update columnWidth (function
columnWidth) to compute max using a visual width function (e.g., stringWidth)
instead of .length, and ensure the module providing stringWidth is imported
where columnWidth is defined (or call the existing padVisible/ stringWidth
helper if present) so the returned column widths match padVisible's measurements
and fix table alignment.

---

Nitpick comments:
In `@packages/1-framework/3-tooling/cli/src/control-api/client.ts`:
- Around line 454-458: The readLedger method should use the ifDefined helper to
conditionally spread the space property instead of the ternary; import ifDefined
from '`@prisma-next/utils/defined`' and change the call to
familyInstance.readLedger to pass an object like { driver, ...ifDefined('space',
space) } (or equivalent usage per the helper's API) so the space key is only
included when defined; keep the await this.ensureConnected() and the rest of
readLedger unchanged.
🪄 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: 2588eb1c-5179-49c4-aea5-6b7436081e0f

📥 Commits

Reviewing files that changed from the base of the PR and between 1406432 and 016dc5c.

⛔ Files ignored due to path filters (1)
  • projects/migration-graph-rendering/slices/log-reads-ledger/spec.md is excluded by !projects/**
📒 Files selected for processing (17)
  • packages/1-framework/1-core/framework-components/src/control/control-instances.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-log.ts
  • packages/1-framework/3-tooling/cli/src/control-api/client.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migration-log-table.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-log.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/read-commands-json-golden.test.ts
  • packages/1-framework/3-tooling/cli/test/control-api/client.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/formatters/migration-log-table.test.ts
  • packages/2-mongo-family/9-family/src/core/control-adapter.ts
  • packages/2-sql/9-family/src/core/control-adapter.ts
  • packages/2-sql/9-family/src/core/control-instance.ts
  • packages/3-mongo-target/2-mongo-adapter/src/core/marker-ledger.ts
  • packages/3-mongo-target/2-mongo-adapter/src/core/mongo-control-adapter.ts
  • packages/3-mongo-target/2-mongo-adapter/test/marker-ledger.test.ts
  • packages/3-targets/6-adapters/postgres/src/core/control-adapter.ts
  • packages/3-targets/6-adapters/sqlite/src/core/control-adapter.ts
  • packages/3-targets/6-adapters/sqlite/test/migrations/runner.ledger.test.ts

wmadden added 3 commits June 3, 2026 12:44
Symmetric cell padding: one leading and one trailing space around each
value; dividers span the full cell width (maxValueWidth + 2).

Signed-off-by: Will Madden <madden@prisma.io>
Use stringWidth in columnWidth so wide migration names line up with
padVisible, and spread optional readLedger space via ifDefined.

Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric wmadden-electric merged commit bcb1a0a into main Jun 3, 2026
21 checks passed
@wmadden-electric wmadden-electric deleted the tml-2770-migration-log-reads-ledger branch June 3, 2026 11:00
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>
medz pushed a commit to medz/prisma-next that referenced this pull request Jun 5, 2026
… migration tree

## 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 (`buildMigrationGraphRows` → `buildMigrationGraphLayout`
→ `renderMigrationGraphTree`). `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
([prisma#706](prisma#706)); this PR only
shares the renderer hook `list` will populate later.
- **`migration log`** — separate slice
([prisma#704](prisma#704)); flat ledger
history, not tree-shaped.

## Linked issue

Refs [TML-2748](https://linear.app/prisma-company/issue/TML-2748)
(resolves applied-from-ledger
[TML-2130](https://linear.app/prisma-company/issue/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

- [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 is `TML-2748: …`
- [x] 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.


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

## 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.

<!-- 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