fix(policy): unify --policy / --policy-source forms across CLI help and docs#1000
Merged
danielmeppiel merged 2 commits intomicrosoft:mainfrom Apr 28, 2026
Merged
Conversation
…nd docs Establish a single Python constant (POLICY_SOURCE_FORMS_HELP) as the source of truth for the user-facing forms accepted by --policy / --policy-source. Both Click decorators and both cli-commands.md bullets align to it; six lockstep tests pin the relationship so future drift fails CI. Also corrects the discover_policy() docstring, which had been omitting the owner/repo case. Closes microsoft#998 and microsoft#994. microsoft#994 (broken cross-reference to a non-existent 'apm install --policy' flag) is subsumed because the offending line is rewritten to the canonical wording rather than redirected.
danielmeppiel
approved these changes
Apr 28, 2026
This was referenced Apr 29, 2026
danielmeppiel
pushed a commit
that referenced
this pull request
Apr 29, 2026
Promotes [Unreleased] -> [0.11.0] - 2026-04-29 and bumps pyproject.toml + uv.lock to 0.11.0. Version-bump rationale: 0.11.0 (minor bump) chosen over 0.10.1 because this release ships one BREAKING removal (`apm marketplace build` -> exits 2, use `apm pack`) plus several net-new features (Dev Container Feature, Codex project-scoped MCP, `marketplace:` block in apm.yml, `apm pack` unification, multi-org `apps[]`). Strict semver in 0.x: minor for features-with-break, patch only for bugfixes. Milestone admin (done out-of-band): - Renamed milestone #8 `0.10.1` -> `0.11.0` - Created milestone #9 `0.12.0` as next-up bucket - Moved 43 open items (42 issues + 1 open PR #999) from `0.11.0` -> `0.12.0` - 6 closed items stay in `0.11.0` PRs shipping in 0.11.0 (22 commits since v0.10.0): User-facing features: - #1042/#722 `apm pack` unifies bundle + marketplace.json (BREAKING: `apm marketplace build` removed) - #1038 `marketplace:` block in apm.yml + `apm marketplace migrate` - #803 /#502 Codex project-scoped MCP (`.codex/config.toml`) + user-scope primitives - #861 Dev Container Feature `ghcr.io/microsoft/apm/apm-cli` - #982/#984 shared/apm.md `apps:` array for cross-org private packages - #820 `target:` in apm.yml validates at parse time - #1032 `apm marketplace add` honors manifest.name (Claude Code parity) - #1000/#998/#994 unified `--policy` / `--policy-source` accepted forms User-facing fixes: - #1015 ADO Entra ID auth + `apm install --update` pre-flight abort - #1019/#1020 GEMINI.md only created when target requested - #1008 marketplace producer respects GITHUB_HOST + multi-host URL forms - #1018 POSIX paths in auto-discovery output (Windows compat) - #996 drop stray 'specify' from generated file footer Maintainer tooling: - #1043 NOTICE.md per CELA template - #1045/#1044 NOTICE drift gate + license-policy gate in CI - #1033 shared/apm.md `[a b]` import-input repair (gh-aw#29076 paper-cut) - #1030 panel workflows skip-don't-fail on unmatched labels; gh-aw v0.71.1 - #1026 shared/apm.md recompiled to apm-action v1.5.0 + bundles-file - #1022 review-panel: true fan-out + binary verdict + label automation - #918 complexity audit + benchmarks suite - #1002 CodeQL clear-text-storage false-positive resolved (token -> placeholder) Files changed: - pyproject.toml: 0.10.0 -> 0.11.0 - uv.lock: regenerated (version field only) - CHANGELOG.md: [Unreleased] promoted to [0.11.0] - 2026-04-29 NOTICE drift check passes against the bumped lockfile. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
danielmeppiel
pushed a commit
that referenced
this pull request
Apr 29, 2026
Promotes [Unreleased] -> [0.11.0] - 2026-04-29 and bumps pyproject.toml + uv.lock to 0.11.0. Version-bump rationale: 0.11.0 (minor bump) chosen over 0.10.1 because this release ships one BREAKING removal (`apm marketplace build` -> exits 2, use `apm pack`) plus several net-new features (Dev Container Feature, Codex project-scoped MCP, `marketplace:` block in apm.yml, `apm pack` unification, multi-org `apps[]`). Strict semver in 0.x: minor for features-with-break, patch only for bugfixes. Milestone admin (done out-of-band): - Renamed milestone #8 `0.10.1` -> `0.11.0` - Created milestone #9 `0.12.0` as next-up bucket - Moved 43 open items (42 issues + 1 open PR #999) from `0.11.0` -> `0.12.0` - 6 closed items stay in `0.11.0` PRs shipping in 0.11.0 (22 commits since v0.10.0): User-facing features: - #1042/#722 `apm pack` unifies bundle + marketplace.json (BREAKING: `apm marketplace build` removed) - #1038 `marketplace:` block in apm.yml + `apm marketplace migrate` - #803 /#502 Codex project-scoped MCP (`.codex/config.toml`) + user-scope primitives - #861 Dev Container Feature `ghcr.io/microsoft/apm/apm-cli` - #982/#984 shared/apm.md `apps:` array for cross-org private packages - #820 `target:` in apm.yml validates at parse time - #1032 `apm marketplace add` honors manifest.name (Claude Code parity) - #1000/#998/#994 unified `--policy` / `--policy-source` accepted forms User-facing fixes: - #1015 ADO Entra ID auth + `apm install --update` pre-flight abort - #1019/#1020 GEMINI.md only created when target requested - #1008 marketplace producer respects GITHUB_HOST + multi-host URL forms - #1018 POSIX paths in auto-discovery output (Windows compat) - #996 drop stray 'specify' from generated file footer Maintainer tooling: - #1043 NOTICE.md per CELA template - #1045/#1044 NOTICE drift gate + license-policy gate in CI - #1033 shared/apm.md `[a b]` import-input repair (gh-aw#29076 paper-cut) - #1030 panel workflows skip-don't-fail on unmatched labels; gh-aw v0.71.1 - #1026 shared/apm.md recompiled to apm-action v1.5.0 + bundles-file - #1022 review-panel: true fan-out + binary verdict + label automation - #918 complexity audit + benchmarks suite - #1002 CodeQL clear-text-storage false-positive resolved (token -> placeholder) Files changed: - pyproject.toml: 0.10.0 -> 0.11.0 - uv.lock: regenerated (version field only) - CHANGELOG.md: [Unreleased] promoted to [0.11.0] - 2026-04-29 NOTICE drift check passes against the bumped lockfile. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
danielmeppiel
added a commit
that referenced
this pull request
Apr 29, 2026
* chore(release): cut 0.11.0 Promotes [Unreleased] -> [0.11.0] - 2026-04-29 and bumps pyproject.toml + uv.lock to 0.11.0. Version-bump rationale: 0.11.0 (minor bump) chosen over 0.10.1 because this release ships one BREAKING removal (`apm marketplace build` -> exits 2, use `apm pack`) plus several net-new features (Dev Container Feature, Codex project-scoped MCP, `marketplace:` block in apm.yml, `apm pack` unification, multi-org `apps[]`). Strict semver in 0.x: minor for features-with-break, patch only for bugfixes. Milestone admin (done out-of-band): - Renamed milestone #8 `0.10.1` -> `0.11.0` - Created milestone #9 `0.12.0` as next-up bucket - Moved 43 open items (42 issues + 1 open PR #999) from `0.11.0` -> `0.12.0` - 6 closed items stay in `0.11.0` PRs shipping in 0.11.0 (22 commits since v0.10.0): User-facing features: - #1042/#722 `apm pack` unifies bundle + marketplace.json (BREAKING: `apm marketplace build` removed) - #1038 `marketplace:` block in apm.yml + `apm marketplace migrate` - #803 /#502 Codex project-scoped MCP (`.codex/config.toml`) + user-scope primitives - #861 Dev Container Feature `ghcr.io/microsoft/apm/apm-cli` - #982/#984 shared/apm.md `apps:` array for cross-org private packages - #820 `target:` in apm.yml validates at parse time - #1032 `apm marketplace add` honors manifest.name (Claude Code parity) - #1000/#998/#994 unified `--policy` / `--policy-source` accepted forms User-facing fixes: - #1015 ADO Entra ID auth + `apm install --update` pre-flight abort - #1019/#1020 GEMINI.md only created when target requested - #1008 marketplace producer respects GITHUB_HOST + multi-host URL forms - #1018 POSIX paths in auto-discovery output (Windows compat) - #996 drop stray 'specify' from generated file footer Maintainer tooling: - #1043 NOTICE.md per CELA template - #1045/#1044 NOTICE drift gate + license-policy gate in CI - #1033 shared/apm.md `[a b]` import-input repair (gh-aw#29076 paper-cut) - #1030 panel workflows skip-don't-fail on unmatched labels; gh-aw v0.71.1 - #1026 shared/apm.md recompiled to apm-action v1.5.0 + bundles-file - #1022 review-panel: true fan-out + binary verdict + label automation - #918 complexity audit + benchmarks suite - #1002 CodeQL clear-text-storage false-positive resolved (token -> placeholder) Files changed: - pyproject.toml: 0.10.0 -> 0.11.0 - uv.lock: regenerated (version field only) - CHANGELOG.md: [Unreleased] promoted to [0.11.0] - 2026-04-29 NOTICE drift check passes against the bumped lockfile. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(changelog): tighten 0.11.0 entries to lead with user impact Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(changelog): move Dev Container Feature to Maintainer tooling (not yet published) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(changelog): de-dupe within 0.11.0 (combine #722 Removed bullets, drop #820 Fixed pointer) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
TL;DR
The "policy source" format accepted by
apm audit --policyandapm policy status --policy-sourceis documented inconsistently across four locations — two Click help texts and two docs sections, with the parser supportingowner/reposhorthand that is missing from three of the four. This PR establishes a single Python constant as the source of truth, threads it through both Click decorators, aligns the docs, and adds six lockstep regression tests so future drift fails CI rather than going unnoticed for months.Note
Closes #998 and #994. #994 reported a broken cross-reference (
Same shape as 'apm install --policy'— a flag that does not exist); investigation revealed #998, the underlying drift. Both are fixed in one PR because they touch the same line of code; splitting would force the same line to be rewritten twice with no benefit.Problem (WHY)
policy.py:288lists 4 forms ('org', file path,owner/repo, https URL);audit.py:440lists 3;cli-commands.md:435lists 3;cli-commands.md:523lists 3 and points at a non-existent flag.owner/repo. Users reading the CLI reference cannot discover thatapm policy status --policy-source contoso/.githubis valid input, even though the parser accepts it (proven bytest_override_owner_repo).cli-commands.md:523saysSame shape as \apm install --policy`, butapm installhas no--policyflag (only--no-policy`).discovery.py:543-547itself omits theowner/repocase, so even the in-code spec drifted.Why these matter: the per-flag accepted-forms list is a contract the CLI advertises and the parser enforces; today they describe the same contract differently in four places, which violates the discoverability guarantee the docs imply.
Approach (WHAT)
POLICY_SOURCE_FORMS_HELPin a new lightweight module (apm_cli/policy/_help_text.py) co-located with the parser.apm audit --policyandapm policy status --policy-sourceClick decorators import and embed the constant via f-string.cli-commands.mdbullets are rewritten to the same canonical wording — this also subsumes #994, since the broken cross-reference is rewritten away rather than redirected to another command.discovery.pyis corrected to list all five resolution branches (it was missingowner/repo) and points readers to the constant as the user-facing rendering.tests/unit/policy/test_help_consistency.py) pin the constant, both Click helps, both docs bullets, and the absence ofapm install --policyreferences docs-tree-wide.Implementation (HOW)
src/apm_cli/policy/_help_text.py(new) — holdsPOLICY_SOURCE_FORMS_HELP. Tiny, zero imports, lives next to the parser so a parser-behavior change forces a help-text update in the same diff.src/apm_cli/commands/audit.py— imports the constant, uses f-string interpolation in the--policyClick help so the command-specific suffix (Used with --ci ... [experimental]) is preserved.src/apm_cli/commands/policy.py— imports the constant, replaces the previous (already-most-accurate) help string withf"Override discovery. {POLICY_SOURCE_FORMS_HELP}".src/apm_cli/policy/discovery.py— expands thediscover_policy()docstring from 4 cases to 5 (the previous text omittedowner/repo) and cross-references the constant.docs/src/content/docs/reference/cli-commands.md— the two affected bullets (lines 435 and 523) are rewritten to canonical wording mirroring the constant, using markdown backticks for inline forms.tests/unit/policy/test_help_consistency.py(new) — six lockstep tests; mutation-tested to confirm each catches a distinct drift mode.Trade-offs
host/owner/repoform. The parser supports it via_fetch_from_repobut no user-facing surface advertises it today. Promoting an internal capability to public API is a product decision, not a docs fix. Conservative call: keep the user-facing list at four forms; readers needing explicit-host can use thehttps://URL form.enterprise/policy-reference.md. That page already lists 4 forms correctly (different wording, same information). Pursuing byte-identical SSOT across audience-distinct docs would expand scope and trade reader-friendly prose for build-system parity.discover_policy(). Behavior is unchanged; only the docstring was corrected and a cross-reference to the constant added. The 507 unit tests intests/unit/policy/pass unchanged.Benefits
owner/reposhorthand.--policyand--policy-sourceusers can now find this form from any single doc page or--helpinvocation.Validation
apm audit --help(relevant fragment):apm policy status --help(relevant fragment):Lockstep regression tests:
Aggregate regression on all touched code (563 tests)
The 26 failures observed in
tests/unit/outside this set are pre-existing onmain(marketplace / install / cowork / config — none touched by this PR), confirmed by stashing the changes and rerunning the same selection on the parent commit.Mutation testing performed during review
Each mutation was applied locally, the relevant test was run, then the mutation was reverted.
'owner/repo'fromPOLICY_SOURCE_FORMS_HELPaudit.pyhelp with hand-written string (bypass constant)apm install --policyreference ingovernance-guide.md(a different docs page)owner/repofromcli-commands.md:523bulletHow to test
pytest tests/unit/policy/test_help_consistency.py -v— expect 6 passes.apm audit --help— expect the--policyline to mentionowner/repo,https://, andlocal file path.apm policy status --help— expect the--policy-sourceline to mention all four canonical forms.grep -r "apm install --policy" docs/— expect no matches (closes [cli-consistency] CLI Consistency Report — 2026-04-27 #994).apm policy status --policy-source contoso/.github— expect the parser to attempt fetch (not a parse-level rejection), confirming the newly-documentedowner/repoform actually works.