Releases: Wave-Engineering/mcp-server-sdlc
Release list
v4.0.0
What's Changed
Full Changelog: v3.0.0...v4.0.0
v3.0.0
What's Changed
- chore(wave): parameterize the kahuna branch name, drop trunk-defaulting target_branch by @bakeb7j0 in #505
- chore(release): v3.0.0 — target_branch is required, no trunk default by @bakeb7j0 in #507
Full Changelog: v2.1.2...v3.0.0
v2.1.2
What's Changed
- chore(release): bump package.json to 2.1.1 to match the released tag by @bakeb7j0 in #499
- chore: bump package.json version to 2.1.2 for v2.1.2 tag by @bakeb7j0 in #501
Full Changelog: v2.1.1...v2.1.2
v2.1.1
Fixes two defects where the tooling reported success it had not achieved
GitLab merges failed with 400 SHA must be provided when merging
pr_merge and pr_merge_wait were a hard block on affected GitLab projects — the MR was left open, waiting for a human, with no MCP fallback. /scpmmr completed MR-create and CI, then died at merge.
Why it started happening, and why it will keep happening: GitLab's merge endpoint rejects an unguarded merge when the project's namespace has require_sha_for_merge, and GitLab now defaults that ON for newly-created groups. This is an upstream environment change, not a regression here — which is why newly-created nested groups failed while older projects that had always merged kept working. Expect it on every new subgroup.
The adapter now resolves the MR's source-branch HEAD and passes it as --sha.
pr_status reported zero checks for PRs with passing checks
pr_status returned checks: none for GitHub PRs that had passing checks — on every GitHub PR, permanently, on any host running gh 2.45 (what Ubuntu 24.04 LTS ships). It ran gh pr checks --json, a flag that does not exist on that version, and treated the resulting non-zero exit as "no checks configured".
Checks are now read from statusCheckRollup on the existing gh pr view call — one subprocess instead of two.
Behaviour changes (not just fixes)
Both change what callers observe. Neither should break correct usage, but they are worth knowing before the upgrade.
1. --auto-merge=false is now forced on GitLab merges. A pending pipeline now merges or fails — it no longer silently enrols (merge-when-pipeline-succeeds) while the tool reports merge_method: "direct_squash" and a completed merge. Anyone who was relying on the enrolment behaviour will see a difference; that behaviour was reporting success for a non-merge.
2. pr_status now fails closed. A checks query that fails returns {ok: false, code} instead of ok: true with a zeroed summary. Callers that treated an empty summary as "this PR has no checks" will now see an error — that is the point, and it is not a regression. A genuine zero (a PR with no checks configured) still returns ok: true with summary: "none"; the two are now distinguishable.
Also in this release
-R <repo>is shell-escaped in the GitLab merge path (was the one caller-supplied field interpolated raw).- Stale-head
409handling is anchored to the HTTP status rather than a bare409match — glab echoes the request URL, which contains the MR IID, so merging MR !409 previously matched on its own number and misclassified genuine failures as races. --shaand--auto-mergeadded to the real-CLI flag-shape gate.--auto-mergeis itself a rename of the older--when-pipeline-succeeds; the mocked unit suite cannot catch a glab that rejects either flag.- Adapter errors now surface a
codethrough thepr_statushandler.
Validation
Both fixes were validated live as paired experiments — the defect reproduced first on the same fixture, then the fix applied — rather than on green unit tests alone:
- GitLab merge: reproduced
400 SHA must be provided when mergingon a realrequire_sha_for_mergenamespace, then merged. Confirmed by reading MR state back from the API, includingmerge_when_pipeline_succeeds: falseto prove a real merge rather than an armed auto-merge. pr_status:gh pr checks --jsonexits 1 on gh 2.45 (what producednone), then the new path reportedtotal 4, passed 4, all_passedon the originally-reported PR.
Full suite: 2416 tests, 0 failures, 78/78 runtime smoke, trivy 0 HIGH/CRITICAL.
Upgrade: curl -fsSL https://raw.githubusercontent.com/Wave-Engineering/mcp-server-sdlc/main/scripts/install-remote.sh | bash — then restart Claude Code so the MCP subprocess picks up the new binary.
v2.1.0
v2.1.0 adds one new MCP tool (branch_guard) and hardens several existing ones against silent false-positive gate results — the dominant theme this cycle is "a compliance/trust check returned a confident ok:true/success when it shouldn't have." ci_wait_run gains a merge-result anchor to stop grading the wrong pipeline; ibm and branch_guard stop guessing repo/branch pairings; work_item stops leaking type::epic onto Plans. Also: three wave-engine handlers stop hardcoding main as the mainline, a deploy-freshness startup check was added, and two HIGH CVEs were patched. CHANGELOG.md was retired in this range (#459) — GitHub Releases notes (this document) are now the authoritative changelog; there is no in-repo file to check.
New tools
branch_guard(#469, refined #471, #485) — Guards against basing on / merging into the wrong mainline. Input:role('base'|'target'), optionalbranch, optionalrepo. Resolves the git host's live default branch and verdicts whether the checked branch is "protected" by name (mainorrelease/*— a shared pattern withibm, not a live host protection query as originally shipped in #469 and reworked in #471). Returns{verdict: 'pass'|'warn', reason, default_branch, checked_branch, is_protected, is_sandbox};kahuna/*sandboxes always pass. Warns when a protected-by-name branch is neither the live default nor a sandbox (e.g. a stalerelease/0.0.1after the default moved torelease/1.0.0). Call it before basing/merging to catch drift against a moved default branch. As of #485,role:'base'with an explicitrepobut nobranchis refused rather than pairing the server cwd's current branch with a possibly-unrelated foreign repo.
Changed
ci_wait_run(#478, #484) — New optional paramsrequire_merge_result: booleanandpr_number: number(required together via a zod.refine). Setrequire_merge_result: trueto accept only a run that validated the actual merge result for the PR/MR's current head — GitHub: apull_requestrun whosehead_shamatches the PR head; GitLab: the pipeline GitLab reports as the MR'shead_pipeline(a detached/heador merge-train/trainpipeline no longer counts). A non-qualifying run now yieldsfinal_status: "not_merge_result"instead of a misleading success. Also: the "no run has appeared yet" grace window is now decoupled by call shape —require_merge_resultstill gets the fulltimeout_sec(merged-results pipelines are slow to appear), but a plainexpected_shawait is now bounded tomin(timeout_sec, 180s)instead of silently consuming the entire timeout on a transient first-poll miss. Phase-2 (polling a run once it has appeared) is unaffected either way.ibm(#481) — New optionalrepoparam, threaded through both the issue lookup and the PR/MR lookup. Pass it whenever the branch being checked is not the one checked out in the server's cwd. Behavior change: an unrecognized branch with norepogiven is now refused (ok:false) rather than silently resolved against the cwd's repo — previously this could match a same-numbered but unrelated issue in the wrong repository and return a falseok:truecompliance pass. The response envelope now echoes therepoactually checked.work_item(#479) —typeenum gains'plan'(appliestype::plan); previously/issue planwas documented but not creatable. Behavior change: the autotype::<type>label is now suppressed whenever the caller already supplies anytype::*label (both platforms) — previously it was always prepended, which was only safe on GitLab by accident (scoped-label eviction); on GitHub the same call could produce an issue tagged with bothtype::epicandtype::plan. Caller-supplied labels are also now trimmed/normalized once before both the suppression check and the platform argv, and a GitHub--labelfailure on a non-existent label now names the remedy (label_create) in the error message.wave_init— thekahunabootstrap's implicitbase_branchno longer defaults to the literal'main'; when the plan omitsbase_branchit now resolves the repo's live default branch via the adapter (#473).wave_finalize—target_branchchanged fromz.string().min(1).default('main')toz.string().min(1).optional(). An explicit value still wins; when omitted, it now resolves the repo's live default branch instead of silently targetingmain(#473). Matters for any repo whose default branch isn'tmain(e.g.release/1.0.0).- Internal-only, no signature/output change:
fetch-ci-trust-signal-github's branch-protection probe (backswave_ci_trust_level) now probes the live default branch instead of a hardcodedmain(#473). FlightDeck event emission was wired intocommutativity_verify,drift_check_path_exists,drift_check_symbol_exists,drift_files_changed,ci_wait_run,pr_wait_ci,wave_ci_trust_level,pr_merge, andwave_finalize(#464) — fire-and-forget telemetry to~/.claude/status/events.jsonl/FlightDeck ingest; every emit runs after the handler's normal work and never alters the response or control flow. - Server startup —
SERVER_VERSIONnow derives from the injected build tag (git describe, e.g.2.1.0) instead of a hardcoded'1.0.0'; uncompiled dev runs report0.0.0-dev. A new one-time, non-blockingdeploy_freshnesscheck compares the running binary's embedded build SHA against the server's own latest GitHub release and emits a singlewarn-level log line if the binary is stale (#482, closes #447) — network-optional, degrades silently ifgh/network/releases are unavailable, and answersinitializein ~150ms even while the freshness check is in flight.
Fixed
ci_wait_run/ wave trust gate (#478) — Fixed a live false-pass: GitLab skips the branch pipeline on a merge commit, and the status mapping treatedskippedassuccess, so a kahuna merge commit's gate could reportfinal_status: "success"for a pipeline that never ran. Also closed a "freshness by absence" gap where a green merge-result run for a previous commit could satisfy the gate for a PR/MR whose head had since moved — the run is now re-validated against the anchor before grading.ci_wait_run(#484) — Fixed a silent full-timeout_sechang: withexpected_shaset, a transient miss on the first CI-run poll used to consume the entire (typically 1800s) timeout with zero partial output before failing; now bounded to ~180s with an actionable error.ibm(#481) — Fixed a false compliance pass where a branch not checked out in the server's cwd got its issue number looked up against the cwd's repo, matching an unrelated same-numbered issue in the wrong repository.work_item(#479) — Fixed a GitHub-only taxonomy leak where an issue created withtype: 'epic'plus a caller-suppliedtype::planlabel ended up carrying both labels (GitHub has no scoped-label mutual exclusion, unlike GitLab).branch_guard(#480, shipped in #485) — Fixed the same cwd-branch/foreign-repo pairing trap as theibmfix, scoped torole:'base': arepogiven without abranchno longer infers the cwd's current branch and resolves it against a repository it may not belong to.- Security (#468, #450, shipped in #485) —
fast-uribumped to^3.1.2(resolves 3.1.3) andhonoto^4.12.25(resolves 4.12.30), patching CVE-2026-6321, CVE-2026-6322, and CVE-2026-54290.trivy fs --severity HIGH,CRITICAL: 0 findings.
v2.0.3
What's Changed
- fix(ibm): distinguish unrecognized-prefix from missing-issue errors by @bakeb7j0 in #451
- fix(wave_finalize): root PR find/create at args.root, not the session project by @bakeb7j0 in #454
Full Changelog: v2.0.2...v2.0.3
v2.0.2
What's Changed
- fix(install): handle PEP 668 in commutativity-probe install by @bakeb7j0 in #433
- fix(epic_sub_issues): parse nested-bullet refs in Phase checklists by @bakeb7j0 in #436
- fix(gitlab-api): URL-encode branch names in resolveBranchSha API path (#437) by @bakeb7j0 in #441
- fix(wave_init): normalize devspec-upshift plan shape before persist (#438) by @bakeb7j0 in #442
- fix(wave_init): expose force param to allow plan overwrite (#439) by @bakeb7j0 in #443
- fix(pr-merge-gitlab): silently drop skip_train instead of returning platform_unsupported (#423) by @bakeb7j0 in #444
- fix(test): standardize ci-run-logs-gitlab fixture to org/repo (release flake) by @bakeb7j0 in #446
Full Changelog: v2.0.1...v2.0.2
v2.0.1
Fixes
- fix(routing):
getAdapteruses repo slug depth to infer platform — 3+ segment slugs route to GitLab regardless of server cwd (#426) - fix(gitlab-api): treat empty stdout from glab list endpoints as empty collection, not error — fixes intermittent
ibm()failure during precheck (#428) - fix(pr_comment): add
target: "issue" | "mr"param to disambiguate GitLab issue vs MR commenting (#430)
v2.0.0
What's Changed
- chore(phase-3): close retrofit — MV-05 verified, MV-06 partial, VRTM populated (#325) by @bakeb7j0 in #369
- feat(wave_init)!: accept kahuna: { plan_id, slug }; remove legacy epic_id by @bakeb7j0 in #370
- feat(wave_finalize)!: accept plan_id; title pattern plan(#N) by @bakeb7j0 in #371
- docs(wave-finalize): correct stale epic_id comment by @bakeb7j0 in #372
- chore(changelog): aggregate P2W2 entries by @bakeb7j0 in #373
- feat(wave-reconcile): Prime(post-wave) reconciliation handler + Category B drift-halt by @bakeb7j0 in #374
- feat(devspec-finalize): require depends_on field on every Story by @bakeb7j0 in #375
- chore(changelog): aggregate P2W3 entries by @bakeb7j0 in #376
Full Changelog: v1.8.1...v2.0.0
v1.8.1 — Platform Adapter Retrofit (Phase 2 + Phase 3)
Platform Adapter Retrofit — Phase 2 + Phase 3 complete
Internal refactor. All 25 platform-aware handlers are now migrated to the PlatformAdapter pair (GitHubAdapter, GitLabAdapter). Gate-greps enforce the adapter boundary across the full handler tree; lib/glab.ts has been removed.
Version note:
v1.8.0shipped the Phase-1-close milestone earlier today (2026-04-26 AM).v1.8.1completes the retrofit (Phase 2 + Phase 3) as a single coherent follow-on release. The bump is non-destructive to thev1.8.0pinning already in the wild.
What users see
No behavioral changes. Every MCP tool call emits the same I/O contract as v1.8.0. lib/glab.ts is no longer exported (internal-only change).
What changed internally
- MIGRATED_METHODS: 10/25 → 26/26
scripts/ci/migration-allowlist.txt: 31 entries → 0 (empty — gate-greps now enforce against ALL handlers)lib/glab.ts: deleted (all helpers migrated to adapters)- Test suite: 1466 → final count (green on every migration PR)
- Bugs closed en route: #280, #281, #282, #283
Links
- Dev Spec:
docs/platform-adapter-retrofit-devspec.md - Adapter architecture:
docs/adapters/README.md - Phase 1 survey:
docs/adapters/survey.md - VRTM: Dev Spec § Appendix V (to be finalized in Story 3.6)
- Full changelog:
v1.8.0...v1.8.1
Install / upgrade
SDLC_VERSION=v1.8.1 ./install-remote.shBinaries attached below (sdlc-server-linux-x64, sdlc-server-darwin-arm64, sdlc-server-darwin-x64) per DM-07.