Preparing a v0.1 migration

migrate-prepare reads the bundle and creates a new directory outside it. The directory must not exist. The command never opens the private store and never changes source documents.

okf migrate old-bundle --to 0.2 --format json
okf migrate-prepare old-bundle --output-dir ../migration-inputs --format json

The directory contains:

After resolving the report and filling the templates, preview and apply through the existing migration path:

okf migrate old-bundle --to 0.2 --actor human:author \
  --citation-mappings ../migration-inputs/citation-mappings.json \
  --generated-at ../migration-inputs/generated-at.json \
  --prepared-source-sha256 HASH_FROM_REPORT --format json

okf migrate old-bundle --to 0.2 --actor human:author \
  --citation-mappings ../migration-inputs/citation-mappings.json \
  --generated-at ../migration-inputs/generated-at.json \
  --prepared-source-sha256 HASH_FROM_REPORT --write --format json

--prepared-source-sha256 rejects a changed bundle before planning. Regenerate the directory under a new name after any source change. The normal preview/apply path still checks its own revision, source resolution, request digest and plan proof. Empty source_id or at values fail the strict input loaders, so an unconfirmed template cannot be applied. When no per-document instant is needed, generated-at.json is []; the flag may be omitted.

For example, two identical unnumbered citations cannot be selected independently by the current mapping DTO. The report marks both as duplicate or unrepresentable parser-owned citation selectors and omits them from the template. The caller must resolve the ambiguity in the source or use a supported unique selector, then prepare again. An unrecognized prose paragraph inside # Citations is reported with its byte span; it is never silently removed. A fenced pseudo-citation is reported as opaque content, not converted to a source.

If a document already has structured sources alongside legacy # Citations, the report emits sources_citations_conflict and omits a mapping for that document. The migration planner also blocks this mixed representation; the caller must reconcile it explicitly before preparing again.

A leading UTF-8 BOM before --- is reported as leading_bom_unsupported at bytes 0–3. The exact frontmatter parser does not recognize that opening line; migration fails closed and leaves the document bytes unchanged. BOM bytes within valid body text or opaque YAML values are preserved by the existing mutation path.

The helper exports no migration proof and performs no mutation. A blocked preview remains blocked until its manual actions are resolved.