Fix security vulnerabilities: the argument (text following the vuln: trigger)
Each argument token is either JIRA-ID:CVE-ID (e.g. MGD-2423:CVE-2023-46604) or a bare CVE-ID (e.g. CVE-2023-46604). Parse and filter each token, research all CVEs first, then fix them one at a time.
Step 0 — Classify & Route (mandatory)
Load and follow the model-routing policy at ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/model-routing.md, then classify per CVE, based on the size of the required repository change — not the CVE category alone.
Default heuristics:
| Required fix (from research output) | Classification |
|---|---|
| Patch or same-major minor bump, no source-code changes expected | MODERATE |
| Major version bump, or code changes required to adopt the new version | SIGNIFICANT |
| Major bump of a security-critical library, or code changes in auth/session/token/permission/payment/audit paths | HIGH-RISK |
Because the required fix is not known up front, start with a provisional MODERATE routing block for research, then finalize the classification from the research report before fix application begins.
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 branch and fix 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.
Step 1 — Prepare
- Parse — Extract Jira ID (optional) and CVE ID from each token.
- Determine NOJIRA placeholder — Scan recent branch names and commit history for
NOJIRA/NO-JIRA; use the project convention when a Jira ID is missing. - Filter — Skip non-CVE IDs (
CWE-*, OWASP patterns) with a warning. - Snapshot repo context — Note the repo path and, when obvious, the primary ecosystem so the research agent can disambiguate detection.
- Resolve the branch name per CVE — Apply the "Git Workflow → Branch naming" section below now, once per CVE token, and record each result as that CVE's
branch. This is the only place a branch name is produced:vuln-fixercreates the branch it is handed and never derives one, and Step 3.9 pushes the same value. A run that reaches the fixer without abranchin its prompt is a defect — the agent would invent a name, the orchestrator would push a different one, and §2.1 check 4 would fail the gate on the mismatch.
Step 2 — Research (parallel)
Invoke one research task per valid CVE. Use a single agent message for the batch.
task(
agent_type: "dev-workflows:vuln-research",
model: `<detection_model — §2.1 detection chain>`,
description: "Research CVE",
prompt: "## Vuln Research Request
repo: [absolute repo path]
cves:
- id: [CVE-ID]
jira: [optional Jira key]
ecosystem_hint: [optional]
model_routing:
classification: MODERATE
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> # vuln-research; vuln-fixer (SIMPLE/MODERATE); review-fixer
planning_model: <§2 Opus chain> # vuln-fixer 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: false
notes: <any §2 / §2.1 fallback or degradation>"
)
Collect all reports:
READY→ candidate for fixingNOT_IN_REPO→ notify and skipLOOKUP_FAILED→ warn and offer retry or skipSKIP_NON_CVE→ already filtered; no further action
Finalize the per-CVE classification from the research output. If the finalized class is HIGH-RISK, re-run vuln-research on Opus for a confirmation pass. If it is SIGNIFICANT, re-run on Opus when the major bump or breaking-change surface is non-trivial.
Step 3 — Fix (sequential)
Process READY CVEs one at a time to avoid conflicting edits to the same dependency files.
Record the tree state once, before anything is applied. On the first CVE, run git -C "<repo>" status --porcelain --untracked-files=all and record the result as pre_existing_dirty; carry it unchanged through every CVE in the run. vuln: never stashes, so stash_ref is always null. This capture is what lets Step 3.9 keep a bystander's work out of the commit (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md §2.2 carve-out 1) — vuln: offers no dirty-tree prompt, so the capture is the whole safeguard and must happen before the first edit.
Start each CVE from the base branch, not from the previous CVE's. After the capture, resolve the base per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md §2.8 and run git -C "<repo>" switch <base> when HEAD is not already there. Every CVE gets its own branch and its own pull request, so a CVE that branches off its predecessor ships that predecessor's fix inside its own diff, its own review, and its own PR.
Three rules make that switch safe:
- Confirm before leaving a branch the user chose. On the first CVE, if HEAD is already on a non-default branch, do not switch silently — the user may be deliberately working there. Ask:
choices: ["Switch to <base> and branch each CVE from it (Recommended)", "Branch each CVE from <current> instead", "Cancel"]. On later CVEs the branch HEAD sits on is one this run created, so switch without asking. - A failed switch stops the run, it does not proceed.
git switchaborts when a tracked file differs between the two branches. Report the abort and the paths git named, and stop — continuing would branch this CVE off whatever HEAD happens to be, which is the contamination this rule exists to prevent. - Verify the tree before the next CVE, rather than trusting the previous CVE's status. Re-run the porcelain command; anything present that is not in
pre_existing_dirtyis residue the previous CVE left behind (a partial revert —BUILD_FAILEDreverts the files the research report named, which for a lockfile ecosystem is not all of them). Surface it and stop rather than carrying it onto the next CVE's branch.
For each READY CVE, before invoking the fixer, write its research report to a temp file (mktemp -t dw-vuln-research-XXXX.md, never inside a repo tree) and record its absolute path as research_file; the fixer, code-review, and resume steps below receive this path instead of the pasted report.
SIMPLE / MODERATE path
Invoke vuln-fixer with baseline_tests: run-fresh:
task(
agent_type: "dev-workflows:vuln-fixer",
model: `<detection_model — §2.1 detection chain>`,
description: "Fix CVE",
prompt: "## Vuln Fix Request
repo: [absolute repo path]
phase: full
branch: [the branch name Step 1 resolved for this CVE]
baseline_tests: run-fresh
jira_placeholder: [NOJIRA or omit]
model_routing:
classification: [MODERATE]
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> # vuln-research; vuln-fixer (SIMPLE/MODERATE); review-fixer
planning_model: <§2 Opus chain> # vuln-fixer 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: false
notes: <any §2 / §2.1 fallback or degradation>
read the single READY research report from the file at [`research_file`]"
)
If the fixer returns status: BLOCKED, the research report at research_file could not be
read — an orchestrator bug, not a user choice: report the unreadable path to the user, mark
this CVE BLOCKED in the Step 4 summary table, and stop working this CVE. Do not retry with
a fresh research pass — that would re-derive the evidence instead of surfacing the failure.
Otherwise, if the fixer returns status: TEST_REGRESSION, follow "Handling Test Failures"
below, then re-invoke vuln-fixer with phase: regression-resume + the chosen
regression_decision, passing the same CVE input with the original research report
re-supplied from research_file.
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 CVE. 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.
SIGNIFICANT / HIGH-RISK path
- Capture baseline at the orchestrator using the existing
test-baselineragent. Keep the full baseline block (passing_countandpassing_tests). - Invoke
vuln-fixerwith review gating enabled:
task(
agent_type: "dev-workflows:vuln-fixer",
model: `<detection_model for SIGNIFICANT; planning_model (§2 Opus chain) only if HIGH-RISK>`,
description: "Apply CVE fix before review",
prompt: "## Vuln Fix Request
repo: [absolute repo path]
phase: full
branch: [the branch name Step 1 resolved for this CVE]
baseline_tests: provided
baseline_passing: [captured count]
baseline:
passing_tests:
- [captured test ids]
jira_placeholder: [NOJIRA or omit]
model_routing:
classification: [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> # vuln-research; vuln-fixer (SIMPLE/MODERATE); review-fixer
planning_model: <§2 Opus chain> # vuln-fixer 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
notes: <any §2 / §2.1 fallback or degradation>
read the single READY research report from the file at [`research_file`]"
)
Handle a
vuln-fixerstop. If the fixer returnsstatus: BLOCKED, the research report atresearch_filecould not be read — an orchestrator bug, not a user choice: report the unreadable path to the user, mark this CVEBLOCKEDin the Step 4 summary table, and stop working this CVE (do not retry with a fresh research pass, and do not proceed to Opus review). Otherwise, if the fixer returnsAWAITING_REVIEW, run Opus code review before tests:- Capture the diff to a temp file: write
git add -N . && git difftomktemp -t dw-vuln-diff-XXXX.patch(never inside a repo tree) and record its path asreview_diff_file - Write the fixer output to a temp file (
mktemp -t dw-vuln-claims-XXXX.md, never inside a repo tree) and record its path asclaims_file. Invokecode-reviewwith the CVE summary, the research handoff (fromresearch_file), the diff (fromreview_diff_file), andclaims_file: [the path](dispatch-pinned to Opus; recorded asreview_modelabove, nomodel:override needed) - Check the review's first line before acting on the verdict. If it is
Diff: unreadable at <path>, the orchestrator's ownreview_diff_filecould not be read — an orchestrator bug, not a user choice: surface the unreadable path to the user and stop working this CVE, marking itBLOCKEDin the Step 4 summary table. Do NOT triage the finding and do NOT dispatchreview-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
BLOCKorPASS WITH RECOMMENDATIONS, invokereview-fixerwith model:<detection_model — §2.1 detection chain>for the survivingBLOCKERandMAJORfindings - Handle a
review-fixerstop. If itsStop condition flagisNEEDS HUMAN, do NOT re-run the review: surface the deferred BLOCKER(s) to the user with the reasonreview-fixergave, mark this CVEBLOCKEDin the Step 4 summary table, and stop working this CVE — do not continue to tests, and do not re-review. Then run Step 3.9 withclean_finish: false: the fix is on disk and stopping the CVE is not a reason to leave it in a working tree, so it is committed and pushed, and its pull request is opened as a draft carrying the DO-NOT-MERGE banner (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md§2.9). Only when the flag isCLEARdo you overwritereview_diff_filewith a freshgit add -N . && git diffand 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. Run Step 3.9 withclean_finish: false— same reasoning as theNEEDS HUMANstop above: the work is committed and pushed, and the pull request is a draft the banner says not to merge
- Capture the diff to a temp file: write
Resume the fixer after review — Re-invoke
vuln-fixerwithphase: verify-resume, the same baseline block, and the original research report re-supplied fromresearch_file. If the resumed agent returnsstatus: BLOCKED, the re-supplied file path could not be read: report the named path to the user and stop this CVE. 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 fixer returns
status: TEST_REGRESSION(from step 4's resumed verify), follow "Handling Test Failures" below, then re-invokevuln-fixerwithphase: regression-resume+ the chosenregression_decision, the same baseline block, and the original research report re-supplied fromresearch_file. If the resumed agent returnsstatus: BLOCKED, the re-supplied file path could not be read: report the named path to the user and stop this CVE. 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.
Step 3.9 — Code-repo handoff (both paths, once per CVE)
vuln-fixer creates the fix branch before its first edit and leaves the change on it, uncommitted; the commit, the push, and the pull request are the orchestrator's, because the consent choice they sit behind is one only the orchestrator can ask (sub-agents dispatched via the task tool run in a separate context and have no interactive tools). The branch-first ordering is what makes this step reachable on the paths where the fixer never runs to completion — an AWAITING_REVIEW return whose review then stops the CVE still has a branch to commit onto.
Runs after the fixer's last return for this CVE — after the verify-resume call on the SIGNIFICANT / HIGH-RISK path, after the regression-resume call where one happened. 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, with the §2.11 inputs:
repoandbranch— the repo, and the branch name Step 1 resolved and the fixer created.pre_existing_dirty— as recorded at the top of Step 3;stash_ref: null.commit_template— the "Commit message" template in this skill's Git Workflow section below.vuln:is the one caller with a template of its own, so §2.3 uses it verbatim rather than deriving a subject from the repo's log.title—fix(deps): <library> upgrade to remediate <CVE-ID>, with[<JIRA-ID>]appended when the CVE has one.body_facts— the CVE summary, the vulnerable range, the version change applied, the classification, the Opus review verdict and triage where the CVE went through review, and the test counts before and after.clean_finish—falsewhen the CVE endedBLOCKED, when its review is stillBLOCK, or when the user chosekeep-anywayon a regression;trueotherwise. Per §2.9 the commit and the push happen either way; only the pull request changes (draft, DO-NOT-MERGE banner).
§2.4's choice is asked on the first CVE and reused for every later one (code_handoff_choice) — a ten-CVE run asks once, not ten times. Emit the §3.1 Code repo: line per CVE and carry its pull-request number into the Step 4 table's PR column.
What to hand off is decided by the tree, never by the status label. Before skipping any CVE, run git -C "<repo>" status --porcelain --untracked-files=all and compare it against pre_existing_dirty:
- Anything of this run's is present ⇒ run Step 3.9. It does not matter which status the CVE carries.
- Nothing of this run's is present ⇒ skip, and say why in the Step 4 table.
This is deliberately not keyed on status, because BLOCKED means two opposite things. It is returned by the first fixer call when the research report cannot be read — nothing was created, nothing changed — and by a resume call (Step 3's SIMPLE/MODERATE path and steps 4 and 5 of the SIGNIFICANT path) when the re-supplied path cannot be read, at which point the branch exists and the fix is already applied to it. It is also the label this command writes into the Step 4 table for four orchestrator-side gate stops, two of which (NEEDS HUMAN, a persisting review BLOCK) are explicitly required below to hand off. A skip list keyed on the label would strand an applied fix on a branch, and the next CVE's git switch would then either abort or carry it onto an unrelated branch.
For orientation, the states that normally reach each outcome: BASELINE_FAILED and a first-call BLOCKED changed nothing; SKIPPED_BY_USER never invoked the fixer; BUILD_FAILED and REVERTED reverted their own change and normally leave the step-2 branch in place and empty — the plugin never deletes a branch (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md §1 rule 3), so name the stray ref in the Step 4 table rather than leaving it unexplained. Each of these is still confirmed against the tree, not assumed.
Never skipped for a CVE that failed a gate. A CVE stopped at an unresolved review BLOCK or at NEEDS HUMAN is handed off with clean_finish: false: its fix is applied and sitting on a branch that exists precisely because the fixer created it before the first edit, and §2.8 is exactly the case for it.
Step 4 — Summarise
After all CVEs are processed, print a result table:
| CVE | Library | Change | Class | Result | PR |
|----------------|-----------------|----------------|--------------|---------|-----|
| CVE-2023-46604 | activemq-broker | 5.15.5→5.15.16 | MODERATE | OK | #42 |
| CVE-2024-99999 | (not in repo) | — | — | SKIP | — |
Append a ### Model Routing section summarising the per-CVE classification, why it was chosen, the models used, and any Opus review verdicts.
Append a ### Review triage section with one line per CVE 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 path, no Opus review)" for CVEs that never reached review.
Then invoke impl-maintenance with a compact session handoff covering the CVEs fixed, notable regressions, workarounds, and overall outcome. Always pass Command run: vuln: 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).
Then 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: vuln:, 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 — the impl-maintenance report still appears in the output; 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.
Then 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 (vuln:) — or NOISSUE … when the run resolved no Jira key — and pushes per §4 step 5. It NEVER touches the code repo this run just fixed: that repo's branches, commits, and pull requests were Step 3.9's, 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 after the feedback path, prefixed Specs repo:, with any guard notice repeated in full. No resume.md is written for vuln: (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md §1 skip list — the durable state is the branch and PR).
Handling Test Failures
vuln-fixer 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:
- Present the failing tests clearly (from the fixer's
failing_tests/diagnosis). - Ask via
ask_user— no option is safe to recommend across arbitrary regressions, so this list carries no(Recommended)marker and the qualifying condition sits in the option's own description (per the marker rule in~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/escalation-rules.md):choices: ["Apply the fix anyway and flag the failures in the PR — for flaky tests", "Revert this fix and skip it", "Investigate further"] - "Investigate further" → show more detail (the diff, full failure output) and re-ask the same choices — this loops here at the orchestrator until the user picks apply or revert.
- Map the final choice to
regression_decision: keep-anyway | revertand re-invokevuln-fixerwithphase: regression-resume(see Step 3).
Git Workflow
Branch naming
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. The orchestrator reads the repo's CONTRIBUTING.md, CONTRIBUTION.md, README.md, DOCUMENTATION-GUIDELINES.md, .github/copilot-instructions.md (+ .github/) for a branch-naming section (§1.1), fills its segments (§1.2) — identity from the §2 ladder ($GIT_USER_INITIALS → git config user.initials → inference → the §2.5 prompt), issue key from the CVE's Jira ID when present (else the documented no-issue literal, or the NOJIRA placeholder detected in Step 1), description from the CVE ID — and hands the resolved name to vuln-fixer. Never add an identity segment the pattern does not ask for.
When the repo documents no convention (§1.4), <prefix> comes from the §2 ladder with fallback fix/:
- With Jira ID:
<prefix>/JIRA-ID-CVE-XXXX-XXXXX - Without Jira ID:
<prefix>/NOJIRA-CVE-XXXX-XXXXX(or<prefix>/CVE-XXXX-XXXXXif the project omits placeholders)
Commit message
Use the project's existing style. Default template:
With Jira ID:
fix(deps): upgrade <library> to <version> to remediate <CVE-ID>
Resolves <JIRA-ID>
Fixes <CVE-ID> - <one-line CVE description>
Vulnerable range: <range>
Safe version: <version>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Without Jira ID:
fix(deps): upgrade <library> to <version> to remediate <CVE-ID>
Fixes <CVE-ID> - <one-line CVE description>
Vulnerable range: <range>
Safe version: <version>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Commit, push, and PR
All three are Step 3.9's, through finish-code-branch (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md §2) — never vuln-fixer's. The commit-message template above is passed as that step's commit_template and used verbatim (§2.3).
- Base branch: resolved per §2.8's ladder —
origin/HEAD, thenorigin/main,origin/master,origin/develop. Never assumed. - Title:
fix(deps): <library> upgrade to remediate <CVE-ID>(append[<JIRA-ID>]when present) - Body: CVE summary, vulnerable range, version change made, classification, review verdict and triage where the CVE went through review, and test results (pass count before vs. after)
- Opened with
ghbehind §2.6's capability probe; on any failure the run falls back to §3.2's manual-open text rather than reporting a pull request that does not exist. Aclean_finish: falseCVE gets a draft plus the DO-NOT-MERGE banner (§2.9).
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) - ALWAYS classify per CVE after research
- NEVER use Opus for a
MODERATEfix unless the user explicitly asks for it - NEVER run tests for a
SIGNIFICANT/HIGH-RISKCVE before the Opus review returns a non-BLOCK verdict - ALWAYS pass the captured baseline block back to
vuln-fixeronphase: verify-resume - ALWAYS run Step 3.9 (
finish-code-branch, per~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/code-repo-handoff.md) after a CVE's last fixer return — the commit is prompt-free (§1 rule 5), §2.4's choice is asked once per run and reused for every later CVE, and a CVE whose fix is on disk is never left uncommitted - NEVER let
vuln-fixercommit, push, or open a pull request — it creates the branch and applies the fix; the orchestrator owns the handoff, because the consent choice behind it is one a sub-agent cannot ask - NEVER push the code repo directly to
main/master— always use the dedicated fix branch (agents/vuln-fixer.md), one per CVE, branched from the base and not from the previous CVE's branch (Step 3). This binds the code repo only: the specs-repo steps above push$SPECS_PATH's bounded artifact paths to the specs repo's own branch (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md§3.4 / §4), and never force-push (§1 rule 4) - ALWAYS run
specs-preflightat Step 0 andcommit-artifactsas 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), alwaysgit -C "$SPECS_PATH"and never acd(§1 rule 1), never force-pushing, and never failing the 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.