ci: dogfood apm audit --ci and integration-drift gate (closes #883)#885
Merged
danielmeppiel merged 2 commits intomainfrom Apr 23, 2026
Merged
ci: dogfood apm audit --ci and integration-drift gate (closes #883)#885danielmeppiel merged 2 commits intomainfrom
danielmeppiel merged 2 commits intomainfrom
Conversation
Adds an APM Self-Check job to ci.yml that runs both CI gates we ship
to users via microsoft/apm-action@v1:
- Gate A (consumer-side): apm audit --ci -- 6 baseline lockfile /
install fidelity checks.
- Gate B (producer-side): regeneration drift -- fails if anyone
edited a regenerated file under .github/ without updating the
canonical .apm/ source.
Wires APM Self-Check into merge-gate.yml's EXPECTED_CHECKS so the
single-authority gate aggregator waits on it before merge.
Includes the precursor regeneration that #883 called out:
.github/agents/auth-expert.agent.md and .github/skills/auth/SKILL.md
were stale vs canonical .apm/ since #856. Bundling the regen into
this PR makes the gate green on first run; a separate precursor PR
would have shipped a self-DOSing gate for one merge cycle.
Adds a 'We dogfood this' callout in integrations/ci-cd.md pointing
at our own ci.yml as the reference implementation of the documented
'Verify deployed primitives' pattern.
Closes #883.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds PR-time dogfooding for APM’s published CI gates by introducing an APM Self-Check job (via microsoft/apm-action@v1) and making merge-gate.yml wait on it, plus regenerates a couple of .github/ auth primitives and updates docs/changelog to reflect the new gate.
Changes:
- Add
APM Self-Checkjob to.github/workflows/ci.ymlto runapm audit --ciplus an integration-driftgit status --porcelaingate. - Update
.github/workflows/merge-gate.ymlto includeAPM Self-CheckinEXPECTED_CHECKS. - Update docs + regenerated auth agent/skill content, and add a changelog entry for the new CI gate.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/ci.yml |
Adds APM Self-Check job that runs apm audit --ci and a drift check after apm install via microsoft/apm-action@v1. |
.github/workflows/merge-gate.yml |
Extends EXPECTED_CHECKS so the gate aggregator waits for the new job. |
docs/src/content/docs/integrations/ci-cd.md |
Adds a “We dogfood this” callout pointing to the repo’s own CI job. |
CHANGELOG.md |
Adds an Unreleased entry describing the new CI self-check gate. |
.github/skills/auth/SKILL.md |
Regenerated auth skill content describing ADO bearer token auth (and related diagnostics). |
.github/agents/auth-expert.agent.md |
Regenerated auth agent content noting ADO AAD bearer-token support and precedence. |
Copilot's findings
- Files reviewed: 6/6 changed files
- Comments generated: 4
Four issues raised by Copilot reviewer; the auth-primitive fixes are
applied to canonical .apm/ sources so they survive future
'apm install --target copilot' regeneration cycles (the previous
deployed-only fixes would have been clobbered by the new
APM Self-Check drift gate this PR introduces).
- .apm/agents/auth-expert.agent.md: replace em dashes ('--') and
arrows ('->') with ASCII; .github/ mirror regenerated.
- .apm/skills/auth/SKILL.md: correct the token_manager.py constant
reference. ADO_APM_PAT is an env var name (string), not a module
constant; only ADO_BEARER_SOURCE = 'AAD_BEARER_AZ_CLI' is defined
on GitHubTokenManager.
- CHANGELOG.md: compress to single bullet ending with (#885) per
Keep-a-Changelog convention; issue ref Closes #883 stays in PR body.
- docs/integrations/ci-cd.md: reword 'we dogfood this' callout to
reference-implementation framing; previous wording overclaimed
('on every PR', 'shown above') given paths-ignore: ['docs/**']
excludes docs-only PRs and the page only shows the drift snippet.
apm audit --ci passes 6/6 locally.
.apm/ <-> .github/ mirror parity verified via diff -q.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Apr 23, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ci: dogfood
apm audit --ciand integration-drift gateTL;DR
microsoft/apmships two CI gates as features and documents them publicly, but never ran them on its own pipeline — the embarrassment that PRs #874, #875, and #878 made unavoidable. This PR adds anAPM Self-Checkjob toci.ymlthat runs both viamicrosoft/apm-action@v1, wires it intomerge-gate.yml'sEXPECTED_CHECKS, and bundles the precursor regeneration the gate would otherwise have flagged on first run. Closes #883.Note
The bundled regen is exactly the drift inventory #883 called out:
.github/agents/auth-expert.agent.mdand.github/skills/auth/SKILL.md, both stale vs.apm/since #856's ADO bearer-token work. The third drift item (pr-description-skill) is owned by PR #884 and intentionally untouched here.Problem (WHY)
apm audit --ciand the integration-drift recipe atintegrations/ci-cd.md"Verify Deployed Primitives" and run neither on this repo. Self-inflicted credibility hole for a project whose value prop is "treat governance as code"..apm/instructions/cicd.instructions.mdfrom.github/instructions/cicd.instructions.mdbecause the maintainer edited the regenerated output. The nextapm installwould have overwritten the new content with the stale source.maintoday:.github/agents/auth-expert.agent.mdand.github/skills/auth/SKILL.mdare stale vs canonical.apm/(provenance: feat(auth): Azure DevOps authentication via Entra ID (AAD) bearer tokens #856 updated.apm/only). Any honest first run of the gate fails on these — which is precisely why the issue called for a precursor PR.Why these matter: shipping a CI gate we don't run ourselves violates "agents pattern-match well against concrete structures" — when the canonical reference repo doesn't match what we tell users to do, the recommendation stops being credible. And accepting silent producer-side drift violates "Grounding outputs in deterministic tool execution transforms probabilistic generation into verifiable action." —
apm installis the deterministic step; bypassing it makes the regenerated tree probabilistic relative to source.Approach (WHAT)
microsoft/apm-action@v1(no secrets needed → fits Tier 1)..github/regen into this PR rather than ship a separate sequencing PR first.APM Self-Checktomerge-gate.yml'sEXPECTED_CHECKSso the single-authority gate aggregator waits on it.merge-gate.yml:7-11integrations/ci-cd.mdpointing at our ownci.yml.Implementation (HOW)
.github/workflows/ci.yml— new top-levelapm-self-checkjob mirroring the issue's spec verbatim. Usesmicrosoft/apm-action@v1(auto-detects target from existing.github/), then runsapm audit --ci(Gate A) and agit status --porcelain -- .github/ .claude/ .cursor/ .opencode/check (Gate B). Permissions scoped tocontents: read. Comments preserved from the issue spec to keep the rationale on-disk for future readers..github/workflows/merge-gate.yml— appendAPM Self-Checkto the comma-separatedEXPECTED_CHECKSenv var (now'Build & Test (Linux),APM Self-Check'); update the inline comment to list both checks. Branch protection requires onlygate, so no ruleset edit is needed..github/agents/auth-expert.agent.md,.github/skills/auth/SKILL.md— pure regenerated output ofapm installagainst current canonical.apm/. Not hand-edited. Diff is exactly the ADO bearer-token content from feat(auth): Azure DevOps authentication via Entra ID (AAD) bearer tokens #856 propagating into the deployed tree.docs/src/content/docs/integrations/ci-cd.md— three-line:::tip[We dogfood this]callout right after the existing "Verify Deployed Primitives" snippet, pointing atmicrosoft/apm's ownci.yml.CHANGELOG.md— single Unreleased entry under### Addedsummarising the gate + bundled regen and citing ci: dogfood apm audit --ci and integration-drift checks in microsoft/apm pipeline #883.Diagrams
Legend: the dogfooding loop — canonical authoring lives in
.apm/,apm installregenerates the integration tree, and the self-check job re-runs install in CI to detect any hand-edit that bypassed the canonical source.flowchart LR A[".apm/ canonical source"] -->|"author edits here"| B["apm install (local)"] B -->|"regenerates"| C[".github/ integration tree"] C -->|"committed to PR"| D["PR opened"] D --> E["APM Self-Check (CI)"] E -->|"microsoft/apm-action@v1<br/>re-runs apm install"| F{"git status --porcelain<br/>.github/ .claude/ .cursor/ .opencode/"} F -->|"clean"| G["Gate B passes"] F -->|"dirty"| H["Gate B fails:<br/>'Run apm install and commit'"] E --> I["apm audit --ci"] I -->|"6/6 baseline checks"| J["Gate A passes"] I -->|"any check fails"| K["Gate A fails"]Legend: producer-side vs consumer-side gates catch different failure modes; both are needed because they have disjoint blast radii.
flowchart TB subgraph CONSUMER["Gate A — apm audit --ci (consumer-side)"] A1["lockfile-exists"] A2["ref-consistency"] A3["deployed-files-present"] A4["no-orphaned-packages"] A5["config-consistency"] A6["content-integrity (Unicode)"] end subgraph PRODUCER["Gate B — regeneration drift (producer-side)"] B1["Run apm install"] B2["git status --porcelain<br/>on integration dirs"] B1 --> B2 end X1["Edited apm.yml<br/>without re-install"] --> A2 X2["Deleted a deployed file"] --> A3 X3["Hidden Unicode in package"] --> A6 Y1["Hand-edit to .github/<br/>without updating .apm/"] --> B2 Y2["Stale .github/ from older<br/>upstream update"] --> B2Trade-offs
mainso the gate isn't enforced; opening the gate-wiring PR right after is the first time it fires, and it has nothing to assert against beyond what we already manually verified). Bundling keeps the change atomic and verifiable from a single diff. Risk: the regen diff is reviewed alongside CI plumbing instead of in isolation — mitigated by the diff being two files, both pure mechanical regen output.microsoft/apm-action@v1unpinned vs SHA-pinned. Chose the floating major. Per the issue spec: "apm-versionis intentionally unpinned. If a future change requires a specific CLI behavior, pin then; for now we want to catch breakage on latest stable as part of release readiness.". Trade: a malicious tag retag onmicrosoft/apm-actionwould execute in CI; mitigated because the action is in our own org and Tier 1 has no secrets to exfiltrate.APM Self-Check(with space) vsapm-self-check(kebab). Chose the spaced display name to match the existing convention inEXPECTED_CHECKS('Build & Test (Linux)'already uses spaces and capitals). Branch protection matches on the rendered check-run name, not the job key, so this is consistent with the documented pattern inmerge-gate.yml's header comment. The kebab form survives as the YAML job key (apm-self-check).GH_CLI_PAT,ADO_APM_PAT, orGH_MODELS_PAT— so Tier 1 is the right home. Catching producer-side drift at PR-time is also where the signal is highest; surfacing it only in the merge queue would let drift accumulate on open PRs.Benefits
.apm/and.github/for the same file; Gate B fails any of them on first push.apm audit --ciruns on every PR, exercising the documented 6/6 baseline (lockfile-exists,ref-consistency,deployed-files-present,no-orphaned-packages,config-consistency,content-integrity).ci.ymlthe canonical example formicrosoft/apm-action@v1consumers — no separate template to maintain.permissions:escalation beyondcontents: read.Validation
apm audit --ci(run locally on the branch — this is the gate validating itself):apm install(verifies Gate B is clean post-regen):After install:
git status --porcelain -- .github/ .claude/ .cursor/ .opencode/returns empty (gate-green).Full diff stat against origin/main
How to test
APM Self-Checkreports green alongsideBuild & Test (Linux).merge-gate.yml'sgatejob waits onAPM Self-Check(poll log line[merge-gate]mentions both checks)..github/instructions/cicd.instructions.mdwithout touching.apm/.APM Self-Checkshould fail with the diff visible in the log and the messageAPM integration files are out of date.apm.ymlwithout runningapm install.APM Self-Checkshould fail with aref-consistencyviolation fromapm audit --ci.docs/src/content/docs/integrations/ci-cd.mdlocally; the new:::tip[We dogfood this]callout appears under "Verify Deployed Primitives" linking tomicrosoft/apm'sci.yml.References
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com