Migrations
Artifacts and approval policy
Review migration files and approve the exact operations they will run.
An artifact is a versioned migration file. Qubu supports two kinds:
- An executable migration contains a reviewed plan and the program to run.
- A verified baseline records the observed schema as a starting point. It does not claim that historical SQL ran through Qubu.
Published formats
These format versions are independent of npm package semver:
| Value | Current version | Meaning |
|---|---|---|
qubu-executable-migration |
1 | Executable artifact envelope |
qubu-verified-baseline |
1 | Non-executable verified starting point |
qubu-migration-program |
1 | Ordered executable phases and statements |
qubu-migration-plan |
2 | Dialect-neutral reviewed plan |
qubu-canonical-json |
1 | Canonical JSON byte encoding |
sha-256 |
1 | Operational digest algorithm contract |
qubu-migration-journal |
1 | Logical journal format |
Strict decoders reject unknown keys, malformed values, non-canonical encoded text, unsupported versions, and digest mismatches. There is no compatibility decoder for provisional application formats.
Executable artifact schema
An executable artifact records:
id, zero-basedsequence, andparentArtifactDigestlineage;- canonicalization and digest descriptors, dialect, and optional minimum server version or required capability constraints;
- the plan plus
planDigest; - renderer identity, the program, and
programDigest; - before/after snapshot descriptors, each with a strong digest and either an embedded snapshot or a reference;
- operation-scoped approvals and custom-program provenance;
- artifact provenance and
artifactDigest.
The executor runs the program stored in the artifact. The SQL preview from
emitMigrationPlan(...).sql is not an executable artifact.
Each phase declares:
- Its position and dependencies.
- Transaction and lock requirements.
- Preconditions and postconditions.
- Ordered statements.
Each statement declares its operation ID, dependencies, SQL, and tagged parameters.
Baseline artifact schema
A baseline records:
id, sequence, and parent lineage.- Encoding descriptors.
- Dialect and optional constraints.
- One verified snapshot descriptor and
verifiedAt. - Provenance and optional operator metadata.
artifactDigest.
It has no migration plan, program, or SQL digest.
Artifact IDs are stable identities, not repository order. Sequence and parent digest establish the linear chain. Renumbering therefore changes lineage and the artifact digest.
Canonical bytes and digest domains
encodeCanonical() produces a repeatable byte representation:
- Sort object keys by Unicode code-point order.
- Preserve array order.
- Emit compact UTF-8 JSON.
- Normalize
-0to0and reject non-finite numbers. - End the file with one line feed.
digestCanonical() prefixes those bytes with the UTF-8 bytes for:
qubu:migrate:v1:<domain>\0
The digest identifies its purpose through one of five domains:
artifact.baseline.migration-plan.migration-program.schema-snapshot.
The prefix ensures that identical JSON used for different purposes gets different digests.
Operational digests have the form sha256: plus 64 lowercase hexadecimal
digits and are recomputed while sealing or decoding.
Fingerprints and integrity digests
Snapshot and plan fingerprint APIs are deterministic FNV-1a64 change
detectors. They remain useful for caches and fixture assertions, but they are
not cryptographic integrity evidence and are never valid journal heads,
artifact parents, or substitutes for a SHA-256 field.
Exact approval policy
Preview planning may retain unresolved safety findings. Sealing is stricter:
| Operation state | Sealing rule |
|---|---|
| Safe and supported | No approval required |
| Review-required, destructive, or lossy | Exact operationId approval with a non-empty reason |
| Unknown or unsupported | Exact custom-program substitution and custom-program approval |
| Explicit custom SQL | Always requires exact review and a reason |
| Skipped operation | Recompute the target snapshot before sealing; never preserve a false after-digest |
An approval also records the operation's safety and the exact sorted finding
codes. It may record approvedBy and approvedAt. A mismatched operation ID,
safety classification, finding set, or decision fails compilation. A broad
"allow unsafe" option on the preview DDL emitter is not an artifact-sealing
approval.
Custom programs replace one exact operation. They must declare transaction and lock requirements, statements, tagged parameters, and any pre/postconditions, plus source and reason provenance. Qubu does not split arbitrary SQL, infer its effects, or approve it automatically.
Version and golden-fixture maintenance
Treat canonical bytes and the meaning of every published field as release contracts. When changing an encoder, tag, ordering rule, parameter encoding, renderer meaning, or schema:
- Keep golden values for every already-published artifact, baseline, program, plan, snapshot, canonicalization, and digest version.
- Verify the same canonical bytes and SHA-256 results in Node.js, Bun, and a worker-compatible Web Crypto runtime.
- If encoded bytes or semantics change, introduce a new explicit format, canonicalization, digest, plan, program, renderer, or artifact version as appropriate. Do not silently update a version 1 fixture.
- Keep old fixtures as decode/verification evidence for supported published versions; add a new fixture for the new version.
- Run artifact tamper/non-canonical tests and packed-package checks before release.
The current canonical SHA-256 vectors live with
packages/migrate/test/artifact.test.ts; changes to them require the same
intentional version decision as file-based golden fixtures.