Closes #519
/claim #519

Summary

This PR implements a pure, algebraic schema migration system for ZIO Blocks. The architecture shifts
migration validation from runtime to compile time, ensuring mathematically sound shape equivalence between schema versions.

Architecture

Pure data core. Migrations are modelled as a MigrationAction ADT — no closures, opaque functions,
or reflection. Every migration is fully serialisable.

Selector macro API. Custom macros for Scala 2.13 (scala-reflect) and Scala 3 (scala.quoted)
extract S => A selector lambdas into DynamicOptic paths at compile time. The developer-facing API is identical across both versions:

MigrationBuilder[PersonV1, PersonV2]
.renameField(_.name, _.fullName)
.build

Two-layer design.

  • DynamicMigration — untyped, serialisable core operating on DynamicValue
  • Migration[A, B] — typed façade with Schema-driven encode/decode

Compile-Time Validation

The .build macro performs a symbolic dry-run of the builder AST against structural Refinement types, proving shape equivalence at compile time. A missing or misaligned field is a compiler error, not a runtime failure. Structural types (e.g. type PersonV0 = { def firstName: String }) are natively
supported for past schema versions without requiring concrete case classes.

Cross-version AST stability is maintained across Scala 3.3.x and 3.7.x — the SelectorMacro intercepts
both Ident and Select patterns arising from reflectiveSelectableFromLangReflectiveCalls desugaring. End-to-end proof is in jvm/src/test/scala-3/.../StructuralTypeMigrationSpec.scala.

Algebraic Laws

MigrationLawsSpec verifies the following invariants via property-based testing:

  • Identityempty.apply(v) == Right(v) for any Record or Variant
  • Associativity(m1 ++ m2) ++ m3 and m1 ++ (m2 ++ m3) produce identical results
  • Reversibilitym.reverse.reverse.actions.length == m.actions.length; round-trips recover the
    original value for all invertible operations

44 tests pass across Scala 2.13, 3.3, and 3.7 on both JVM and JS targets.

https://github.com/user-attachments/assets/01f3e8e1-731a-4762-b7eb-46dc82d20a13

Claim

Total prize pool $8,000
Total paid $0
Status Pending
Submitted March 14, 2026
Last updated March 14, 2026

Contributors

DA

Dakoda

@DakodaStemen

100%

Sponsors

MA

marianaguzmanguerrero16-dev

@marianaguzmanguerrero16-dev

$4,000
ZI

ZIO

@ZIO

$4,000