@prisma-next/target-mongo 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/control.d.mts +24 -7
  2. package/dist/control.d.mts.map +1 -1
  3. package/dist/control.mjs +98 -72
  4. package/dist/control.mjs.map +1 -1
  5. package/dist/descriptor-meta-D9_5quQi.mjs +14 -0
  6. package/dist/descriptor-meta-D9_5quQi.mjs.map +1 -0
  7. package/dist/{migration-factories-Dbk5afMU.mjs → migration-factories-CoNYWrd1.mjs} +3 -1
  8. package/dist/migration-factories-CoNYWrd1.mjs.map +1 -0
  9. package/dist/migration.d.mts +7 -1
  10. package/dist/migration.d.mts.map +1 -1
  11. package/dist/migration.mjs +1 -1
  12. package/dist/{op-factory-call-CVgzmLJh.d.mts → op-factory-call--nK5dk8n.d.mts} +1 -1
  13. package/dist/{op-factory-call-CVgzmLJh.d.mts.map → op-factory-call--nK5dk8n.d.mts.map} +1 -1
  14. package/dist/pack.mjs +1 -11
  15. package/dist/pack.mjs.map +1 -1
  16. package/dist/runtime.d.mts +20 -0
  17. package/dist/runtime.d.mts.map +1 -0
  18. package/dist/runtime.mjs +28 -0
  19. package/dist/runtime.mjs.map +1 -0
  20. package/dist/schema-verify.mjs +1 -1
  21. package/dist/{verify-mongo-schema-P0TRBJNs.mjs → verify-mongo-schema-Daa7BMJY.mjs} +1 -1
  22. package/dist/{verify-mongo-schema-P0TRBJNs.mjs.map → verify-mongo-schema-Daa7BMJY.mjs.map} +1 -1
  23. package/package.json +16 -14
  24. package/src/core/marker-ledger.ts +90 -20
  25. package/src/core/migration-factories.ts +8 -0
  26. package/src/core/mongo-ops-serializer.ts +0 -8
  27. package/src/core/mongo-planner.ts +8 -2
  28. package/src/core/mongo-runner.ts +80 -57
  29. package/src/core/planner-produced-migration.ts +0 -1
  30. package/src/core/render-typescript.ts +3 -7
  31. package/src/exports/runtime.ts +38 -0
  32. package/dist/migration-factories-Dbk5afMU.mjs.map +0 -1
@@ -1,11 +1,11 @@
1
- import { a as DropCollectionCall, c as schemaCollectionToCreateCollectionOptions, i as CreateIndexCall, l as schemaIndexToCreateIndexOptions, n as CollModMeta, o as DropIndexCall, r as CreateCollectionCall, s as OpFactoryCall, t as CollModCall } from "./op-factory-call-CVgzmLJh.mjs";
1
+ import { a as DropCollectionCall, c as schemaCollectionToCreateCollectionOptions, i as CreateIndexCall, l as schemaIndexToCreateIndexOptions, n as CollModMeta, o as DropIndexCall, r as CreateCollectionCall, s as OpFactoryCall, t as CollModCall } from "./op-factory-call--nK5dk8n.mjs";
2
2
  import { MongoSchemaIR } from "@prisma-next/mongo-schema-ir";
3
3
  import { MongoQueryPlan } from "@prisma-next/mongo-query-ast/execution";
4
4
  import { AnyMongoMigrationOperation, MongoAndExpr, MongoDdlCommandVisitor, MongoExistsExpr, MongoExprFilter, MongoFieldFilter, MongoFilterExpr, MongoFilterVisitor, MongoInspectionCommandVisitor, MongoMigrationPlanOperation, MongoNotExpr, MongoOrExpr } from "@prisma-next/mongo-query-ast/control";
5
5
  import { Migration, MigrationMeta } from "@prisma-next/migration-tools/migration";
6
6
  import { MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlanWithAuthoringSurface, MigrationPlanner, MigrationPlannerConflict, MigrationPlannerResult, MigrationRunnerExecutionChecks, MigrationRunnerResult, MigrationScaffoldContext, OperationContext } from "@prisma-next/framework-components/control";
7
7
  import { MongoContract } from "@prisma-next/mongo-contract";
8
- import { ContractMarkerRecord } from "@prisma-next/contract/types";
8
+ import { Contract, ContractMarkerRecord } from "@prisma-next/contract/types";
9
9
  import { Db } from "mongodb";
10
10
  import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
11
11
  import { MongoAdapter, MongoDriver } from "@prisma-next/mongo-lowering";
@@ -33,10 +33,21 @@ declare function readMarker(db: Db): Promise<ContractMarkerRecord | null>;
33
33
  declare function initMarker(db: Db, destination: {
34
34
  readonly storageHash: string;
35
35
  readonly profileHash: string;
36
+ readonly invariants?: readonly string[];
36
37
  }): Promise<void>;
38
+ /**
39
+ * Updates the marker doc atomically (CAS on `expectedFrom`).
40
+ *
41
+ * `destination.invariants`:
42
+ * - `undefined` → existing field left untouched.
43
+ * - explicit value → merged into the existing field server-side via an
44
+ * aggregation pipeline (`$setUnion + $sortArray`), atomic at the
45
+ * document level. `[]` is a no-op merge.
46
+ */
37
47
  declare function updateMarker(db: Db, expectedFrom: string, destination: {
38
48
  readonly storageHash: string;
39
49
  readonly profileHash: string;
50
+ readonly invariants?: readonly string[];
40
51
  }): Promise<boolean>;
41
52
  declare function writeLedgerEntry(db: Db, entry: {
42
53
  readonly edgeId: string;
@@ -68,7 +79,12 @@ declare class MongoMigrationPlanner implements MigrationPlanner<'mongo', 'mongo'
68
79
  readonly contract: unknown;
69
80
  readonly schema: unknown;
70
81
  readonly policy: MigrationOperationPolicy;
71
- readonly fromHash: string;
82
+ /**
83
+ * The "from" contract (state the planner assumes the database starts at),
84
+ * or `null` for reconciliation flows. Used to populate `describe().from`
85
+ * on the produced plan as `fromContract?.storage.storageHash ?? null`.
86
+ */
87
+ readonly fromContract: Contract | null;
72
88
  readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'mongo', 'mongo'>>;
73
89
  }): MigrationPlannerResult;
74
90
  /**
@@ -89,10 +105,12 @@ interface MarkerOperations {
89
105
  initMarker(destination: {
90
106
  readonly storageHash: string;
91
107
  readonly profileHash: string;
108
+ readonly invariants?: readonly string[];
92
109
  }): Promise<void>;
93
110
  updateMarker(expectedFrom: string, destination: {
94
111
  readonly storageHash: string;
95
112
  readonly profileHash: string;
113
+ readonly invariants?: readonly string[];
96
114
  }): Promise<boolean>;
97
115
  writeLedgerEntry(entry: {
98
116
  readonly edgeId: string;
@@ -165,9 +183,8 @@ declare function renderOps(calls: ReadonlyArray<OpFactoryCall>): MongoMigrationP
165
183
  //#endregion
166
184
  //#region src/core/render-typescript.d.ts
167
185
  interface RenderMigrationMeta {
168
- readonly from: string;
186
+ readonly from: string | null;
169
187
  readonly to: string;
170
- readonly kind?: string;
171
188
  readonly labels?: readonly string[];
172
189
  }
173
190
  /**
@@ -176,8 +193,8 @@ interface RenderMigrationMeta {
176
193
  * `Migration` (i.e. `MongoMigration`) from `@prisma-next/family-mongo`, and
177
194
  * implements the abstract `operations` and `describe` members. `meta` is
178
195
  * always rendered — `describe()` is part of the `Migration` contract, so
179
- * even an empty stub must satisfy it; callers pass empty strings for a
180
- * migration-new scaffold.
196
+ * even an empty stub must satisfy it; callers pass `from: null` for a
197
+ * baseline `migration-new` scaffold (and a real `to` hash either way).
181
198
  *
182
199
  * The walk is polymorphic: each call node contributes its own
183
200
  * `renderTypeScript()` expression and declares its own
@@ -1 +1 @@
1
- {"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/contract-to-schema.ts","../src/core/ddl-formatter.ts","../src/core/filter-evaluator.ts","../src/core/marker-ledger.ts","../src/core/mongo-ops-serializer.ts","../src/core/mongo-planner.ts","../src/core/mongo-runner.ts","../src/core/planner-produced-migration.ts","../src/core/render-ops.ts","../src/core/render-typescript.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/contract-to-schema.ts","../src/core/ddl-formatter.ts","../src/core/filter-evaluator.ts","../src/core/marker-ledger.ts","../src/core/mongo-ops-serializer.ts","../src/core/mongo-planner.ts","../src/core/mongo-runner.ts","../src/core/planner-produced-migration.ts","../src/core/render-ops.ts","../src/core/render-typescript.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/control.mjs CHANGED
@@ -1,10 +1,10 @@
1
- import { n as contractToMongoSchemaIR, t as verifyMongoSchema } from "./verify-mongo-schema-P0TRBJNs.mjs";
2
- import { a as dropCollection, n as createCollection, o as dropIndex, r as createIndex, t as collMod } from "./migration-factories-Dbk5afMU.mjs";
1
+ import { n as contractToMongoSchemaIR, t as verifyMongoSchema } from "./verify-mongo-schema-Daa7BMJY.mjs";
2
+ import { a as dropCollection, n as createCollection, o as dropIndex, r as createIndex, t as collMod } from "./migration-factories-CoNYWrd1.mjs";
3
3
  import { canonicalize, deepEqual } from "@prisma-next/mongo-schema-ir";
4
4
  import { AggregateCommand, MongoAddFieldsStage, MongoLimitStage, MongoLookupStage, MongoMatchStage, MongoMergeStage, MongoProjectStage, MongoSortStage, RawAggregateCommand, RawDeleteManyCommand, RawDeleteOneCommand, RawFindOneAndDeleteCommand, RawFindOneAndUpdateCommand, RawInsertManyCommand, RawInsertOneCommand, RawUpdateManyCommand, RawUpdateOneCommand } from "@prisma-next/mongo-query-ast/execution";
5
+ import { type } from "arktype";
5
6
  import { CollModCommand, CreateCollectionCommand, CreateIndexCommand, DropCollectionCommand, DropIndexCommand, ListCollectionsCommand, ListIndexesCommand, MongoAndExpr, MongoExistsExpr, MongoFieldFilter, MongoNotExpr, MongoOrExpr } from "@prisma-next/mongo-query-ast/control";
6
7
  import { ifDefined } from "@prisma-next/utils/defined";
7
- import { type } from "arktype";
8
8
  import { TsExpression, jsonToTsSource, renderImports } from "@prisma-next/ts-render";
9
9
  import { Migration } from "@prisma-next/migration-tools/migration";
10
10
  import { detectScaffoldRuntime, shebangLineFor } from "@prisma-next/migration-tools/migration-ts";
@@ -138,6 +138,31 @@ var FilterEvaluator = class {
138
138
  //#region src/core/marker-ledger.ts
139
139
  const COLLECTION = "_prisma_migrations";
140
140
  const MARKER_ID = "marker";
141
+ const MongoMarkerDocSchema = type({
142
+ storageHash: "string",
143
+ profileHash: "string",
144
+ "contractJson?": "unknown | null",
145
+ "canonicalVersion?": "number | null",
146
+ "updatedAt?": "Date",
147
+ "appTag?": "string | null",
148
+ "meta?": type({ "[string]": "unknown" }).or("null"),
149
+ "invariants?": type("string").array(),
150
+ "+": "delete"
151
+ });
152
+ function parseMongoMarkerDoc(doc) {
153
+ const result = MongoMarkerDocSchema(doc);
154
+ if (result instanceof type.errors) throw new Error(`Invalid marker doc on ${COLLECTION}: ${result.summary}`);
155
+ return {
156
+ storageHash: result.storageHash,
157
+ profileHash: result.profileHash,
158
+ contractJson: result.contractJson ?? null,
159
+ canonicalVersion: result.canonicalVersion ?? null,
160
+ updatedAt: result.updatedAt ?? /* @__PURE__ */ new Date(),
161
+ appTag: result.appTag ?? null,
162
+ meta: result.meta ?? {},
163
+ invariants: result.invariants ?? []
164
+ };
165
+ }
141
166
  async function executeAggregate(db, cmd) {
142
167
  return db.collection(cmd.collection).aggregate(cmd.pipeline).toArray();
143
168
  }
@@ -150,15 +175,7 @@ async function executeFindOneAndUpdate(db, cmd) {
150
175
  async function readMarker(db) {
151
176
  const doc = (await executeAggregate(db, new RawAggregateCommand(COLLECTION, [{ $match: { _id: MARKER_ID } }, { $limit: 1 }])))[0];
152
177
  if (!doc) return null;
153
- return {
154
- storageHash: doc["storageHash"],
155
- profileHash: doc["profileHash"],
156
- contractJson: doc["contractJson"] ?? null,
157
- canonicalVersion: doc["canonicalVersion"] ?? null,
158
- updatedAt: doc["updatedAt"],
159
- appTag: doc["appTag"] ?? null,
160
- meta: doc["meta"] ?? {}
161
- };
178
+ return parseMongoMarkerDoc(doc);
162
179
  }
163
180
  async function initMarker(db, destination) {
164
181
  await executeInsertOne(db, new RawInsertOneCommand(COLLECTION, {
@@ -169,18 +186,36 @@ async function initMarker(db, destination) {
169
186
  canonicalVersion: null,
170
187
  updatedAt: /* @__PURE__ */ new Date(),
171
188
  appTag: null,
172
- meta: {}
189
+ meta: {},
190
+ invariants: destination.invariants ?? []
173
191
  }));
174
192
  }
193
+ /**
194
+ * Updates the marker doc atomically (CAS on `expectedFrom`).
195
+ *
196
+ * `destination.invariants`:
197
+ * - `undefined` → existing field left untouched.
198
+ * - explicit value → merged into the existing field server-side via an
199
+ * aggregation pipeline (`$setUnion + $sortArray`), atomic at the
200
+ * document level. `[]` is a no-op merge.
201
+ */
175
202
  async function updateMarker(db, expectedFrom, destination) {
176
- return await executeFindOneAndUpdate(db, new RawFindOneAndUpdateCommand(COLLECTION, {
177
- _id: MARKER_ID,
178
- storageHash: expectedFrom
179
- }, { $set: {
203
+ const setBase = {
180
204
  storageHash: destination.storageHash,
181
205
  profileHash: destination.profileHash,
182
206
  updatedAt: /* @__PURE__ */ new Date()
183
- } }, false)) !== null;
207
+ };
208
+ const update = destination.invariants === void 0 ? { $set: setBase } : [{ $set: {
209
+ ...setBase,
210
+ invariants: { $sortArray: {
211
+ input: { $setUnion: [{ $ifNull: ["$invariants", []] }, destination.invariants] },
212
+ sortBy: 1
213
+ } }
214
+ } }];
215
+ return await executeFindOneAndUpdate(db, new RawFindOneAndUpdateCommand(COLLECTION, {
216
+ _id: MARKER_ID,
217
+ storageHash: expectedFrom
218
+ }, update, false)) !== null;
184
219
  }
185
220
  async function writeLedgerEntry(db, entry) {
186
221
  await executeInsertOne(db, new RawInsertOneCommand(COLLECTION, {
@@ -320,13 +355,9 @@ const QueryPlanJson = type({
320
355
  target: "string",
321
356
  storageHash: "string",
322
357
  lane: "string",
323
- paramDescriptors: "unknown[]",
324
358
  "targetFamily?": "string",
325
359
  "profileHash?": "string",
326
- "annotations?": "Record<string, unknown>",
327
- "refs?": "Record<string, unknown>",
328
- "projection?": "Record<string, string> | string[]",
329
- "projectionTypes?": "Record<string, string>"
360
+ "annotations?": "Record<string, unknown>"
330
361
  })
331
362
  });
332
363
  const CheckJson = type({
@@ -490,13 +521,9 @@ function deserializeMongoQueryPlan(json) {
490
521
  target: m.target,
491
522
  storageHash: m.storageHash,
492
523
  lane: m.lane,
493
- paramDescriptors: m.paramDescriptors,
494
524
  ...ifDefined("targetFamily", m.targetFamily),
495
525
  ...ifDefined("profileHash", m.profileHash),
496
- ...ifDefined("annotations", m.annotations),
497
- ...ifDefined("refs", m.refs),
498
- ...ifDefined("projection", m.projection),
499
- ...ifDefined("projectionTypes", m.projectionTypes)
526
+ ...ifDefined("annotations", m.annotations)
500
527
  };
501
528
  return {
502
529
  collection: data.collection,
@@ -818,8 +845,8 @@ const BASE_IMPORTS = [{
818
845
  * `Migration` (i.e. `MongoMigration`) from `@prisma-next/family-mongo`, and
819
846
  * implements the abstract `operations` and `describe` members. `meta` is
820
847
  * always rendered — `describe()` is part of the `Migration` contract, so
821
- * even an empty stub must satisfy it; callers pass empty strings for a
822
- * migration-new scaffold.
848
+ * even an empty stub must satisfy it; callers pass `from: null` for a
849
+ * baseline `migration-new` scaffold (and a real `to` hash either way).
823
850
  *
824
851
  * The walk is polymorphic: each call node contributes its own
825
852
  * `renderTypeScript()` expression and declares its own
@@ -861,7 +888,6 @@ function buildDescribeMethod(meta) {
861
888
  lines.push(" return {");
862
889
  lines.push(` from: ${JSON.stringify(meta.from)},`);
863
890
  lines.push(` to: ${JSON.stringify(meta.to)},`);
864
- if (meta.kind) lines.push(` kind: ${JSON.stringify(meta.kind)},`);
865
891
  if (meta.labels && meta.labels.length > 0) lines.push(` labels: ${jsonToTsSource(meta.labels)},`);
866
892
  lines.push(" };");
867
893
  lines.push(" }");
@@ -908,7 +934,6 @@ var PlannerProducedMongoMigration = class extends Migration {
908
934
  return renderCallsToTypeScript(this.calls, {
909
935
  from: this.meta.from,
910
936
  to: this.meta.to,
911
- ...ifDefined("kind", this.meta.kind),
912
937
  ...ifDefined("labels", this.meta.labels)
913
938
  });
914
939
  }
@@ -1030,7 +1055,7 @@ var MongoMigrationPlanner = class {
1030
1055
  return {
1031
1056
  kind: "success",
1032
1057
  plan: new PlannerProducedMongoMigration(result.calls, {
1033
- from: options.fromHash,
1058
+ from: options.fromContract?.storage.storageHash ?? null,
1034
1059
  to: contract.storage.storageHash
1035
1060
  })
1036
1061
  };
@@ -1142,40 +1167,44 @@ var MongoMigrationRunner = class {
1142
1167
  }
1143
1168
  const destination = options.plan.destination;
1144
1169
  const profileHash = options.destinationContract.profileHash ?? destination.storageHash;
1145
- if (operationsExecuted === 0 && existingMarker?.storageHash === destination.storageHash && existingMarker.profileHash === profileHash) return ok({
1146
- operationsPlanned: operations.length,
1147
- operationsExecuted
1148
- });
1149
- const liveSchema = await this.deps.introspectSchema();
1150
- const verifyResult = verifyMongoSchema({
1151
- contract: options.destinationContract,
1152
- schema: liveSchema,
1153
- strict: options.strictVerification ?? true,
1154
- frameworkComponents: options.frameworkComponents,
1155
- ...options.context ? { context: options.context } : {}
1156
- });
1157
- if (!verifyResult.ok) return runnerFailure("SCHEMA_VERIFY_FAILED", verifyResult.summary, {
1158
- why: "The resulting database schema does not satisfy the destination contract.",
1159
- meta: { issues: verifyResult.schema.issues }
1160
- });
1161
- if (existingMarker) {
1162
- if (!await markerOps.updateMarker(existingMarker.storageHash, {
1170
+ const incomingInvariants = options.plan.providedInvariants ?? [];
1171
+ const existingInvariantSet = new Set(existingMarker?.invariants ?? []);
1172
+ const incomingIsSubsetOfExisting = incomingInvariants.every((id) => existingInvariantSet.has(id));
1173
+ const markerAlreadyAtDestination = existingMarker !== null && existingMarker.storageHash === destination.storageHash && existingMarker.profileHash === profileHash;
1174
+ if (!(operationsExecuted === 0 && markerAlreadyAtDestination && incomingIsSubsetOfExisting)) {
1175
+ const liveSchema = await this.deps.introspectSchema();
1176
+ const verifyResult = verifyMongoSchema({
1177
+ contract: options.destinationContract,
1178
+ schema: liveSchema,
1179
+ strict: options.strictVerification ?? true,
1180
+ frameworkComponents: options.frameworkComponents,
1181
+ ...options.context ? { context: options.context } : {}
1182
+ });
1183
+ if (!verifyResult.ok) return runnerFailure("SCHEMA_VERIFY_FAILED", verifyResult.summary, {
1184
+ why: "The resulting database schema does not satisfy the destination contract.",
1185
+ meta: { issues: verifyResult.schema.issues }
1186
+ });
1187
+ if (existingMarker) {
1188
+ if (!await markerOps.updateMarker(existingMarker.storageHash, {
1189
+ storageHash: destination.storageHash,
1190
+ profileHash,
1191
+ invariants: incomingInvariants
1192
+ })) return runnerFailure("MARKER_CAS_FAILURE", "Marker was modified by another process during migration execution.", { meta: {
1193
+ expectedStorageHash: existingMarker.storageHash,
1194
+ destinationStorageHash: destination.storageHash
1195
+ } });
1196
+ } else await markerOps.initMarker({
1163
1197
  storageHash: destination.storageHash,
1164
- profileHash
1165
- })) return runnerFailure("MARKER_CAS_FAILURE", "Marker was modified by another process during migration execution.", { meta: {
1166
- expectedStorageHash: existingMarker.storageHash,
1167
- destinationStorageHash: destination.storageHash
1168
- } });
1169
- } else await markerOps.initMarker({
1170
- storageHash: destination.storageHash,
1171
- profileHash
1172
- });
1173
- const originHash = existingMarker?.storageHash ?? "";
1174
- await markerOps.writeLedgerEntry({
1175
- edgeId: `${originHash}->${destination.storageHash}`,
1176
- from: originHash,
1177
- to: destination.storageHash
1178
- });
1198
+ profileHash,
1199
+ invariants: incomingInvariants
1200
+ });
1201
+ const originHash = existingMarker?.storageHash ?? "";
1202
+ await markerOps.writeLedgerEntry({
1203
+ edgeId: `${originHash}->${destination.storageHash}`,
1204
+ from: originHash,
1205
+ to: destination.storageHash
1206
+ });
1207
+ }
1179
1208
  return ok({
1180
1209
  operationsPlanned: operations.length,
1181
1210
  operationsExecuted
@@ -1195,7 +1224,7 @@ var MongoMigrationRunner = class {
1195
1224
  };
1196
1225
  }
1197
1226
  for (const plan of op.run) {
1198
- const wireCommand = adapter.lower(plan);
1227
+ const wireCommand = await adapter.lower(plan, {});
1199
1228
  for await (const _ of driver.execute(wireCommand));
1200
1229
  }
1201
1230
  if (runPostchecks && op.postcheck.length > 0) {
@@ -1221,7 +1250,7 @@ var MongoMigrationRunner = class {
1221
1250
  collection: check.source.collection
1222
1251
  }
1223
1252
  });
1224
- const wireCommand = adapter.lower(check.source);
1253
+ const wireCommand = await adapter.lower(check.source, {});
1225
1254
  let matchFound = false;
1226
1255
  for await (const row of driver.execute(wireCommand)) if (filterEvaluator.evaluate(check.filter, row)) {
1227
1256
  matchFound = true;
@@ -1254,10 +1283,7 @@ var MongoMigrationRunner = class {
1254
1283
  }
1255
1284
  ensureMarkerCompatibility(marker, plan) {
1256
1285
  const origin = plan.origin ?? null;
1257
- if (!origin) {
1258
- if (marker) return runnerFailure("MARKER_ORIGIN_MISMATCH", "Database already has a contract marker but the plan has no origin. This would silently overwrite the existing marker.", { meta: { markerStorageHash: marker.storageHash } });
1259
- return;
1260
- }
1286
+ if (!origin) return;
1261
1287
  if (!marker) return runnerFailure("MARKER_ORIGIN_MISMATCH", `Missing contract marker: expected origin storage hash ${origin.storageHash}.`, { meta: { expectedOriginStorageHash: origin.storageHash } });
1262
1288
  if (marker.storageHash !== origin.storageHash) return runnerFailure("MARKER_ORIGIN_MISMATCH", `Existing contract marker (${marker.storageHash}) does not match plan origin (${origin.storageHash}).`, { meta: {
1263
1289
  markerStorageHash: marker.storageHash,