Skip to content

feat: Azure DevOps repo support - #47

Draft
splashthree wants to merge 7 commits into
MCKRUZ:masterfrom
splashthree:ado-fold0-profile-and-plan
Draft

feat: Azure DevOps repo support#47
splashthree wants to merge 7 commits into
MCKRUZ:masterfrom
splashthree:ado-fold0-profile-and-plan

Conversation

@splashthree

Copy link
Copy Markdown
Contributor

What

First slice of making the plugin fully usable on Azure DevOps repos. Two artifacts plus their supporting changes:

  1. profiles/ado-enterprise/ — microsoft-enterprise's stack (C#/.NET 8 + Angular 17 + Azure, SOC 2 gates, 80% coverage, TDD) with stack.ci_cd.platform: azure-devops, so /sdlc-setup composes the existing Azure DevOps CI/CD pack (harness/packs/cicd/azure-devops/). Only intended deltas from the sibling profile: profile_id, the platform line, template wording, and the copied switchboard-rules.json self-id.
  2. docs/proposals/ado-repo-support-matrix.md — the plan for the remaining work, folded into five packages (one spec = one branch = one PR each): A installer platform-awareness (P0 — installs currently dump .github/ payload on every platform and put rubrics where the ADO pipelines don't look), B pack-aware doctor, C PR-flow rails (az repos pr create in hooks/skills/permissions), D prose sweep + platform-switch runbook, E keyless gate auth via Azure AI Foundry + Entra ID RBAC (spike first).

Supporting changes:

  • Profile added to the five curated enumerations (setup command, README, SKILL.md, docs/commands.md, docs/profiles.md, docs/architecture.md tree).
  • New test guard TestOnDiskProfiles: every profiles/*/profile.yaml must pass the real schema, and profile_id must equal the directory name (the profiles/<profile_id>/compliance/ lookup contract). Future profiles get CI coverage the moment their directory exists.
  • Doc-accuracy fix found during verification: docs/architecture.md §1.1–1.2 and docs/profiles.md Step 5 described a profiles registry inside plugin.json that does not exist — rewritten to describe the real mechanism (directory-listing auto-discovery; .claude-plugin/plugin.json is metadata-only).

Why

The ADO pipelines pack has existed since the harness landed, but no shipped profile exercises it and the docs steered profile authors to a fictional registration step. This PR gives ADO a first-class, menu-selectable entry point and lays down the reviewed plan for removing the remaining GitHub-only assumptions — additively (see the proposal's "Additive guarantee": GitHub-profile installs and API-key auth stay byte/behavior-identical; a fold that must edit an existing test has broken the rule).

Reviewer notes

  • Verification (4 independent passes, evidence in the proposal doc): full suite 818 passed (807 before + 11 new); fresh-repo e2e drill — init → harness install (composed stacks/dotnet + cicd/azure-devops + Angular) → gate check → artifact snapshot → upgrade dry-run idempotent (0 CONFLICT / 0 RETIRED); byte-level diff -r vs microsoft-enterprise shows only the intended delta; repo-wide sweep for profile enumerations and stale registration claims.
  • Known, intentional warts (documented in the proposal, fixed by Fold A — not here): an install from this profile still also emits .github/workflows/ files, and rubrics land at .github/profile/rubrics/ instead of .azuredevops/rails/rubrics/. This PR ships the profile that Fold A's golden-tree test will install from.
  • Several curated doc lists were already missing creative-tooling before this PR; only the ado-enterprise entries were added to keep the diff on-message.

🤖 Generated with Claude Code

splashthree and others added 2 commits August 7, 2026 19:05
First slice of Azure DevOps repo support (plan: docs/proposals/ado-repo-support-matrix.md).

- profiles/ado-enterprise/ — microsoft-enterprise's stack (C#/.NET 8 + Angular 17 +
  Azure, SOC 2 gates) with platform: azure-devops, so /sdlc-setup composes the
  existing Azure Pipelines CI/CD pack. Purely additive; auto-discovered.
- docs/proposals/ado-repo-support-matrix.md — the folded fix matrix (Folds 0/A-E):
  installer platform-awareness, pack-aware doctor, PR-flow rails, prose sweep,
  keyless Foundry+RBAC gate auth; additive guarantee + platform-switch runbook.
- Profile added to the five curated enumerations (sdlc-setup command, README,
  SKILL.md, docs/commands.md, docs/profiles.md, docs/architecture.md tree).
- New TestOnDiskProfiles guard: every profiles/*/profile.yaml must pass the real
  schema and profile_id must equal the directory name (the compliance-gate lookup
  contract). Future profiles get CI coverage the moment the directory exists.
- Fixed fictional plugin.json profile-registry docs (architecture.md 1.1/1.2,
  profiles.md Step 5): profiles are directory-listing auto-discovered; the real
  .claude-plugin/plugin.json is metadata-only.

Verified: 818 tests pass; fresh-repo e2e drill (init -> harness install -> gates ->
upgrade dry-run: 0 CONFLICT / 0 RETIRED); byte-level diff vs sibling profile clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… (Fold A)

_copy_core now consults stack.ci_cd.platform via _CORE_LAYOUT_BY_PLATFORM:
azure-devops installs drop the GitHub-only payload (workflows/, rulesets,
CODEOWNERS, apply-branch-protection.sh) and redirect the neutral governance
content (rubrics, eval-bypasses, dependency-exceptions ledgers) to
.azuredevops/rails/ — where the ADO pipelines actually read them (fixes the
live bug where <<RUBRIC_DIR>> pointed at a path nothing created).

rails-telemetry.schema.json intentionally stays at .github/: both packs'
telemetry pipelines commit their report to .github/rails-telemetry.json on
purpose (one canonical path so the operator-side fleet collector reads a
mixed GitHub/Azure fleet); the schema stays beside its report.

github-actions and core-only installs fall through to the identity layout —
byte-for-byte unchanged, proven by the untouched enterprise-tree.txt golden.
New: ado-enterprise golden-repo test + tree snapshot, synthetic core-layout
unit tests, upgrade-idempotency coverage. Suite: 834 passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@splashthree splashthree changed the title feat: ado-enterprise profile + Azure DevOps repo support plan (Fold 0) feat: Azure DevOps repo support — profile, plan, platform-aware installer (Folds 0+A, B–D landing) Aug 9, 2026
@splashthree
splashthree marked this pull request as draft August 9, 2026 01:34
splashthree and others added 3 commits August 8, 2026 18:55
installed_platform() reads the manifest's composed pack ids; on
cicd/azure-devops the platform-facing checks follow the platform:

- Tools: require az (+ azure-devops extension), never gh — demanding gh on
  an ADO repo is telling the user to fix a working setup
- Repo secrets: required_variable_groups() reads `- group: NAME` references
  from the installed pipelines (quote-aware — exotic legal names survive;
  <<VARIABLE_GROUP>>/sentinel/template expressions are unfinished setup, not
  missing groups) and checks them via az pipelines variable-group list
- Branch protection: az repos policy list; enforcing = isEnabled AND
  isBlocking (an enabled-but-optional policy is advice, not a gate)
- Residual tokens: .azuredevops/ joined the scan roots — <<GATED_PATHS>> in
  security.yml was invisible before

az hardening from adversarial review: shutil.which resolution (az.cmd on
Windows), cwd=repo so org/project detection reads --repo's remote not the
doctor's CWD, --only-show-errors so az stderr chatter never corrupts the
JSON parse, list-shape guard, TypeError-safe manifest read.

GitHub/core-only installs are byte-identical (verified against the HEAD
doctor on scratch installs: offline+online outputs diff-clean); the gh check
bodies are renamed originals. Existing tests unmodified; +30 beside them.
Suite: 867 passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…iter (Fold C)

- review-gate.{sh,ps1}: `az repos pr create` joins git push / gh pr create as
  a gated trigger (segment-anchored; a mention inside echo/quotes still walks
  free). Shared-payload hardening that also strengthens the GitHub twins,
  stated plainly: leading VAR=value prefixes are stripped before matching
  (AZURE_DEVOPS_EXT_PAT=... az repos pr create is a documented az auth
  pattern and was a bypass — as was FOO=1 git push), and the ps1 twin now
  splits segments on newlines like the sh twin always did (a multi-line
  command with the trigger on a later line walked past it on Windows).
- New ADO pack settings fragment merged into .claude/settings.json:
  read-only az queries allowed (az repos pr SHOW — az has no 'pr view'; the
  adversarial review caught that gh-vocabulary bug after unit tests had
  pinned it), mutating az + configure-branch-policies.sh behind ask,
  .azuredevops/** gated like .github/**. GitHub installs get none of it
  (starter-install test pins the absence).
- pr-writer skill names both platforms (az repos pr create, --labels
  risk:high — flag verified against the live CLI).

Verified: install+upgrade agree byte-for-byte on the merged settings (68/68
IDENTICAL dry-run); GitHub control matches the golden tree exactly; the real
.sh hook drilled against a 14-case trigger table incl. adversarial forms
(pwsh twin runs the same table where pwsh exists). Suite: 886 passed.
Deferred, documented: wrapper/subshell forms (env/nohup/bash -c) remain the
parser's coverage boundary, in parity with git push since day one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…forms (Fold D)

One editorial rule applied everywhere: prose that named only the GitHub
mechanism now names the ADO analogue that already exists. Setup Step 7
offers configure-branch-policies.sh beside apply-branch-protection.sh;
sdlc-doctor.md describes the pack-aware doctor (gh/az); the harness tour
(HARNESS.md, README.md install map, CLAUDE.md.template examples) covers the
.azuredevops/ layout the platform-aware installer actually produces; phases
03/08/09 pair Key Vault+variable groups, Azure Artifacts, ADO Boards; the
close-phase harness audit checks either pipelines home; doctor's
DEV_ENVIRONMENT token owner text goes platform-neutral.

New: "Switching CI platform" runbook in sdlc-upgrade.md — the profile edit →
dry-run → RETIRED/NEW swap report → human deletes retired files → doctor +
shakedown drills flow, clean since Fold A made the core platform-aware.

Also: sdlc-setup.md's stale <<ADO_ORGANIZATION>> references corrected to the
ADO_ORGANIZATION_NOT_SET sentinel the pack actually installs (argv-safe
form, per the pack's own docs). The .github/RAILS.md path is deliberately
unchanged everywhere — the ADO pack overlays that path by design.

Plan doc updated to match reality: folds 0/A–D consolidated in PR MCKRUZ#47 (one
commit per fold), E separate and spike-first; per-fold DONE markers with
landed SHAs. Suite: 886 passed, command-contract lint green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@splashthree splashthree changed the title feat: Azure DevOps repo support — profile, plan, platform-aware installer (Folds 0+A, B–D landing) feat: Azure DevOps repo support — profile, platform-aware installer, pack-aware doctor, PR rails, docs (Folds 0+A–D) Aug 9, 2026
@splashthree splashthree changed the title feat: Azure DevOps repo support — profile, platform-aware installer, pack-aware doctor, PR rails, docs (Folds 0+A–D) feat: Azure DevOps repo support Aug 9, 2026
Windows CI (first run of the new review-gate hook tests) checked out
review-gate.sh with CRLF via autocrlf; bash rejects `set -uo pipefail\r`
and exits 1 before the hook runs — every sh trigger test failed at the
exit-0 assertion. Same class as d67db30, but here the shipped artifact
itself was at risk: a plugin cloned on Windows would install broken hooks
and rails scripts. .gitattributes pins *.sh to LF everywhere; .ps1 stays
platform-default (pwsh is CRLF-tolerant — its 15 Windows tests passed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@splashthree

Copy link
Copy Markdown
Contributor Author

CI note: the harness == kit invariant check is red because Folds C+D touch harness/ — the canonical source lives in intent-driven-development, and the byte-identical mirror is now up as a companion PR there. Merge order: the kit PR first, then this one (the invariant checks out the kit's main). The Windows pytest leg was fixed in 6723ed3 (.gitattributes: CRLF checkout was breaking the bash hooks — a real product bug for Windows-cloned installs, not just a test issue).

The Windows CI leg's `bash` resolves to C:\Windows\System32\bash.exe — the
WSL shim, which with no distro installed exits 1 ("Windows Subsystem for
Linux has no installed distributions") before the hook ever runs; all 17 sh
trigger tests failed on the exit-0 assertion. Git Bash is the bash a real
Windows install executes hooks with, so _bash() finds it explicitly
(ProgramFiles, then the git.exe-relative path) and never falls back to the
shim. Runners now also surface stderr in every assertion so the next
environmental failure names itself instead of reading "got 1".

(The prior .gitattributes fix stands on its own: a CRLF checkout would break
the hooks for real Windows installs regardless of which bash runs them.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.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