Hub RFC 005 migration manifests
RFC-005 — Migration Manifests for Upgrade Chain Automation
| Field | Value |
|---|---|
| RFC | RFC-005 |
| Title | Migration Manifests — Automated min_upgrade_from Declaration |
| Author | Koder Engineering |
| Date | 2026 |
| Status | Draft |
| Depends on | RFC-004 (Upgrade Chains) |
Table of Contents
- Abstract
- Motivation
- Design
- Worked Example
- Validation Rules
- Security Considerations
- Compatibility
- Alternatives Considered
1. Abstract
RFC-004 introduced min_upgrade_from as a manually declared field passed via --min-upgrade-from at publish time. This RFC adds a *igration manifest*— a structured TOML file committed alongside the code — from which publish.sh reads min_upgrade_from automatically, and which Koder Flow can validate in CI before the release is created.
The goal is to make the upgrade chain constraint *o-located with the breaking change*(same commit, same diff review) rather than a publish-time memory exercise.
2. Motivation
2.1 The problem with pure manual declaration
RFC004 requires the publisher to remember to pass `minupgrade-from when
calling publish.sh`. The constraint is invisible during code review and easy to forget. A missed declaration silently breaks users who skip versions.
2.2 Why co-location matters
The moment a developer deletes the legacy migration code or changes a data format, that is the right moment to declare the constraint — in the same PR, in the same file tree. A manifest file committed alongside the breaking change:
- Appears in the PR diff and is reviewed as code.
- Is version-controlled and auditable via
git log. - Can be linted in CI before the release reaches users.
- Removes the publish-time memory burden.
3. Design
3.1 Manifest File Format
A TOML file with a single [upgrade] table:
# migrations/v3.0.0.toml
[upgrade]
min_upgrade_from = "2.0.0"
reason = "removes legacy binary config reader; JSON migration code lives in v2.x"Fields:
| Field | Type | Required | Description |
|---|---|---|---|
min_upgrade_from |
string | Yes | Semver lower bound (same semantics as RFC-004) |
reason |
string | No | Human-readable explanation — shown in admin review queue |
3.2 File Location
<repo-root>/
migrations/
v2.0.0.toml ← no constraint (absent = no constraint)
v3.0.0.toml ← declares min_upgrade_from = "2.0.0"
v3.1.0.toml ← absent = no constraint for v3.1.0- One file per version that carries a constraint.
- Versions with no constraint have no manifest file (absence =
min_upgrade_from: null). - The file name *ust*match the release version exactly:
v{VERSION}.toml.
3.3 publish.sh Auto-Detection
Before sending the publish request, publish.sh checks for the manifest:
REPO_ROOT/migrations/v{VERSION}.tomlIf found and --min-upgrade-from was *ot*passed explicitly on the command line, the script reads min_upgrade_from from the manifest and passes it to the API. Explicit --min-upgrade-from always takes precedence (allows overrides in automated pipelines).
*esolution order:*
--min-upgrade-fromCLI flag (explicit, highest priority)migrations/v{VERSION}.tomlmanifest (auto-detected)- None (no constraint)
3.4 Store Backend Handling
The publish API (POST /api/v1/publish/:slug) already accepts min_upgrade_from as a form field (RFC-004 §5.3). No change needed at the API level — publish.sh passes the value regardless of whether it came from the CLI flag or the manifest.
Optionally, the API can also accept the manifest file itself as a multipart upload (-F "migration_manifest=@migrations/v3.0.0.toml"), which allows richer server-side validation and preserves the reason field for the admin review queue. This is left as a backend enhancement (see §3.5).
3.5 Koder Flow Integration
When a release is created in Koder Flow (via UI or API), Flow can:
*. Surface the manifest in release notes*
If migrations/v{TAG}.toml exists in the repo at the release tag, Flow displays min_upgrade_from and reason prominently in:
- The release creation confirmation page.
- The release details page.
- The admin review queue (Koder Hub side).
*. CI lint step*
A pre-built lint action validates the manifest on every PR that touches a migrations/ file:
# .koder-ci.yml (example)
lint-migration-manifest:
run: khub-lint migrations/Validation checks:
min_upgrade_fromis valid semver.min_upgrade_from< the declared version (extracted from file name).- The referenced version exists in the published catalog (warning, not error).
*. Release webhook*
When a release is tagged, Flow can call the Store publish API with the manifest data as an additional form field, enabling the Store to store reason for admin review display.
4. Worked Example
Publisher is releasing v3.0.0 which removes the binary config reader:
# 1. Code change + manifest committed in the same PR:
git add src/config/json_reader.go migrations/v3.0.0.toml
git commit -m "feat: remove legacy binary config reader (requires v2.0.0 migration)"
# 2. Create release (tag + Flow release):
git tag products/dev/store/v3.0.0
git push origin products/dev/store/v3.0.0
# 3. Publish — no --min-upgrade-from needed:
publish.sh --slug my-app --version 3.0.0 --version-code 30 --file my-app.deb
# → Auto-detected min_upgrade_from=2.0.0 from migrations/v3.0.0.toml
# → Publishing my-app v3.0.0 [min_upgrade_from=2.0.0]5. Validation Rules
| Rule | Level | Description |
|---|---|---|
| Valid semver | Error | min_upgrade_from must be parseable semver |
min_upgrade_from < version |
Error | Prevents self-referential constraints |
| Referenced version published | Warning | Version in constraint may not exist yet (out |
reason present |
Warning | Recommended for admin review clarity |
| File name matches release version | Error | v3.0.0.toml must be published with --version 3.0.0 |
6. Security Considerations
The manifest is source-controlled and goes through code review — this is strictly safer than a publish-time CLI flag that bypasses review. The same publisherabuse mitigations from RFC004 §8.1 apply (admin review queue, yank protections).
7. Compatibility
- *pps without manifests:*
publish.shfinds no file, sends nomin_upgrade_from— identical to current behavior. - *pps with
--min-upgrade-fromflag:*flag wins over manifest — noregression for existing pipelines.
- *re
RFC005publish.sh:*ignores manifests silently; the publishermust pass
--min-upgrade-frommanually as today.
8. Alternatives Considered
A. Embed manifest inside the package artifact (.deb, .apk)
Store reads it from the binary at publish time.
*ejected for v1:*Requires modifying the build pipeline for every app. The source-repo manifest approach requires zero changes to how packages are built.
B. Heuristic artifact diff (automatic, no manifest)
Flow diffs consecutive release artifacts looking for removed files, schema changes, etc.
*eferred:*High false-positive rate; cannot reliably infer safe waypoints from binary diffs alone. Useful as a suggestion layer on top of manifests, not as a replacement. Tracked separately.
C. In-code annotation (@requiresUpgradeFrom("2.0.0"))
Source annotation that a static analysis tool reads.
*ejected:*Language-specific, requires SDK integration per platform, fragile across refactors. TOML manifest is language-agnostic.