Skip to content
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
b47fa35
fix(cli): unify JSON error output for db schema-verify and db sign
jkomyno Mar 10, 2026
089f5e7
chore: snapshot lint
jkomyno Mar 10, 2026
0cca55d
test(cli): implement CLI scenario catalog e2e test suite (Phases 1-4)
jkomyno Mar 10, 2026
1c0b7cf
fix(test): restore full drift-schema journey coverage (M/N)
jkomyno Mar 10, 2026
f76c329
fix(core-control-plane): export errorSchemaVerificationFailed from ba…
jkomyno Mar 10, 2026
50542a9
fix(test): restore P3 chain breakage recovery (find migration dir by …
jkomyno Mar 10, 2026
000a654
fix(test): implement U.01 target mismatch via contract.json tampering
jkomyno Mar 10, 2026
959309c
fix(test): resolve integration-tests typecheck errors
jkomyno Mar 10, 2026
4669eea
test: remove Journey H (brownfield extras) — covered by Journey N
jkomyno Mar 11, 2026
6ae09fe
test: remove Journeys P4 and P5 — covered by cli.migration-apply.e2e.…
jkomyno Mar 11, 2026
ef7e3c6
test: merge Journeys Q, R, X into Journey B; delete migration-edge-cases
jkomyno Mar 11, 2026
6bc3b72
test: remove Journey I (CI pipeline) and Journey J (help)
jkomyno Mar 11, 2026
f85c820
docs: update scenario catalog to reflect journey consolidation
jkomyno Mar 11, 2026
ce21c3e
feat: add test:journeys command for running CLI journey tests
jkomyno Mar 11, 2026
313716e
docs: add journey test README and describe scenarios in test comments
jkomyno Mar 12, 2026
b6a683f
chore: remove plan file from branch (kept locally)
jkomyno Mar 12, 2026
6063273
fix: remove obsolete eslint-plugin snapshot entries
jkomyno Mar 12, 2026
13c57d3
fix(cli): restore main's db-sign and db-schema-verify failure handling
jkomyno Mar 12, 2026
5b60ce5
fix(test): address CodeRabbit review feedback
jkomyno Mar 12, 2026
8e2b11a
refactor(core-control-plane): use ifDefined in errorSchemaVerificatio…
jkomyno Mar 12, 2026
e2ddada
fix(test): use == null to cover undefined from getExitCode()
jkomyno Mar 12, 2026
d5ab105
fix(test): use pathe and remove error-swallowing in journey helpers
jkomyno Mar 13, 2026
8f9982b
fix(core-control-plane): use concrete types in errorSchemaVerificatio…
jkomyno Mar 16, 2026
975e130
refactor(test): unify runCommand and runCommandRaw into runCommandCore
jkomyno Mar 16, 2026
171004f
refactor(test): remove setupJourneyNoDb, use setupJourney({ createTem…
jkomyno Mar 16, 2026
c45b0aa
fix(test): replace dynamic import with static import of runDbUpdate
jkomyno Mar 16, 2026
62bc14d
refactor(test): use static import for withClient in sql() helper
jkomyno Mar 16, 2026
8e936b4
docs(test): document pool: 'forks' as hard requirement in vitest config
jkomyno Mar 16, 2026
01d78b0
refactor(test): use useDevDatabase() and contractFixtures in journey …
jkomyno Mar 16, 2026
8f74861
fix(planner): emit executable DDL for NOT NULL columns on non-empty t…
jkomyno Mar 16, 2026
3eb0629
fix(planner): use unambiguous zero defaults and verify default removal
jkomyno Mar 16, 2026
179a493
fix(planner): add date type coverage and mark getTypeZeroDefault as i…
jkomyno Mar 16, 2026
69d0935
refactor(planner): collapse numeric switch groups and rename to build…
jkomyno Mar 16, 2026
2b43045
refactor(planner,runner): improve readability of skip and precheck co…
jkomyno Mar 16, 2026
3d0a6e0
refactor(test): extract planAddColumn helper in planner behavior tests
jkomyno Mar 16, 2026
a4d4780
docs: document db update reconciliation mode and NOT NULL column stra…
jkomyno Mar 16, 2026
2384066
fix(test): use ColumnDefaultLiteralInputValue instead of unknown in p…
jkomyno Mar 17, 2026
271dfc7
fix(runner): treat undefined origin the same as null in skip gate
jkomyno Mar 17, 2026
98ee266
fix(test): tighten journey test assertions per review feedback
jkomyno Mar 17, 2026
ba28e97
fix(test): correct error code and revert ANSI assertion
jkomyno Mar 17, 2026
c320087
Merge branch 'main' into fix/ddl-not-null
jkomyno Mar 19, 2026
3a57f7b
Merge branch 'main' into fix/ddl-not-null
jkomyno Mar 24, 2026
fefba88
fix(postgres): make temporary defaults extensible
jkomyno Mar 25, 2026
3b77676
fix(postgres): avoid placeholder defaults on constrained columns
jkomyno Mar 25, 2026
fd12d87
fix(postgres): stabilize timetz temporary defaults
jkomyno Mar 25, 2026
99ed751
test(postgres): cover constrained fallback planning
jkomyno Mar 25, 2026
f81fce6
fix(postgres): satisfy planner typecheck
jkomyno Mar 25, 2026
04e721a
Merge branch 'main' into fix/ddl-not-null
jkomyno Mar 26, 2026
837693a
Merge branch 'main' into fix/ddl-not-null
jkomyno Mar 26, 2026
196fd70
refactor: rename temporary-default helpers to identity-value terminology
jkomyno Mar 26, 2026
5a78738
Merge branch 'main' into fix/ddl-not-null
jkomyno Mar 30, 2026
7faaf74
refactor(planner): extract postgres SQL builders and fix json identit…
jkomyno Mar 30, 2026
2aaf712
Merge branch 'main' into fix/ddl-not-null
jkomyno Mar 30, 2026
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
12 changes: 10 additions & 2 deletions docs/architecture docs/subsystems/7. Migration System.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,16 @@ For CLI usage, output formats, and common failure modes, see the canonical comma

Greenfield, brownfield-conservative, and brownfield-incremental paths are supported. Baselines help bootstrap fresh environments; incremental adoption expands contract coverage safely over time. See [ADR 122 — Database Initialization & Adoption](../adrs/ADR%20122%20-%20Database%20Initialization%20&%20Adoption.md).

### `db update` (live reconciliation)

`prisma-next db update` is the **reconciliation** entrypoint. It introspects the live database schema, diffs it against the destination contract, and applies the resulting operations.

Unlike `migration apply`, which replays serialized edges, `db update` always works from a live introspection. Plans produced by the planner carry `origin: null` (no prior-state assertion). The runner treats this as "trust the planner": operations are always applied regardless of marker state. This ensures `db update` can recover from schema drift — for example, when a DBA manually drops a column, the planner detects the missing column and re-adds it even though the contract marker already matches the destination hash.

By contrast, `migration apply` constructs plans with `origin: { storageHash }` from the migration chain. When the marker matches the destination, the runner skips operations (the migration was already applied). This provides safe idempotent replays.

**NOT NULL columns without defaults.** The planner first resolves a temporary default by consulting codec hooks (for parameterized or extension-owned types) and then built-in fallbacks (`''` for text, `0` for integers, `false` for booleans, `'{}'` for arrays, `''::tsvector` for `tsvector`, length-aware zero literals for `bit(n)`, etc.). When a safe literal is available, it emits a reusable 2-step recipe: add the column with the temporary default, then drop the default immediately after. Existing rows permanently retain the backfilled value; future inserts must provide an explicit value. When no safe temporary default is known, the planner falls back to the empty-table precheck path.
Comment thread
jkomyno marked this conversation as resolved.
Outdated

## Multi-Service Namespacing

Per-service markers allow independent contracts within a single physical database (e.g., Postgres schemas). Each service has its own `prisma_contract.marker`; permissions and verification remain isolated. For engines without schemas, use separate databases. See namespacing notes in [ADR 021 — Contract Marker Storage](../adrs/ADR%20021%20-%20Contract%20Marker%20Storage.md).
Expand Down Expand Up @@ -333,5 +343,3 @@ Provide:
- edges/<edgeId>/migration.json — manifests with ops and checks; optional tasks modules
- graph.index.json (optional) — committed graph index when enabled
- digests — content hashes for integrity


22 changes: 22 additions & 0 deletions packages/2-sql/3-tooling/family/src/core/migrations/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ export interface ExpandNativeTypeInput {
readonly typeParams?: Record<string, unknown>;
}

/**
* Input for resolving a temporary SQL literal used to backfill existing rows when
* adding a NOT NULL column without an explicit default.
*/
export interface ResolveTemporaryDefaultLiteralInput {
readonly nativeType: string;
readonly codecId?: string;
readonly typeParams?: Record<string, unknown>;
}

export interface CodecControlHooks<TTargetDetails = unknown> {
planTypeOperations?: (options: {
readonly typeName: string;
Expand Down Expand Up @@ -194,6 +204,18 @@ export interface CodecControlHooks<TTargetDetails = unknown> {
* Returns the expanded type string, or the original nativeType if no expansion is needed.
*/
expandNativeType?: (input: ExpandNativeTypeInput) => string;
/**
* Resolves a temporary SQL literal for safely adding a NOT NULL column without an explicit
* default to a non-empty table.
*
* Return semantics:
* - string: use this literal
* - null: explicitly no safe temporary default is known; fall back to another strategy
* - undefined: no opinion; planner may use built-in fallbacks
*/
resolveTemporaryDefaultLiteral?: (
input: ResolveTemporaryDefaultLiteralInput,
) => string | null | undefined;
Comment thread
jkomyno marked this conversation as resolved.
Outdated
}

export interface SqlControlExtensionDescriptor<TTargetId extends string>
Comment thread
jkomyno marked this conversation as resolved.
Expand Down
1 change: 1 addition & 0 deletions packages/2-sql/3-tooling/family/src/exports/control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export type {
CreateSqlMigrationPlanOptions,
ExpandNativeTypeInput,
PslScalarTypeDescriptor,
ResolveTemporaryDefaultLiteralInput,
SqlControlAdapterDescriptor,
SqlControlExtensionDescriptor,
SqlControlStaticContributions,
Expand Down
14 changes: 14 additions & 0 deletions packages/3-extensions/pgvector/src/exports/control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ import { pgvectorOperationSignature, pgvectorPackMeta } from '../core/descriptor

const PGVECTOR_CODEC_ID = 'pg/vector@1' as const;

function buildZeroVectorTemporaryDefaultLiteral(
typeParams: Record<string, unknown> | undefined,
): string | null {
const length = typeParams?.['length'];
if (typeof length !== 'number' || !Number.isInteger(length) || length <= 0) {
return null;
}

const zeroVector = `[${new Array(length).fill('0').join(',')}]`;
return `'${zeroVector}'::vector`;
}

const vectorControlPlaneHooks: CodecControlHooks = {
expandNativeType: ({ nativeType, typeParams }) => {
const length = typeParams?.['length'];
Expand All @@ -15,6 +27,8 @@ const vectorControlPlaneHooks: CodecControlHooks = {
}
return nativeType;
},
resolveTemporaryDefaultLiteral: ({ typeParams }) =>
buildZeroVectorTemporaryDefaultLiteral(typeParams),
};

const pgvectorDatabaseDependencies: ComponentDatabaseDependencies<unknown> = {
Expand Down
Loading
Loading