Skip to content

feat(repo-ops): renumber-migration tool, gated on commands.migrationGraph - #88

Merged
allenhutchison merged 6 commits into
mainfrom
renumber-migration
Oct 5, 2026
Merged

allenhutchison merged 6 commits into
mainfrom
renumber-migration

Conversation

@allenhutchison

@allenhutchison allenhutchison commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Human overview

Adds renumber-migration.sh to repo-ops: after a migration collision it re-parents the branch's migrations onto the live base head, re-runs the repo's graph check, and reports one verdict. It is inert in any repo that does not set commands.migrationGraph, and it never commits or pushes. Part of P2 in the tech-lead-loop design (Q4 decided: maintainerd, gated on that key). Refs Vycari/vycari#102.

Human required (optional)

  • Pepper's .claude/maintainerd.json will need commands.migrationGraph and paths.migrations before the tool does anything there (pepper also has its own scripts/renumber_migration.py); not part of this PR.

AI reviewer

What the diff does. plugins/repo-ops/scripts/renumber-migration.sh (new, bash 3.2, jq/git/sed only): reads commands.migrationGraph (unset/null -> not-configured, exit 0, before touching git) and paths.migrations (no default; a set graph command without it is exit 3). Requires the base (origin/<defaultBranch>, fetched unless --no-fetch) to be an ancestor of HEAD, else refused:behind-base: the graph check can only judge a tree that holds the base's migrations. Base head = the one revision no other names as parent (not exactly one -> refused). Branch migrations = index files absent from the base, ordered into one linear chain; renamed to head+1.. in two phases via .renumber.N scratch names so 0172->0173 cannot clobber a not-yet-moved 0173. revision/down_revision and the docstring Revision ID:/Revises: lines are rewritten with sed -E to a temp file (BSD/GNU parity), then read back; a mismatch is exit 3 rather than a half-renumbered file. Changes are git added, not committed. Then the graph check runs from the repo root.

Contract mirrors wait-for-review/wait-for-checks style: verdict on line 1, exit mirrors it (0 ok, 1 graph-failed, 2 refused:<reason>, 3 tool could not run, never a verdict). Verdicts are listed in the script header and the README table.

Idempotence. The plan compares each file's current name and down_revision to the target; no difference -> up-to-date (graph check still runs). Files are read from the index, so a re-run after a staged but uncommitted renumber is also up-to-date. Tests cover re-run before commit, after commit, and a second renumber after main moves again.

Schema. commands.migrationGraph and paths.migrations added to the canonical config-schema.md (example + tables + prose) and re-vendored with sync-references.sh. No version bump: version-bump.yml does it on merge.

Alternatives rejected. A lib/ shared with the wait tools: this branch is off main, not #86, and wait-common.sh is wait-specific; the script is self-contained. Python (pepper's own renumber_migration.py is): the maintainerd scripts are bash and a stranger's repo may have no Python. Auto-rebasing the branch: it would rewrite history; the tool refuses and prints the command instead. Defaulting paths.migrations to an Alembic path: the brief and Q4 keep layout in config.

Known limits, stated plainly. (1) It only sees the base head; an id claimed by another still-open PR is invisible, so a graph check that names such a collision needs a re-run after that PR lands (pepper's tool can feed open PRs; not replicated here). (2) Numeric sequential ids and <id>_<slug> names only; hash ids, merge migrations, multi-parent or non-linear branch chains are refused:. (3) Stale prose references to an old id are reported, never edited. (4) A crash between the two git mv phases leaves .renumber.N files; the error text says how to recover.

Where to look hardest. The chain-order loop and the two-phase rename; the sed expressions (anchored to line start, matching only the exact old id); refuse vs die (verdict vs tool error).

Verification. ./scripts/test-renumber-migration.sh: 59 passed, 0 failed, on bash 5 and on macOS /bin/bash 3.2 (real throwaway git repos, bare origin, no network). shellcheck -S warning clean on both scripts. ./scripts/sync-references.sh --check, python3 scripts/check-links.py, check-merge-arming.py, and the other four test-*.sh suites pass. Not run: against pepper's real migrations or a real Alembic.

Deferred. Open-PR id reservation (limit 1), tracked under Vycari/vycari#102's tool follow-ups; no separate issue filed yet, will file one if the maintainer wants it.

Checklist (repo-specific)

  • Plugin manifests validate against the marketplace and stay within the closed Agent Plugins schema (N/A: no manifest changed)
  • Every skill has well-formed frontmatter (N/A: no skill changed)
  • ./scripts/test-coverage.sh and ./scripts/test-profile.sh pass locally
  • ./scripts/sync-references.sh --check passes (vendored reference docs still match canonical)
  • python3 scripts/check-links.py passes

https://claude.ai/code/session_01T7j4GUt15DJp7G9UK4tMNE

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no new findings or outstanding previous findings remain.

Summary

Adds a config-gated migration renumbering tool that re-parents a branch’s linear migrations onto the base head, stages the result, and runs the repository’s graph check. It also documents the configuration and adds a throwaway-repository test suite to CI.

Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Read migrationGraph configuration] --> B{Configured?}
  B -- No --> C[not-configured]
  B -- Yes --> D[Check base ancestry and migration chain]
  D --> E{Safe to renumber?}
  E -- No --> F[refused]
  E -- Yes --> G[Plan new IDs and parent revisions]
  G --> H{Changes needed?}
  H -- Yes --> I[Rename and rewrite; stage changes]
  H -- No --> J[Run graph check]
  I --> J
  J --> K[Report verdict]
Loading

Reviews (7) · Last reviewed commit: "renumber-migration: retitle its README s..."

@allenhutchison

Copy link
Copy Markdown
Collaborator Author

Deferred item (open-PR id reservation) is tracked in #89.

https://claude.ai/code/session_01T7j4GUt15DJp7G9UK4tMNE

Comment thread plugins/repo-ops/scripts/renumber-migration.sh
Comment thread plugins/repo-ops/scripts/renumber-migration.sh Outdated
Comment thread plugins/repo-ops/scripts/renumber-migration.sh
Comment thread plugins/repo-ops/scripts/renumber-migration.sh
Comment thread plugins/repo-ops/scripts/renumber-migration.sh Outdated
Comment thread plugins/repo-ops/scripts/renumber-migration.sh Outdated
Comment thread plugins/repo-ops/scripts/renumber-migration.sh Outdated
@allenhutchison

Copy link
Copy Markdown
Collaborator Author

Rebased onto main after #83 (merge-guard) merged; it was conflicting. Two text-only conflicts: the README layout tree now lists merge-guard alongside renumber-migration.sh, and in the repo-ops README the merge-guard section stays under Hooks, followed by the Tools section. No code conflicts. All validate.yml steps pass locally (hooks 190/0, renumber-migration 67/0).

https://claude.ai/code/session_01T7j4GUt15DJp7G9UK4tMNE

…raph

Re-parents a branch's migrations onto the live base head after a collision: git mv to
head+1.., rewrite revision/down_revision, re-run the repo's graph check, report one verdict.
Idempotent; inert when commands.migrationGraph is unset. Adds commands.migrationGraph and
paths.migrations to the config schema.

Claude-Session: https://claude.ai/code/session_01T7j4GUt15DJp7G9UK4tMNE
…res a revision

Base head is read from the flat files only; a branch-added nested file is
refused only when it declares a revision.

Claude-Session: https://claude.ai/code/session_01T7j4GUt15DJp7G9UK4tMNE
@allenhutchison

Copy link
Copy Markdown
Collaborator Author

Rebased again, onto main after #80 and #86 merged. The conflicts were text only. validate.yml now runs both the wait-tools and renumber-migration test steps. The README layout tree lists both test scripts and the scripts {wait-for-review,wait-for-checks,renumber-migration}.sh. In the repo-ops README, this PR's section follows the new Wait tools section. One extra commit renames it from "Tools" to "Migration tools" so the two H2s don't read as duplicates. All validate.yml steps pass locally (hooks 190/0, wait tools 73/0, renumber-migration 67/0).

https://claude.ai/code/session_01T7j4GUt15DJp7G9UK4tMNE

@allenhutchison
allenhutchison merged commit 9e4f26d into main Oct 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant