Renovate-style role-manifest migration automation: design proposal
Defines reviewable local and automated pull-request flows for role-manifest schema migrations.
Research state: Incomplete
Summary
Schema migration and repository automation are separate concerns; automated manifest updates should arrive as reviewable pull requests.
Schema and role-manifest migration commands are documented in Schema versions. This page defines local and hosted pull-request capabilities; Config versioning and migration owns delivery.
Research question
How should jackin❯ migrate its owned configuration files and help role authors update jackin.role.toml without silently writing to repositories it does not own? jackin❯ can migrate config.toml and per-workspace files on startup, while a role manifest requires explicit repository authorization and a reviewable diff.
Why it matters
Versioned migrations protect operator-owned configuration from destructive recreation. Role repositories require a separate capability because jackin❯ cannot mutate them without consent; reviewable pull requests make schema changes visible to role authors and CI.
Relationship to the pre-release rule
AGENTS.md states: "Do not write migration code, compatibility shims, fallback parsers for old field names, 'tolerant ignore + warn' handlers, or deprecation warnings. Make the new shape the only shape; let stale configs fail with the standard parser error." The migration framework is a deliberate, scoped exception for the three file kinds operators and role authors actively edit (config.toml, per-workspace files, jackin.role.toml) — breaking changes to those three must bump the version and add a migration step. The pre-release exemption stays in force for every other surface (CLI flags, internal Rust APIs) until the first tagged release.
Local migration pull requests
After jackin❯ role migrate writes the updated manifest to a local clone, an opt-in --pr flag would create a branch and open a pull request in the role repo via gh, gated on: gh authenticated with write access to the role repo, the role repo resolving to a github.com URL (the git source in config.toml), and a deterministic branch name (jackin/manifest-migrate-v{old}-to-v{new}). This would let the jackin❯ maintainer migrate all first-party role repos in one pass when a breaking manifest change ships, and let operators send migration PRs to third-party role repos they depend on, without needing --pr automation running anywhere but their own machine.
Scheduled repository automation
--pr only runs from an operator's machine, so a role repo whose author never runs jackin role migrate stays broken in CI until someone opens a PR by hand. A scheduled action closes that gap by watching role repos and opening migration PRs upstream automatically, running the small jackin-role binary rather than the full jackin operator binary. The proposal extends the existing jackin-project/jackin-role-action (already used today for validate-only workflows in generated role repos) with a migrate mode, rather than introducing a separate action repo role authors would need to install.
Two deployment shapes mirror Renovate's own hosted-vs-self-hosted split:
- Hosted GitHub App (Mend Renovate equivalent) — a runner hosted by jackin-project, role-repo authors only install the app. The app holds
pull_requests:write+contents:writeon the repos it watches and runs the migration on a cron from a central runner. Identity for the PR is the app bot, parallel torenovate[bot]. Authors do not manage tokens. - Self-hosted workflow with PAT or
GITHUB_TOKEN(renovate-bot/renovate-actionequivalent) — the runner is the role repo's own GitHub Actions. Role authors add a workflow that calls the action on a schedule (on: schedule: - cron: "0 6 * * *") and onworkflow_dispatch. The workflow usessecrets.GITHUB_TOKEN(opens PRs from the same repo) or an operator-supplied PAT for cross-repo cases. Authors manage the token themselves but skip the app registration.
Per-run flow (both modes):
- Check out the role repo at the default branch.
- Run
jackin-role validate <repo>to detect whether the manifest is already current. If yes, jump to the cleanup step below. - Switch to a deterministic branch name (e.g.
jackin/schema-migration/v1alpha1-to-v1alpha2) and run the manifest migrator. - Commit the migrated manifest with a fixed message shape; push.
- Open a PR if none exists for that branch; update the existing PR if one does (Renovate's "branch is the source of truth" model). PR body links to the Schema Versions page and names the source jackin❯ tag for traceability.
Cleanup (subsequent runs only): if a previous run opened a migration PR and the manifest is now current (because the maintainer hand-merged or hand-migrated), close the PR and delete the branch so zombies do not accumulate.
Limitations and open questions
- Target-repo discovery. How does the central runner enumerate which repos to scan? Renovate uses an onboarding PR plus a per-repo config file; jackin❯'s analog is unspecified. Options include push-event subscriptions, an explicit per-repo allowlist, or organization-level configuration.
- App vs. PAT default in docs. Renovate's default-recommended path is the hosted app; jackin❯ picks one as the documented default and calls out the other as fallback.
- Source of "current schema." The action needs to know which
CURRENT_MANIFEST_VERSIONto migrate to. Options: pin to the latestjackin-rolerelease, follow the samelatest-buildchannel as the existing validate action, or pin per-workflow. This affects how new schema versions roll out across the role-repo ecosystem. - Branch lifecycle. When a role author rebases, force-pushes, or hand-edits the migration PR, the action must detect drift and either rebase its own commit or stop (Renovate calls this "rebase strategy" and supports multiple modes; jackin❯ picks one).
- Conflict handling. If a role author has already partially migrated, the action's migration step may produce a no-op diff. The action needs to detect that case and close the PR rather than open an empty one.
Current constraints
Current migration behavior establishes these constraints:
- Retention window. jackin❯ does not keep old migration code forever; a
versionolder than the oldest step in the registry, or newer than the binary's current version, errors rather than attempting a direct migration. Operators upgrade through an older jackin❯ first. This is the current behavior (see the error-mode rows in Schema Versions), not a proposal. - Config migration failure recovery. Writes use
atomic_write(temp file + rename) incrates/jackin-config/src/app_config/persist.rs, so a failed write aborts startup with a clear error instead of leaving a half-written file. - Schema changelog. The original open question was where a "what changed between vN and vN+1" changelog should live. Schema Versions is that location and is updated on every version bump.
- Comment preservation during migration.
toml_editpreserves document structure for unchanged tables, but migrated tables (renamed keys, restructured sections) lose their original comments — the stderr migration message names this so operators know comments on rewritten sections must be re-applied by hand. This is a known, accepted limitation rather than an open question.
Related work
- Config versioning and migration framework — owns delivery of this design.
- Schema Versions — canonical version history and migration tables.
- Configuration File —
versionfield and config schema reference. - Publishing Role Images — the existing
jackin-project/jackin-role-actionvalidate/publish workflow this proposal would extend.