Skip to content

feat(workflows): Phase 5 ADO MG-PR verbs wired (replaces human-gate stub)#118

Merged
PolyphonyRequiem merged 1 commit into
mainfrom
sdlc/phase5-ado-mg-wiring
May 6, 2026
Merged

feat(workflows): Phase 5 ADO MG-PR verbs wired (replaces human-gate stub)#118
PolyphonyRequiem merged 1 commit into
mainfrom
sdlc/phase5-ado-mg-wiring

Conversation

@PolyphonyRequiem

Copy link
Copy Markdown
Owner

feat(workflows): Phase 5 ADO MG-PR verbs wired (replaces human-gate stub)

Replaces the mg_pr_human_gate_ado stub in implement-mg.yaml with the
real pr open-mg-ado + pr merge-mg-ado verbs (shipped in PR #106 but
previously unwired because the workflow chain didn't thread the ADO
connection inputs).

What changed

polyphony-implement.yaml (1.1.0 → 1.2.0)

  • New optional inputs: organization, project, repository (all
    default ""). Required only when platform=ado; ignored otherwise.
  • Threaded down to implement-mg.yaml alongside the existing platform
    input.

implement-mg.yaml (1.0.0 → 1.1.0)

  • New optional inputs: organization, project, repository.
  • pr_platform_router now also computes ado_inputs_ready + missing
    so the workflow can fail early and clearly when platform=ado but the
    connection inputs are blank — without burning an ADO API call that
    would just return error_code: invalid_argument.
  • Replaced mg_pr_human_gate_ado (operator-managed PR) with:
    • mg_pr_open_ado — script invoking polyphony pr open-mg-ado with
      --organization/--project/--repository. Idempotent (reuses an
      existing OPEN PR for the same head/base pair).
    • mg_pr_merge_ado — script invoking polyphony pr merge-mg-ado.
      Hardcoded merge-commit per the ADR (nested MGs depend on git
      ancestry; squash and rebase would break the chain). Idempotent
      (recognises an already-merged PR).
    • mg_pr_failed_gate_ado — human gate fired when either ADO verb
      returns a non-empty error_code (or merge returns merged=false).
      Retry routes back to mg_pr_open_ado (safe — both verbs are
      idempotent); abort routes to $end without invoking scope_closer.
    • mg_pr_inputs_missing_gate — human gate fired when platform=ado
      but one or more of organization/project/repository is blank.
      Surfaces the missing field list from the router so the operator can
      re-invoke with the correct inputs.
  • output.pr_url and output.pr_number now prefer mg_pr_open_ado when
    defined, falling back to mg_pr_open (per M3 + M7).
  • All routes use explicit error_code is defined and != '' /
    merged == true conditions plus a catch-all to the failure gate
    (per M4).

index.yaml

  • Added missing implement-mg entry (was previously absent).
  • Bumped polyphony-implement versions list to include 1.1.0 + 1.2.0
    (1.1.0 was already on disk but not tracked in the index — historical
    drift fixed in passing).

Scope decision (per rubber-duck pass)

This PR DOES NOT touch polyphony-full.yaml. Promoting platform to
the apex creates a misleading semantic where a full run with
platform=ado would still create GitHub plan PRs (because
plan-level.yaml is GitHub-only today). Operators wanting ADO MG
support should invoke polyphony-implement.yaml directly with
platform=ado + the three connection inputs, OR pre-author the plan
and start from ready_for_implementation. Apex-level platform threading
is deferred until plan-level + feature-pr ADO support land.

Validation

  • All 16 lint scripts (8 ps1 + 8 Pester suites) pass.
  • conductor validate passes for both touched workflows.
  • 2400/2400 .NET tests pass.
  • Verb signatures verified against the ADO MG verb help output and
    result schemas (PrOpenMgAdoResult, PrMergeMgAdoResult).

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

…tub)

Replaces the `mg_pr_human_gate_ado` stub in `implement-mg.yaml` with the
real `pr open-mg-ado` + `pr merge-mg-ado` verbs (shipped in PR #106 but
previously unwired because the workflow chain didn't thread the ADO
connection inputs).

## What changed

### `polyphony-implement.yaml` (1.1.0 → 1.2.0)

- New optional inputs: `organization`, `project`, `repository` (all
  default `""`). Required only when `platform=ado`; ignored otherwise.
- Threaded down to `implement-mg.yaml` alongside the existing `platform`
  input.

### `implement-mg.yaml` (1.0.0 → 1.1.0)

- New optional inputs: `organization`, `project`, `repository`.
- `pr_platform_router` now also computes `ado_inputs_ready` + `missing`
  so the workflow can fail early and clearly when platform=ado but the
  connection inputs are blank — without burning an ADO API call that
  would just return `error_code: invalid_argument`.
- Replaced `mg_pr_human_gate_ado` (operator-managed PR) with:
  - `mg_pr_open_ado` — script invoking `polyphony pr open-mg-ado` with
    `--organization/--project/--repository`. Idempotent (reuses an
    existing OPEN PR for the same head/base pair).
  - `mg_pr_merge_ado` — script invoking `polyphony pr merge-mg-ado`.
    Hardcoded merge-commit per the ADR (nested MGs depend on git
    ancestry; squash and rebase would break the chain). Idempotent
    (recognises an already-merged PR).
  - `mg_pr_failed_gate_ado` — human gate fired when either ADO verb
    returns a non-empty `error_code` (or merge returns merged=false).
    Retry routes back to `mg_pr_open_ado` (safe — both verbs are
    idempotent); abort routes to `$end` without invoking `scope_closer`.
  - `mg_pr_inputs_missing_gate` — human gate fired when platform=ado
    but one or more of `organization/project/repository` is blank.
    Surfaces the missing field list from the router so the operator can
    re-invoke with the correct inputs.
- `output.pr_url` and `output.pr_number` now prefer `mg_pr_open_ado` when
  defined, falling back to `mg_pr_open` (per M3 + M7).
- All routes use explicit `error_code is defined and != ''` /
  `merged == true` conditions plus a catch-all to the failure gate
  (per M4).

### `index.yaml`

- Added missing `implement-mg` entry (was previously absent).
- Bumped `polyphony-implement` versions list to include 1.1.0 + 1.2.0
  (1.1.0 was already on disk but not tracked in the index — historical
  drift fixed in passing).

## Scope decision (per rubber-duck pass)

This PR DOES NOT touch `polyphony-full.yaml`. Promoting `platform` to
the apex creates a misleading semantic where a full run with
`platform=ado` would still create GitHub plan PRs (because
`plan-level.yaml` is GitHub-only today). Operators wanting ADO MG
support should invoke `polyphony-implement.yaml` directly with
`platform=ado` + the three connection inputs, OR pre-author the plan
and start from `ready_for_implementation`. Apex-level platform threading
is deferred until plan-level + feature-pr ADO support land.

## Validation

- All 16 lint scripts (8 ps1 + 8 Pester suites) pass.
- `conductor validate` passes for both touched workflows.
- 2400/2400 .NET tests pass.
- Verb signatures verified against the ADO MG verb help output and
  result schemas (`PrOpenMgAdoResult`, `PrMergeMgAdoResult`).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PolyphonyRequiem PolyphonyRequiem merged commit 995014b into main May 6, 2026
1 check passed
@PolyphonyRequiem PolyphonyRequiem deleted the sdlc/phase5-ado-mg-wiring branch May 6, 2026 23:34
PolyphonyRequiem added a commit that referenced this pull request May 7, 2026
… (Phase 5) (#121)

Replaces the human-gate stub of `ado-pr.yaml` with a real platform-native
PR lifecycle and makes `feature-pr.yaml`'s creator step platform-aware.
Mirrors the shape of `implement-mg.yaml` from PR #118 (the canonical
template for github/ado dual-leg workflows).

## ado-pr.yaml — full rewrite (1.0.1 → 2.0.0)

Was a 138-LOC stub that emitted ADO_PR_NOT_IMPLEMENTED and surfaced a
single human gate. Now a real ~600-LOC lifecycle:

- `ado_inputs_validator` (entry) — fail-fast on missing organization/
  project/repository inputs before burning an API call.
- `ado_pr_status_check` — calls `polyphony pr poll-status-ado`, routes
  6 ways on `state`: merged → already-merged emitter; approved +
  merge_allowed → merger; approved + blocked → blocked-gate;
  changes_requested / pending / closed / error → respective human gates.
- `ado_pr_merger` — calls `polyphony pr merge-feature-ado`, passes
  `--match-head-commit {{ status_check.head_sha }}` as a stale-head
  guard. On `error_code == 'stale_head'` routes back to
  `ado_pr_status_check` (re-poll with new SHA, then re-attempt merge).
- Terminal emitters: `ado_pr_already_merged_emitter` (idempotent merged
  case), `ado_pr_treat_as_merged_emitter` (operator override — emits
  `override=true`/`reason='operator_manually_verified_merge'` for log
  traceability).
- 7 human gates total: `ado_pr_blocked_gate` (approved-but-not-mergeable
  with `policy.blocking_reasons` surfaced), `ado_pr_changes_requested_gate`,
  `ado_pr_pending_gate`, `ado_pr_closed_gate`, `ado_pr_error_gate`,
  `ado_pr_merge_failed_gate`, `ado_inputs_missing_gate`.
- Gate option labels renamed: "Treat as merged" → "I manually verified
  merge" (per rubber-duck — old phrasing concealed that polyphony hadn't
  actually verified anything).

NO LLM reviewer in this revision: humans review natively in ADO; polyphony
just polls and merges. LLM-advisory mode for ADO is a future enhancement
that needs a `pr post-comment-ado` verb (doesn't exist yet).

## feature-pr.yaml — restructure (1.0.1 → 1.1.0)

- New optional inputs `organization`/`project`/`repository` for ADO.
- `entry_point` flips from `feature_pr_creator` → `pr_platform_router`
  (router upstream of creator, mirrors implement-mg.yaml shape).
- `pr_platform_router` computes `{ platform, ado_inputs_ready, missing }`.
  GitHub → `feature_pr_creator_github`; ADO + ready → `feature_pr_creator_ado`;
  ADO + missing → `feature_pr_inputs_missing_gate`.
- Creator split: `feature_pr_creator` → `feature_pr_creator_github` (calls
  `pr create-feature-pr`) + `feature_pr_creator_ado` (calls
  `pr create-feature-ado`).
- New `feature_pr_creator_failed_gate_ado` for ADO creator errors (retry
  is idempotent — reuses existing OPEN PR).
- `pr_lifecycle_ado` now threads `organization`/`project`/`repository` +
  `pr_number` from the ADO creator into ado-pr.yaml v2.
- ADO leg short-circuits remediation: on `pr_lifecycle_ado.merged == false`,
  routes to new `ado_remediation_not_supported_emitter` (emits merged=false
  with `reason='ado_remediation_not_supported'`). The remediation chain
  (`remediation_planner`/`remediation_implementer`/`feature_pr_updater`)
  is GitHub-only — uses `gh` directly; cannot run on ADO without `pr
  post-comment-ado`/`pr request-review-ado` verbs that don't exist yet.
  Operator must remediate manually in ADO and re-invoke the workflow.
- All `feature_pr_creator.output.pr_number` references in remediation
  prompts renamed to `feature_pr_creator_github.output.pr_number` —
  safe because the remediation chain is now GitHub-only by construction.
- Output map updated: `pr_url` and new `pr_number` use
  `is defined` guards to prefer ADO when defined, fall back to GitHub
  (M3 / StrictUndefined-safe).

## Lint script update

`lint-ado-pr.ps1` was written for the stub and required two now-obsolete
shapes: the `ADO_PR_NOT_IMPLEMENTED` sentinel string and a `merged` gate
option value. Both are gone in v2 (real lifecycle has no sentinel; gate
options are semantic — `repoll`, `verified_merge`, `retry`,
`trigger_remediation`, `abort` — not literal `merged`/`aborted`). Lint
now requires only `abort` from human gates (universal exit-path rule per
P6) and is documented in the comment block.

`lint-ado-pr.Tests.ps1` updated accordingly: dropped two stub-era tests;
added one focused test for the `abort`-required check.

## Validation

- All 8 lint scripts pass (`lint-ado-pr.ps1` PASS).
- All 16 lint Pester suites pass (101/101 tests).
- `dotnet build` clean, `dotnet test` 2475/2475 (no code changes — pure
  YAML + PowerShell lint update).

## Rubber-duck blockers addressed

1. **Approved ≠ mergeable.** Routes split for `approved + merge_allowed`
   (→ merger) vs `approved + blocked` (→ `ado_pr_blocked_gate`). Merger
   passes `--match-head-commit` for stale-head safety; on `stale_head`
   error_code routes back to status_check.
2. **"Treat as merged" can lie.** Renamed to "I manually verified merge"
   across all 5 gates that present it. Emitter records `override=true`
   and `reason='operator_manually_verified_merge'` for log traceability.
3. **ADO remediation is GitHub-only.** Short-circuited at
   `pr_lifecycle_ado` instead of bleeding into the GitHub-shaped
   `remediation_planner` chain. Honest "not supported" exit beats a
   silent failure inside the wrong toolchain.

## Deferred

- LLM advisory reviewer for ADO (needs `pr post-comment-ado`).
- ADO remediation chain (needs `pr post-comment-ado` +
  `pr request-review-ado`).
- Plan-level ADO wiring (next workflow PR; same pattern, deeper
  workflow).

Co-authored-by: Daniel Green <dangreen@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant