Upgrade components: the argument (text following the upgrade: trigger)
Each token is one of: component:1.2.3 (exact), component:minor (latest patch on current minor), component:latest (latest stable), component:lts (latest LTS), or bare component (latest compatible with everything else).
component can be a library, framework, language runtime, build tool, or path like .github/workflows.
Each component is committed on its own as soon as its gates pass; the branch is pushed once, and a pull request opened where the host allows one — see Phase 2's step 6.5 and step 7.5.
Phase 0 — Specs-repo preflight
Cite ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md and execute its specs-preflight entry point (§3) inline: flush any leftover session artifacts from an earlier run, retry an artifact commit that failed to push, and settle the branch. This runs against $SPECS_PATH only — git -C "$SPECS_PATH", never a cd, so the code repo this run is about to upgrade is untouched (§1 rule 1). Prompt-free and silent when the specs repo is clean and on its default branch. If a guard fires, emit its §5 notice; if it returns specs_git: blocked (§3.3 G0), carry that flag for the whole run — the terminal commit-artifacts step skips on it.
Phase 1 — Compatibility Planning (no files changed)
Inventory — Detect all components and their current versions from build files, runtime version files, and CI YAML. Use ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/upgrade/ecosystems.md. For Java, version declarations span build files, .sdkmanrc, .java-version, .tool-versions, Dockerfiles, and GitHub Actions workflow files — upgrade: java:lts (and any other Java target) updates all of them consistently, never just the build file.
Resolve requested targets — Apply the Version Resolution section below to each requested token.
Delegate planning in parallel — Spawn one planner task per requested component. Use a single agent message for the whole batch.
Use this pattern for each component:
task(
agent_type: "dev-workflows:upgrade-planner",
model: `<detection_model — §2.1 detection chain>`,
description: "Plan component upgrade",
prompt: "## Upgrade Plan Request
repo: [absolute repo path]
component: [component name]
target: [exact | minor | latest | lts | bare]
other_upgrades:
- name: [other requested component]
target: [its target token]
repo_inventory:
[component]: [current version]
model_routing:
classification: [SIMPLE | MODERATE | SIGNIFICANT | HIGH-RISK]
reason: <one-line>
current_model: <the model this orchestrator is running under>
detection_model: <§2.1 detection chain: claude-sonnet-4.6, fallback claude-sonnet-4.5/gpt-5.4> # upgrade-planner, test-baseliner; upgrade-executor (SIMPLE/MODERATE); review-fixer
planning_model: <§2 Opus chain> # risk-planner (SIGNIFICANT/HIGH-RISK; dispatch-pinned to this chain, recorded, no override); upgrade-executor escalates here only if HIGH-RISK
review_model: <§2 Opus chain> # code-review (dispatch-pinned to this chain; recorded, no override)
opus_available: <true if a §2 Opus model resolved, else false>
gate_tests_on_review: <true for SIGNIFICANT/HIGH-RISK, false otherwise>
notes: <any §2 / §2.1 fallback or degradation>"
)
Collect planner results
READY → candidate for execution
NOT_FOUND → warn and skip
CONFLICT → surface conflict_details and ranked alternatives; do not proceed until the conflict is resolved or the component is skipped. Incompatible explicit versions — e.g. upgrade: gradle:9 java:11 requests two explicit versions that won't work together (Gradle 9 requires Java 17+): the planner stops and offers ranked alternatives — the highest Gradle version compatible with Java 11, or upgrading Java to 17 so Gradle 9 becomes compatible
For each READY component, write its planner handoff to a temp file (mktemp -t dw-upgrade-plan-XXXX.md, never inside a repo tree) and record its absolute path as the component's plan_file (it persists into Phase 2); the risk-planner, executor, and resume steps below receive this path instead of the pasted handoff.
Classify each READY component — Load and follow the model-routing policy at ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/model-routing.md, then record: the actual resolved change, related upgrades, and planner findings. Print one classification line per component. When in doubt, escalate to SIGNIFICANT.
Risk plan for SIGNIFICANT / HIGH-RISK components — For every component classified SIGNIFICANT or HIGH-RISK, invoke risk-planner before execution (dispatch-pinned to Opus; recorded as planning_model above, no model: override needed):
task(
agent_type: "dev-workflows:risk-planner",
description: "Plan risky upgrade",
prompt: "Task description: Upgrade [component] from [current] to [target] in this repo.
Classification: [SIGNIFICANT | HIGH-RISK] — reason: [routing trigger]
Upgrade plan: read it from the file at [`plan_file`]
Current state: branch = [git branch], uncommitted = [git status --short summary]
Before writing the plan, grep the repo for import sites and usage patterns of this component to understand blast radius, migration order, test coverage, and rollback."
)
If the planner returns ### Re-classification, surface it and let the user accept the down-classification, override it, or cancel the component.
Confirm the full plan — Present the resolved component list, classifications, related upgrades, and any Opus plans. Do not touch files until approved.
Phase 2 — Execution (after user confirms)
Phase 2 prep (once)
Create feature branch
- Run
git status --porcelain. If dirty, show the diff summary and ask via ask_user whether to stash, proceed anyway, or cancel. On stash, record the resulting stash as stash_ref; on proceed anyway, record the git status --porcelain --untracked-files=all paths as pre_existing_dirty. Steps 6.5 and 7.5 need both (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md §2.2 carve-outs 1–2); a clean tree records null for each.
- Resolve the branch name per
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/branch-naming.md — the repo's own documented convention wins. Read the repo's CONTRIBUTING.md, CONTRIBUTION.md, README.md, DOCUMENTATION-GUIDELINES.md, .github/copilot-instructions.md (+ .github/) for a branch-naming section (§1.1) and fill its segments (§1.2): an identity placeholder from the §2 ladder ($GIT_USER_INITIALS → git config user.initials → inference → the §2.5 prompt), an issue-key segment from the run's Jira key when it has one (else the documented no-issue literal), and the description segment from the slug upgrade-<component>-to-<version> (or upgrade-<first>-and-<N>-more for a batch). Never add an identity segment the pattern does not ask for. Only when no convention is documented (§1.4) build <prefix>/<slug> with the §2 ladder's fallback chore/.
- If HEAD is on a non-default branch with ahead commits, ask whether to branch from current position, branch from default, or cancel.
- Run
git checkout -b <branch-name>. If it exists, append -<7-char-sha>.
Capture baseline tests — Invoke the existing test baseline agent once and reuse the result for the entire batch:
task(
agent_type: "dev-workflows:test-baseliner",
model: `<detection_model — §2.1 detection chain>`,
description: "Capture test baseline",
prompt: "Mode: capture
Project root: [absolute repo path]"
)
Store the returned baseline; do not re-run baseline capture per component.
Per-component loop (sequential, in requested order)
Delegate execution — For each READY plan, invoke the executor agent with the planner handoff and the captured baseline.
task(
agent_type: "dev-workflows:upgrade-executor",
model: `<detection_model — §2.1 detection chain — for SIMPLE/MODERATE; planning_model — §2 Opus chain — only if HIGH-RISK>`,
description: "Execute component upgrade",
prompt: "## Upgrade Execution Request
repo: [absolute repo path]
phase: full
baseline:
passing_count: [captured count]
passing_tests:
- [captured test ids]
model_routing:
classification: [component class]
reason: <one-line>
current_model: <the model this orchestrator is running under>
detection_model: <§2.1 detection chain: claude-sonnet-4.6, fallback claude-sonnet-4.5/gpt-5.4> # upgrade-planner, test-baseliner; upgrade-executor (SIMPLE/MODERATE); review-fixer
planning_model: <§2 Opus chain> # risk-planner (SIGNIFICANT/HIGH-RISK; dispatch-pinned to this chain, recorded, no override); upgrade-executor escalates here only if HIGH-RISK
review_model: <§2 Opus chain> # code-review (dispatch-pinned to this chain; recorded, no override)
opus_available: <true if a §2 Opus model resolved, else false>
gate_tests_on_review: [true for SIGNIFICANT / HIGH-RISK, false otherwise]
notes: <any §2 / §2.1 fallback or degradation>
read the full READY upgrade plan from the file at [`plan_file`]"
)
3a. Handle an upgrade-executor stop. If the executor returns status: BLOCKED, the upgrade plan at plan_file could not be read — an orchestrator bug, not a user choice: report the unreadable path to the user, mark this component BLOCKED in the Step 7 results table, and stop working this component (do not retry with a fresh planning pass). This applies regardless of classification — skip steps 4–6 for this component and continue the per-component loop with the next one.
Review gate for SIGNIFICANT / HIGH-RISK — If the executor returns status: AWAITING_REVIEW, run the Opus code-review gate before any test verification:
- Capture the diff to a temp file: write
git add -N . && git diff to mktemp -t dw-upgrade-diff-XXXX.patch (never inside a repo tree) and record its path as review_diff_file
- Write the executor output to a temp file (
mktemp -t dw-upgrade-claims-XXXX.md, never inside a repo tree) and record its path as claims_file. Invoke code-review using the approved risk plan, the diff (from review_diff_file), and claims_file: [the path] (dispatch-pinned to Opus; recorded as review_model above, no model: override needed)
- Check the review's first line before acting on the verdict. If it is
Diff: unreadable at <path>, the orchestrator's own review_diff_file could not be read — an orchestrator bug, not a user choice: surface the unreadable path to the user and stop working this component, marking it BLOCKED in the Step 7 results table. Do NOT triage the finding and do NOT dispatch review-fixer: the finding names a capture failure no fixer can act on, and running the cycle would spend a fix dispatch and a re-review to arrive back here.
- Triage sub-step (before any fixer dispatch): follow
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/finding-triage.md. For each finding, verify its claimed consequence at the location it names; keep or dismiss; record every dismissal with a reason that disposes of that finding's own claim. Hand the fixer survivors only, and carry the dismissal list into this run's report.
- If review returns
BLOCK or PASS WITH RECOMMENDATIONS, invoke review-fixer with model: <detection_model — §2.1 detection chain> for the surviving BLOCKER and MAJOR findings
- Handle a
review-fixer stop. If its Stop condition flag is NEEDS HUMAN, do NOT re-run the review: surface the deferred BLOCKER(s) to the user with the reason review-fixer gave, mark this component BLOCKED in the Step 7 results table, and stop working this component — skip steps 5–6 and continue the per-component loop with the next one. Only when the flag is CLEAR do you overwrite review_diff_file with a fresh git add -N . && git diff and re-run the Opus review once against that refreshed path — so the re-review reads the post-fix diff, not the stale pre-fix capture
- If the second verdict is still
BLOCK, stop and escalate; do not continue to tests
Resume verify step after review — Re-invoke upgrade-executor with phase: verify-resume, the original READY plan (from plan_file), and the same baseline block captured in Phase 2 prep. If the resumed agent returns status: BLOCKED, the re-supplied file path could not be read: report the named path to the user and stop this component. Do NOT retry, and do NOT reconstruct the artifact — a resume that re-derives its own input is the failure ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/context-management.md's read-failure contract exists to prevent.
If the executor returns status: TEST_REGRESSION, follow "Handling Test Failures" below, then re-invoke upgrade-executor with phase: regression-resume + the chosen regression_decision, the original READY plan (from plan_file), and the same baseline block. If the resumed agent returns status: BLOCKED, the re-supplied file path could not be read: report the named path to the user and stop this component. Do NOT retry, and do NOT reconstruct the artifact — a resume that re-derives its own input is the failure ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/context-management.md's read-failure contract exists to prevent.
6.5. Commit this component (in-loop, prompt-free) — Once this component's own gates have settled — its review verdict is non-BLOCK or the user chose to keep it, and its verify step has returned — commit it before moving to the next one. Cite ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md and execute §2.1–§2.3 only (the split-call form of §2.12 — the gate runs every time): stage per §2.2 honouring pre_existing_dirty, and commit per §2.3 with a subject derived from the repo's own git log — with a Jira key <KEY> upgrade <component> to <version>, otherwise matching whatever convention that log shows. Do not push here and do not ask §2.4's choice; step 7.5 owns both.
Committing per component is the point of putting this inside the loop: a batch that dies on component three still has one and two committed, each with its own message, on a branch that bisects.
Every loop-exit path routes here first. Three exits above skip the remaining steps for a component — step 3a (BLOCKED, an unreadable plan_file), the review-fixer NEEDS HUMAN stop, and a second verdict still BLOCK. The last two leave files written by the executor and possibly by review-fixer; they run 6.5 before moving on, so that work is committed under its own component's message instead of being swept into the next component's commit by that component's add -A. Step 3a is different: it returns before the executor touches anything, so 6.5 finds nothing staged, makes no commit, and — because that component never reached the repository — it does not set clean_finish: false (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md §2.9's third bullet). A component whose executor simply changed nothing takes the same no-commit path.
A component that reached the repository and ended BLOCKED, or whose review stayed BLOCK, is committed — unreviewed work that exists is recoverable, work that was never committed is not — and it sets clean_finish: false for step 7.5.
"Stop and escalate" on a persisting BLOCK stops the component, not the run. The loop continues with the next component; step 7.5 still runs at the end. A reading that stops the whole run would leave every earlier component committed but never pushed.
- Collect results — Accumulate one summary row per component. Preserve the classification, review verdict, related upgrades applied, any regression notes, and this component's commit sha (or "no changes").
7.5. Code-repo handoff (push + PR, once for the batch) — After the loop, cite ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md and execute the full finish-code-branch entry point (§2) inline. Step 6.5 already committed every component, so §2.2 takes its nothing staged path and the call continues into §2.4's consent choice and §2.5–§2.6 — the branch carries commits to push (§2.12).
Pass the §2.11 inputs: repo and branch from Phase 2 prep step 1; pre_existing_dirty and stash_ref as recorded there; title = <KEY> upgrade <component> to <version> for a single component, or <KEY> upgrade <first> and <N> more for a batch (dropping the key in a run with none); body_facts = the Upgrade Summary rows, each component's classification and review verdict, and the test result against the Phase 2 prep baseline; clean_finish: false when any component ended BLOCKED or with a review still BLOCK or with kept regressions, true otherwise. Emit the §3.1 Code repo: outcome line with the Step 7 results table.
- Post-batch maintenance — After all components finish, invoke
impl-maintenance with a compact session handoff summarising what was upgraded, key failures or workarounds, and the overall result. Always pass Command run: upgrade: in that handoff — omitting it makes impl-maintenance default to implement:, mislabeling the run.
Context hygiene. This was a large run — consider /compact to free context before your next task (per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md §3 — non-pipeline, so /compact only; guidance only).
Persist plugin feedback (automatic) — After impl-maintenance returns, project its plugin-facing slice into the specs repo by citing ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/feedback-emission.md and calling its emit-auto entry point (§6). Pass the Lessons Learned report, command: upgrade:, the run's jira_key (or null) and source, and plugin_version (read from ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/.plugin/plugin.json). emit-auto renders only the report's Command workflow improvements, New agents / skills, and plugin Reference docs sections plus the Key observations that triggered them (§4 plugin-facing predicate) — never target-project copilot-instructions.md/hook advice — as origin: auto entries, dedupes by stable id (§3), resolves the target via the §2 specs-first ladder, and writes silently. List the persisted path (or "no plugin-facing signal — nothing persisted") after the lessons-learned report. ADDITIVE — this step NEVER fails the run, NEVER commits (still true — the assertion is scoped to this step, which only writes the feedback file; those writes are committed by the separate terminal commit-artifacts step, per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md §4), and NEVER writes into the code repo or the current working directory.
Commit session artifacts (terminal) — Cite ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md and execute its commit-artifacts entry point (§4) inline — the LAST action of the run. It stages ONLY the §2.1 bounded artifact paths inside $SPECS_PATH, commits <KEY> Add dev-workflows session artifacts (upgrade:) — or NOISSUE … when the run resolved no Jira key — and pushes per §4 step 5. It NEVER touches the code repo this run just upgraded: that repo's per-component commits, its push, and its pull request were steps 6.5 and 7.5, through a different reference and against a different remote. It NEVER force-pushes, NEVER fails the run, and skips entirely when the run carries specs_git: blocked (§3.3 G0), re-emitting that notice. Print its §6 outcome line as the run's last output, prefixed Specs repo:, with any guard notice repeated in full. No resume.md is written for upgrade: (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md §1 skip list).
Version Resolution
| Token |
Resolution |
component:1.2.3 |
Use exact version; verify it exists; run compatibility check; surface conflicts (never silently downgrade) |
component:minor |
Latest stable patch within current MAJOR.MINOR.* |
component:latest |
Highest stable release; run compatibility check |
component:lts |
Consult official LTS source (see lts-sources.md); if lookup fails, ask the user |
bare component |
Highest version compatible with all other repo components; report conflict if none found |
Output
## Upgrade Summary
| Component | Before | After | Class | Review | Status | Notes |
|------------|--------|--------|-------------|--------|---------|-----------------------------|
| springboot | 3.1.4 | 3.3.11 | HIGH-RISK | PASS | OK | Also upgraded hibernate 6.4 |
| java | 17 | 21 | SIGNIFICANT | PASS W/RECS | OK | Updated 2 test files |
| commons-text | 1.10 | 1.11 | MODERATE | N/A | OK | |
| redis | - | - | - | - | SKIPPED | Not found in project |
Tests: 142 passed, 0 regressions (baseline: 142 passing)
Append a ### Review triage section with one line per SIGNIFICANT/HIGH-RISK component that went through Opus review: - Review triage: [N findings reviewed, M survived] — dismissals: [one line per dismissal, finding — reason; or "none"] — or "N/A (SIMPLE / MODERATE, no Opus review)" for components that never reached review.
Include the impl-maintenance lessons-learned report after the summary table.
Handling Test Failures
upgrade-executor cannot prompt the user directly — sub-agents dispatched via the task tool
run in a separate context and have no access to interactive tools, even when one is listed in
their tools:. When it returns status: TEST_REGRESSION (previously-green tests now failing,
not auto-fixable), the orchestrator (this skill, running in the interactive session) handles
the decision:
Invariants (always enforced)
- ALWAYS
emit-block (per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/feedback-emission.md) before escalating a halt caused by a plugin / skill / command / reference gap (a capability the run needed but the plugin lacked) — so a run abandoned at the block still records it. NEVER for a work-quality review BLOCK or an environment / user halt (repo-missing, dirty-tree, jira-not-found, cancellation)
- NEVER skip per-component classification after planning
- NEVER use Opus for a
MODERATE component unless the user explicitly asks for it
- NEVER run tests for a
SIGNIFICANT / HIGH-RISK component before the Opus review returns a non-BLOCK verdict
- NEVER modify files during Phase 1
- NEVER touch files before the upgrade branch exists
- ALWAYS run
specs-preflight at Phase 0 and commit-artifacts as the run's last action (per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md) — bounded to $SPECS_PATH's artifact paths (§2.1) and to plugin-created branches (§2.2), always git -C "$SPECS_PATH" and never a cd (§1 rule 1), never force-pushing, and never failing the run
- ALWAYS capture the baseline once before executing any component
- ALWAYS pass the same baseline block to
upgrade-executor on phase: verify-resume
- ALWAYS include classification in the final summary table
- ALWAYS commit each component in step 6.5 as its gates settle, and run the full
finish-code-branch once in step 7.5 (per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md §2.12's split form) — the commits are prompt-free (§1 rule 5), the push and pull request sit behind §2.4's choice, and a run that ends with the upgrade uncommitted is a defect
- NEVER skip step 6.5 for a component that ended
BLOCKED or with a review still BLOCK — it is committed like any other and sets clean_finish: false, which makes step 7.5's pull request a draft carrying the DO-NOT-MERGE banner (§2.9)
- NEVER push or ask for the pull request inside the per-component loop — one push, one pull request, one
Code repo: line per run
- After the run, suggest
/compact (a big non-pipeline run) per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md §3 — compact-only, no clear/resume pointer; guidance only, never auto-run.
1---2name: upgrade3description: Component upgrade workflow. Upgrades libraries, frameworks, runtimes, or build tools to specified or latest versions. Plans with Opus for complex upgrades, runs code review, and verifies with tests. Activated when the user prompt starts with "upgrade:".4---56Upgrade components: the argument (text following the `upgrade:` trigger)78Each token is one of: `component:1.2.3` (exact), `component:minor` (latest patch on current minor), `component:latest` (latest stable), `component:lts` (latest LTS), or bare `component` (latest compatible with everything else).910`component` can be a library, framework, language runtime, build tool, or path like `.github/workflows`.1112Each component is committed on its own as soon as its gates pass; the branch is pushed once, and a pull request opened where the host allows one — see Phase 2's step 6.5 and step 7.5.1314---1516## Phase 0 — Specs-repo preflight1718Cite `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md` and execute its `specs-preflight` entry point (§3) inline: flush any leftover session artifacts from an earlier run, retry an artifact commit that failed to push, and settle the branch. This runs against `$SPECS_PATH` only — `git -C "$SPECS_PATH"`, never a `cd`, so the code repo this run is about to upgrade is untouched (§1 rule 1). Prompt-free and silent when the specs repo is clean and on its default branch. If a guard fires, emit its §5 notice; if it returns `specs_git: blocked` (§3.3 G0), carry that flag for the whole run — the terminal `commit-artifacts` step skips on it.1920---2122## Phase 1 — Compatibility Planning (no files changed)23241. **Inventory** — Detect all components and their current versions from build files, runtime version files, and CI YAML. Use `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/upgrade/ecosystems.md`. For Java, version declarations span build files, `.sdkmanrc`, `.java-version`, `.tool-versions`, Dockerfiles, and GitHub Actions workflow files — `upgrade: java:lts` (and any other Java target) updates all of them consistently, never just the build file.25262. **Resolve requested targets** — Apply the `Version Resolution` section below to each requested token.27283. **Delegate planning in parallel** — Spawn one planner task per requested component. Use a single agent message for the whole batch.2930 Use this pattern for each component:3132 ```33 task(34 agent_type: "dev-workflows:upgrade-planner",35 model: `<detection_model — §2.1 detection chain>`,36 description: "Plan component upgrade",37 prompt: "## Upgrade Plan Request38 repo: [absolute repo path]39 component: [component name]40 target: [exact | minor | latest | lts | bare]41 other_upgrades:42 - name: [other requested component]43 target: [its target token]44 repo_inventory:45 [component]: [current version]46 model_routing:47 classification: [SIMPLE | MODERATE | SIGNIFICANT | HIGH-RISK]48 reason: <one-line>49 current_model: <the model this orchestrator is running under>50 detection_model: <§2.1 detection chain: claude-sonnet-4.6, fallback claude-sonnet-4.5/gpt-5.4> # upgrade-planner, test-baseliner; upgrade-executor (SIMPLE/MODERATE); review-fixer51 planning_model: <§2 Opus chain> # risk-planner (SIGNIFICANT/HIGH-RISK; dispatch-pinned to this chain, recorded, no override); upgrade-executor escalates here only if HIGH-RISK52 review_model: <§2 Opus chain> # code-review (dispatch-pinned to this chain; recorded, no override)53 opus_available: <true if a §2 Opus model resolved, else false>54 gate_tests_on_review: <true for SIGNIFICANT/HIGH-RISK, false otherwise>55 notes: <any §2 / §2.1 fallback or degradation>"56 )57 ```58594. **Collect planner results**60 - `READY` → candidate for execution61 - `NOT_FOUND` → warn and skip62 - `CONFLICT` → surface `conflict_details` and ranked `alternatives`; do not proceed until the conflict is resolved or the component is skipped. **Incompatible explicit versions** — e.g. `upgrade: gradle:9 java:11` requests two explicit versions that won't work together (Gradle 9 requires Java 17+): the planner stops and offers ranked alternatives — the highest Gradle version compatible with Java 11, or upgrading Java to 17 so Gradle 9 becomes compatible6364 For each `READY` component, write its planner handoff to a temp file (`mktemp -t dw-upgrade-plan-XXXX.md`, never inside a repo tree) and record its absolute path as the component's `plan_file` (it persists into Phase 2); the risk-planner, executor, and resume steps below receive this path instead of the pasted handoff.65665. **Classify each READY component** — Load and follow the model-routing policy at `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/model-routing.md`, then record: the actual resolved change, related upgrades, and planner findings. Print one classification line per component. When in doubt, escalate to `SIGNIFICANT`.67686. **Risk plan for SIGNIFICANT / HIGH-RISK components** — For every component classified `SIGNIFICANT` or `HIGH-RISK`, invoke `risk-planner` before execution (dispatch-pinned to Opus; recorded as `planning_model` above, no `model:` override needed):6970 ```71 task(72 agent_type: "dev-workflows:risk-planner",73 description: "Plan risky upgrade",74 prompt: "Task description: Upgrade [component] from [current] to [target] in this repo.75 Classification: [SIGNIFICANT | HIGH-RISK] — reason: [routing trigger]76 Upgrade plan: read it from the file at [`plan_file`]77 Current state: branch = [git branch], uncommitted = [git status --short summary]7879 Before writing the plan, grep the repo for import sites and usage patterns of this component to understand blast radius, migration order, test coverage, and rollback."80 )81 ```8283 If the planner returns `### Re-classification`, surface it and let the user accept the down-classification, override it, or cancel the component.84857. **Confirm the full plan** — Present the resolved component list, classifications, related upgrades, and any Opus plans. Do not touch files until approved.8687---8889## Phase 2 — Execution (after user confirms)9091### Phase 2 prep (once)92931. **Create feature branch**94 - Run `git status --porcelain`. If dirty, show the diff summary and ask via `ask_user` whether to stash, proceed anyway, or cancel. On **stash**, record the resulting stash as `stash_ref`; on **proceed anyway**, record the `git status --porcelain --untracked-files=all` paths as `pre_existing_dirty`. Steps 6.5 and 7.5 need both (`~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md` §2.2 carve-outs 1–2); a clean tree records `null` for each.95 - Resolve the branch name per `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/branch-naming.md` — **the repo's own documented convention wins**. Read the repo's `CONTRIBUTING.md`, `CONTRIBUTION.md`, `README.md`, `DOCUMENTATION-GUIDELINES.md`, `.github/copilot-instructions.md` (+ `.github/`) for a branch-naming section (§1.1) and fill its segments (§1.2): an **identity** placeholder from the §2 ladder (`$GIT_USER_INITIALS` → `git config user.initials` → inference → the §2.5 prompt), an **issue-key** segment from the run's Jira key when it has one (else the documented no-issue literal), and the **description** segment from the slug `upgrade-<component>-to-<version>` (or `upgrade-<first>-and-<N>-more` for a batch). Never add an identity segment the pattern does not ask for. Only when no convention is documented (§1.4) build `<prefix>/<slug>` with the §2 ladder's fallback `chore/`.96 - If HEAD is on a non-default branch with ahead commits, ask whether to branch from current position, branch from default, or cancel.97 - Run `git checkout -b <branch-name>`. If it exists, append `-<7-char-sha>`.98992. **Capture baseline tests** — Invoke the existing test baseline agent once and reuse the result for the entire batch:100101 ```102 task(103 agent_type: "dev-workflows:test-baseliner",104 model: `<detection_model — §2.1 detection chain>`,105 description: "Capture test baseline",106 prompt: "Mode: capture107 Project root: [absolute repo path]"108 )109 ```110111 Store the returned baseline; do not re-run baseline capture per component.112113### Per-component loop (sequential, in requested order)1141153. **Delegate execution** — For each `READY` plan, invoke the executor agent with the planner handoff and the captured baseline.116117 ```118 task(119 agent_type: "dev-workflows:upgrade-executor",120 model: `<detection_model — §2.1 detection chain — for SIMPLE/MODERATE; planning_model — §2 Opus chain — only if HIGH-RISK>`,121 description: "Execute component upgrade",122 prompt: "## Upgrade Execution Request123 repo: [absolute repo path]124 phase: full125 baseline:126 passing_count: [captured count]127 passing_tests:128 - [captured test ids]129 model_routing:130 classification: [component class]131 reason: <one-line>132 current_model: <the model this orchestrator is running under>133 detection_model: <§2.1 detection chain: claude-sonnet-4.6, fallback claude-sonnet-4.5/gpt-5.4> # upgrade-planner, test-baseliner; upgrade-executor (SIMPLE/MODERATE); review-fixer134 planning_model: <§2 Opus chain> # risk-planner (SIGNIFICANT/HIGH-RISK; dispatch-pinned to this chain, recorded, no override); upgrade-executor escalates here only if HIGH-RISK135 review_model: <§2 Opus chain> # code-review (dispatch-pinned to this chain; recorded, no override)136 opus_available: <true if a §2 Opus model resolved, else false>137 gate_tests_on_review: [true for SIGNIFICANT / HIGH-RISK, false otherwise]138 notes: <any §2 / §2.1 fallback or degradation>139140 read the full READY upgrade plan from the file at [`plan_file`]"141 )142 ```1431443a. **Handle an `upgrade-executor` stop.** If the executor returns `status: BLOCKED`, the upgrade plan at `plan_file` could not be read — an orchestrator bug, not a user choice: report the unreadable path to the user, mark this component `BLOCKED` in the Step 7 results table, and stop working this component (do not retry with a fresh planning pass). This applies regardless of classification — skip steps 4–6 for this component and continue the per-component loop with the next one.1451464. **Review gate for SIGNIFICANT / HIGH-RISK** — If the executor returns `status: AWAITING_REVIEW`, run the Opus code-review gate before any test verification:147 - Capture the diff to a temp file: write `git add -N . && git diff` to `mktemp -t dw-upgrade-diff-XXXX.patch` (never inside a repo tree) and record its path as `review_diff_file`148 - Write the executor output to a temp file (`mktemp -t dw-upgrade-claims-XXXX.md`, never inside a repo tree) and record its path as `claims_file`. Invoke `code-review` using the approved risk plan, the diff (from `review_diff_file`), and `claims_file: [the path]` (dispatch-pinned to Opus; recorded as `review_model` above, no `model:` override needed)149 - **Check the review's first line before acting on the verdict.** If it is `Diff: unreadable at <path>`, the orchestrator's own `review_diff_file` could not be read — an orchestrator bug, not a user choice: surface the unreadable path to the user and stop working this component, marking it `BLOCKED` in the Step 7 results table. Do NOT triage the finding and do NOT dispatch `review-fixer`: the finding names a capture failure no fixer can act on, and running the cycle would spend a fix dispatch and a re-review to arrive back here.150 - **Triage sub-step** (before any fixer dispatch): follow `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/finding-triage.md`. For each finding, verify its claimed consequence at the location it names; keep or dismiss; record every dismissal with a reason that disposes of that finding's own claim. Hand the fixer **survivors only**, and carry the dismissal list into this run's report.151 - If review returns `BLOCK` or `PASS WITH RECOMMENDATIONS`, invoke `review-fixer` with model: `<detection_model — §2.1 detection chain>` for the surviving `BLOCKER` and `MAJOR` findings152 - **Handle a `review-fixer` stop.** If its `Stop condition flag` is `NEEDS HUMAN`, do NOT re-run the review: surface the deferred BLOCKER(s) to the user with the reason `review-fixer` gave, mark this component `BLOCKED` in the Step 7 results table, and stop working this component — skip steps 5–6 and continue the per-component loop with the next one. Only when the flag is `CLEAR` do you **overwrite `review_diff_file`** with a fresh `git add -N . && git diff` and re-run the Opus review once against that refreshed path — so the re-review reads the post-fix diff, not the stale pre-fix capture153 - If the second verdict is still `BLOCK`, stop and escalate; do not continue to tests1541555. **Resume verify step after review** — Re-invoke `upgrade-executor` with `phase: verify-resume`, the original `READY` plan (from `plan_file`), and the same baseline block captured in Phase 2 prep. If the resumed agent returns `status: BLOCKED`, the re-supplied file path could not be read: report the named path to the user and stop this component. Do NOT retry, and do NOT reconstruct the artifact — a resume that re-derives its own input is the failure `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/context-management.md`'s read-failure contract exists to prevent.1561576. **If the executor returns `status: TEST_REGRESSION`**, follow "Handling Test Failures" below, then re-invoke `upgrade-executor` with `phase: regression-resume` + the chosen `regression_decision`, the original `READY` plan (from `plan_file`), and the same baseline block. If the resumed agent returns `status: BLOCKED`, the re-supplied file path could not be read: report the named path to the user and stop this component. Do NOT retry, and do NOT reconstruct the artifact — a resume that re-derives its own input is the failure `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/context-management.md`'s read-failure contract exists to prevent.1581596.5. **Commit this component (in-loop, prompt-free)** — Once this component's own gates have settled — its review verdict is non-`BLOCK` or the user chose to keep it, and its verify step has returned — commit it before moving to the next one. Cite `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md` and execute **§2.1–§2.3 only** (the split-call form of §2.12 — the gate runs every time): stage per §2.2 honouring `pre_existing_dirty`, and commit per §2.3 with a subject derived from the repo's own `git log` — with a Jira key `<KEY> upgrade <component> to <version>`, otherwise matching whatever convention that log shows. Do **not** push here and do **not** ask §2.4's choice; step 7.5 owns both.160161 Committing per component is the point of putting this inside the loop: a batch that dies on component three still has one and two committed, each with its own message, on a branch that bisects.162163 **Every loop-exit path routes here first.** Three exits above skip the remaining steps for a component — step 3a (`BLOCKED`, an unreadable `plan_file`), the `review-fixer` `NEEDS HUMAN` stop, and a second verdict still `BLOCK`. The last two leave files written by the executor and possibly by `review-fixer`; they run 6.5 before moving on, so that work is committed under its own component's message instead of being swept into the next component's commit by that component's `add -A`. Step 3a is different: it returns before the executor touches anything, so 6.5 finds nothing staged, makes no commit, and — because that component never reached the repository — it does **not** set `clean_finish: false` (`~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md` §2.9's third bullet). A component whose executor simply changed nothing takes the same no-commit path.164165 A component that reached the repository and ended `BLOCKED`, or whose review stayed `BLOCK`, **is** committed — unreviewed work that exists is recoverable, work that was never committed is not — and it sets `clean_finish: false` for step 7.5.166167 **"Stop and escalate" on a persisting `BLOCK` stops the component, not the run.** The loop continues with the next component; step 7.5 still runs at the end. A reading that stops the whole run would leave every earlier component committed but never pushed.1681697. **Collect results** — Accumulate one summary row per component. Preserve the classification, review verdict, related upgrades applied, any regression notes, and this component's commit sha (or "no changes").1701717.5. **Code-repo handoff (push + PR, once for the batch)** — After the loop, cite `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md` and execute the full `finish-code-branch` entry point (§2) inline. Step 6.5 already committed every component, so §2.2 takes its `nothing staged` path and the call continues into §2.4's consent choice and §2.5–§2.6 — the branch carries commits to push (§2.12).172173 Pass the §2.11 inputs: `repo` and `branch` from Phase 2 prep step 1; `pre_existing_dirty` and `stash_ref` as recorded there; `title` = `<KEY> upgrade <component> to <version>` for a single component, or `<KEY> upgrade <first> and <N> more` for a batch (dropping the key in a run with none); `body_facts` = the Upgrade Summary rows, each component's classification and review verdict, and the test result against the Phase 2 prep baseline; `clean_finish: false` when any component ended `BLOCKED` or with a review still `BLOCK` or with kept regressions, `true` otherwise. Emit the §3.1 `Code repo:` outcome line with the Step 7 results table.1741758. **Post-batch maintenance** — After all components finish, invoke `impl-maintenance` with a compact session handoff summarising what was upgraded, key failures or workarounds, and the overall result. **Always pass `Command run: upgrade:`** in that handoff — omitting it makes `impl-maintenance` default to `implement:`, mislabeling the run.176177**Context hygiene.** This was a large run — consider **`/compact`** to free context before your next task (per `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md` §3 — non-pipeline, so `/compact` only; guidance only).1781799. **Persist plugin feedback (automatic)** — After `impl-maintenance` returns, project its plugin-facing slice into the specs repo by citing `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/feedback-emission.md` and calling its `emit-auto` entry point (§6). Pass the Lessons Learned report, `command: upgrade:`, the run's `jira_key` (or `null`) and `source`, and `plugin_version` (read from `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/.plugin/plugin.json`). `emit-auto` renders only the report's **Command workflow improvements**, **New agents / skills**, and plugin **Reference docs** sections plus the **Key observations** that triggered them (§4 plugin-facing predicate) — never target-project `copilot-instructions.md`/hook advice — as `origin: auto` entries, dedupes by stable `id` (§3), resolves the target via the §2 specs-first ladder, and writes silently. List the persisted path (or "no plugin-facing signal — nothing persisted") after the lessons-learned report. ADDITIVE — this step NEVER fails the run, NEVER commits (still true — the assertion is scoped to *this step*, which only writes the feedback file; those writes are committed by the separate terminal `commit-artifacts` step, per `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md` §4), and NEVER writes into the code repo or the current working directory.18018110. **Commit session artifacts (terminal)** — Cite `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md` and execute its `commit-artifacts` entry point (§4) inline — the LAST action of the run. It stages ONLY the §2.1 bounded artifact paths inside `$SPECS_PATH`, commits `<KEY> Add dev-workflows session artifacts (upgrade:)` — or `NOISSUE …` when the run resolved no Jira key — and pushes per §4 step 5. It NEVER touches the code repo this run just upgraded: that repo's per-component commits, its push, and its pull request were steps 6.5 and 7.5, through a different reference and against a different remote. It NEVER force-pushes, NEVER fails the run, and skips entirely when the run carries `specs_git: blocked` (§3.3 G0), re-emitting that notice. Print its §6 outcome line as the run's last output, prefixed `Specs repo:`, with any guard notice repeated in full. No `resume.md` is written for `upgrade:` (`~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md` §1 skip list).182183---184185## Version Resolution186187| Token | Resolution |188|---|---|189| `component:1.2.3` | Use exact version; verify it exists; run compatibility check; surface conflicts (never silently downgrade) |190| `component:minor` | Latest stable patch within current `MAJOR.MINOR.*` |191| `component:latest` | Highest stable release; run compatibility check |192| `component:lts` | Consult official LTS source (see `lts-sources.md`); if lookup fails, ask the user |193| bare `component` | Highest version compatible with all other repo components; report conflict if none found |194195---196197## Output198199```200## Upgrade Summary201202| Component | Before | After | Class | Review | Status | Notes |203|------------|--------|--------|-------------|--------|---------|-----------------------------|204| springboot | 3.1.4 | 3.3.11 | HIGH-RISK | PASS | OK | Also upgraded hibernate 6.4 |205| java | 17 | 21 | SIGNIFICANT | PASS W/RECS | OK | Updated 2 test files |206| commons-text | 1.10 | 1.11 | MODERATE | N/A | OK | |207| redis | - | - | - | - | SKIPPED | Not found in project |208209Tests: 142 passed, 0 regressions (baseline: 142 passing)210```211212Append a `### Review triage` section with one line per SIGNIFICANT/HIGH-RISK component that went through Opus review: - **Review triage:** [N findings reviewed, M survived] — dismissals: [one line per dismissal, `finding — reason`; or "none"] — or "N/A (SIMPLE / MODERATE, no Opus review)" for components that never reached review.213214Include the `impl-maintenance` lessons-learned report after the summary table.215216---217218## Handling Test Failures219220`upgrade-executor` cannot prompt the user directly — sub-agents dispatched via the `task` tool221run in a separate context and have no access to interactive tools, even when one is listed in222their `tools:`. When it returns `status: TEST_REGRESSION` (previously-green tests now failing,223not auto-fixable), the **orchestrator** (this skill, running in the interactive session) handles224the decision:225226- Present the failing tests clearly (from the executor's `failing_tests` / `diagnosis`).227- Ask via `ask_user`:228 ```229 choices: ["Keep the upgrade and leave the failing tests for you to fix", "Revert this upgrade and skip it", "Investigate further before deciding"]230 ```231- **"Investigate further"** → show more detail (the diff, full failure output) and re-ask232 the same choices — this loops here at the orchestrator until the user picks keep or revert.233- Map the final choice to `regression_decision: keep-anyway | revert` and re-invoke234 `upgrade-executor` with `phase: regression-resume` (see Phase 2 step 6).235236---237238## Invariants (always enforced)239240- ALWAYS `emit-block` (per `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/feedback-emission.md`) before escalating a halt caused by a **plugin / skill / command / reference gap** (a capability the run needed but the plugin lacked) — so a run abandoned at the block still records it. NEVER for a work-quality review BLOCK or an environment / user halt (repo-missing, dirty-tree, jira-not-found, cancellation)241- NEVER skip per-component classification after planning242- NEVER use Opus for a `MODERATE` component unless the user explicitly asks for it243- NEVER run tests for a `SIGNIFICANT` / `HIGH-RISK` component before the Opus review returns a non-BLOCK verdict244- NEVER modify files during Phase 1245- NEVER touch files before the upgrade branch exists246- ALWAYS run `specs-preflight` at Phase 0 and `commit-artifacts` as the run's last action (per `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md`) — bounded to `$SPECS_PATH`'s artifact paths (§2.1) and to plugin-created branches (§2.2), always `git -C "$SPECS_PATH"` and never a `cd` (§1 rule 1), never force-pushing, and never failing the run247- ALWAYS capture the baseline once before executing any component248- ALWAYS pass the same baseline block to `upgrade-executor` on `phase: verify-resume`249- ALWAYS include classification in the final summary table250- ALWAYS commit each component in step 6.5 as its gates settle, and run the full `finish-code-branch` once in step 7.5 (per `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md` §2.12's split form) — the commits are prompt-free (§1 rule 5), the push and pull request sit behind §2.4's choice, and a run that ends with the upgrade uncommitted is a defect251- NEVER skip step 6.5 for a component that ended `BLOCKED` or with a review still `BLOCK` — it is committed like any other and sets `clean_finish: false`, which makes step 7.5's pull request a draft carrying the DO-NOT-MERGE banner (§2.9)252- NEVER push or ask for the pull request inside the per-component loop — one push, one pull request, one `Code repo:` line per run253- After the run, suggest **`/compact`** (a big non-pipeline run) per `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md` §3 — compact-only, no clear/resume pointer; guidance only, never auto-run.