feat: dogfood APM on microsoft/apm -- .apm/ primitives, compile, --check gate#842
feat: dogfood APM on microsoft/apm -- .apm/ primitives, compile, --check gate#842sergio-sisternes-epam wants to merge 10 commits intomicrosoft:mainfrom
Conversation
e4d1001 to
1ccc60d
Compare
1ccc60d to
13dcdbc
Compare
…istic sort base_dir Two foundational fixes required before apm compile --check can enforce a strict stdout contract and round-trip determinism: 1. context_optimizer.py: replace bare print() with logger.debug(). Timing output is opt-in via --verbose/DEBUG level and must never leak to default stdout. 2. template_builder.py: build_conditional_sections() now takes a required base_dir parameter. Previously Path.cwd() was used in the sort key and relative-path display, making compile output depend on the user's current working directory. Sort order must be deterministic regardless of where apm is invoked from. Updated the single caller in agents_compiler.py to pass self.base_dir. Added unit tests covering logger routing (caplog vs capsys) and deterministic sort behaviour. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The apm compile --check flag (landing in a later commit) will run in Tier 1 CI and read user-authored markdown from .apm/ primitives. _resolve_path previously accepted absolute paths unguarded and performed naive base_path/path joins with no traversal or symlink-escape checks. This is the first path_security import into the compilation/ subsystem. New contract (3-gate fail-closed): 1. Absolute paths are rejected outright (return None). 2. validate_path_segments rejects '..' at parse time; './' is allowed since it is legitimate in markdown links (allow_current_dir=True). 3. ensure_path_within resolves symlinks and asserts containment after the join; the resolved path is returned on success. PathTraversalError / OSError / ValueError all map to None, which the caller surfaces as 'Referenced file not found' via the existing validate_link_targets flow. Three other pre-existing path-traversal gaps in the compilation subsystem (apm.yml output_path, applyTo patterns, full path_security integration across compile) are explicitly deferred to a labelled security follow-up issue filed pre-merge. Supply-chain-security-expert review: 0 blockers, 0 majors, 3 minors (all non-exploitable edge cases filed under the follow-up). Tests: TestResolvePathSecurity covers absolute rejection, traversal at depth, current-directory allowance, symlink escape, and an integration check via validate_link_targets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…instructions (microsoft#792) Closes microsoft#792. Instructions with empty or missing applyTo frontmatter were previously silently dropped by both the distributed compiler and the single-file template builder. They now aggregate into .github/copilot-instructions.md for the vscode-family targets (vscode, copilot, agents, opencode, codex, all, minimal). Design (approved by python-architect pre-implementation): - New AgentsCompiler._compile_copilot_instructions() sibling emitter called between _compile_agents_md and _compile_claude_md in the target-routing block. Returns Optional[CompilationResult]; None when no root-scoped instructions exist so no empty file is written and _merge_results stays clean. - New should_compile_copilot_instructions() predicate in target_detection so the gate can diverge from should_compile_agents_md later if needed. - New build_root_sections() helper in template_builder mirrors build_conditional_sections but without pattern headers; filters empty-applyTo instructions, deterministic sort by portable_relpath(path, base_dir). - Hardcoded path .github/copilot-instructions.md (GitHub Copilot convention); no new CompilationConfig field needed. - Prefixed stat key 'copilot_instructions_written' to avoid _merge_results collisions. Also standardises the generated-file header across all three emitters. New constant GENERATED_HEADER in compilation/constants.py: Replaces the inconsistent AGENTS.md ('from distributed .apm/ primitives'), CLAUDE.md ('Generated by APM CLI') and template-builder variants. Updates the target-description strings in target_detection so apm init / status output reflects the new file. Tests: new tests/unit/compilation/test_copilot_instructions.py with 12 cases covering mixed fixture, empty case, deterministic sort, round-trip stability, header presence, source attribution, dry-run mode, target gating, and an integration test asserting both AGENTS.md and copilot-instructions.md are produced with the correct content split. Existing tests updated for the header standardisation. Full suite: 4804 passed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a CI-friendly --check mode to `apm compile` that compares the expected compiler output against on-disk generated files and exits: 0 – all outputs match, 1 – drift or stale files, 2 – unrecoverable. Implementation highlights: - New CATEGORY_DRIFT diagnostic level with drift() / drift_count - AgentsCompiler.preview_all_outputs() dry-runs the full pipeline and returns Dict[Path, str] without writing to disk - _run_check() / _render_drift_report() in the CLI compare previews to disk, detect stale well-known outputs, and emit a concise report - --check implies --local-only and is mutually exclusive with --validate, --watch, --dry-run, --single-agents, --clean - Remove 'No applyTo pattern specified' validation warning – root-scoped instructions are now first-class primitives Co-authored-by: Claude <noreply@anthropic.com>
Creates the first APM manifest for microsoft/apm itself and ports all
26 existing agent primitives from .github/** into .apm/:
.apm/instructions/ (9) - 8 copied from .github/instructions/ plus
new contributing.instructions.md aggregating
.github/copilot-instructions.md as a
root-scoped (applyTo-less) instruction.
.apm/agents/ (10) - byte-identical copies of .github/agents/.
.apm/skills/ (8) - byte-identical copies of .github/skills/.
This commit adds sources only; it does NOT regenerate .github/** outputs.
apm compile --check now reports drift for every .github/** file, which
the next commit resolves by running `apm compile` for real.
Refs microsoft#695, microsoft#792.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Removes legacy .github/instructions/ and .github/agents/ source trees (ported to .apm/ in the previous commit) and regenerates all agent-tool outputs from .apm/ primitives: - Root AGENTS.md and CLAUDE.md (aggregated) - Distributed AGENTS.md and CLAUDE.md in .github/, docs/src/, src/apm_cli/, src/apm_cli/integration/, tests/ - .github/copilot-instructions.md (root-scoped instructions) Adds compilation.exclude patterns to apm.yml to scope discovery to first-party primitives (excludes tests/, templates/, packages/, build/, docs/node_modules/). Marks generated outputs as linguist-generated in .gitattributes so GitHub's diff views collapse them by default and language stats exclude them. Removes AGENTS.md from .gitignore since it is now a committed compile artifact. Closes microsoft#695, closes microsoft#792. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
13dcdbc to
b046eea
Compare
Runs 'apm compile --check' on every PR and merge_group event to ensure AGENTS.md, CLAUDE.md, and .github/copilot-instructions.md stay in sync with .apm/ primitives. Read-only check: exit 0 when outputs match, exit 1 on drift. The error message directs contributors to run 'apm compile' locally and commit the regenerated outputs. Part of the microsoft#695 / microsoft#792 dogfooding PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- CONTRIBUTING.md: new "Recompiling agent outputs" section explaining .apm/ is source of truth and the compile workflow - docs/.../cli-commands.md: document apm compile --check flag and exit-code contract - docs/.../manifest-schema.md: document compilation.exclude patterns - CHANGELOG.md: entries under [Unreleased] for --check, copilot- instructions compile target, root-scoped instructions, dogfood switch, and link_resolver containment fix README callout proposal written to session files for user approval (per doc-sync rule 2). Part of the microsoft#695 / microsoft#792 dogfooding PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
APM uses APM to manage its own agent primitives. The new section points readers at the .apm/ source tree, the apm compile workflow, and the CI gate -- linking to CONTRIBUTING.md for the full procedure. Part of the microsoft#695 / microsoft#792 dogfooding PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Compiled outputs fall into two groups:
- GitHub-hosted consumers (Copilot in PR/chat, Agentic Workflows, Cloud Agents)
read AGENTS.md and .github/** directly from the repo -- no build step runs
on their side, so we MUST commit these files.
- Claude Code runs exclusively on a developer's machine. Contributors can
regenerate CLAUDE.md locally via apm compile.
This commit implements that split:
- .gitignore: gitignore CLAUDE.md / **/CLAUDE.md (with exceptions for template
fixtures, docs-site pages, and test fixtures).
- Untrack the 5 previously-tracked CLAUDE.md files.
- .gitattributes: drop CLAUDE.md linguist-generated entries (no longer tracked);
keep AGENTS.md and copilot-instructions.md markers.
- .github/workflows/ci.yml: scope the drift gate to 'apm compile -t copilot
--check' so CI only asserts sync on the outputs we actually commit.
- CONTRIBUTING.md / README.md / cli-commands.md: document the policy
explicitly ('pre-built for GitHub Copilot; other platforms run apm compile
on checkout') including a note on how local -t copilot --check interacts
with a full-target local compile.
- CHANGELOG.md: clarify the Unreleased dogfood entry.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
8dfab45 to
0bab40e
Compare
There was a problem hiding this comment.
Pull request overview
Dogfoods APM in microsoft/apm by moving agent primitives into .apm/, extending apm compile to emit Copilot-native root instructions, and adding a CI drift gate (apm compile --check) to ensure generated outputs stay in sync.
Changes:
- Added
apm compile --checkverification mode and wired it into Tier 1 CI. - Added
.github/copilot-instructions.mdemission from root-scoped instructions (emptyapplyTo). - Migrated repo primitives to
.apm/and regenerated committed outputs; updated docs/manifest schema/CLI docs accordingly.
Reviewed changes
Copilot reviewed 56 out of 58 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_diagnostics.py | Adds drift diagnostic category coverage in tests. |
| tests/unit/primitives/test_primitives.py | Updates instruction validation expectations for empty applyTo. |
| tests/unit/core/test_target_detection.py | Adds target gate tests for copilot-instructions emission + updates descriptions. |
| tests/unit/compilation/test_template_builder.py | New tests for deterministic sort behavior with explicit base_dir. |
| tests/unit/compilation/test_preview_outputs.py | New tests for preview_all_outputs() behavior. |
| tests/unit/compilation/test_link_resolver.py | Adds security/containment tests for _resolve_path + link validation. |
| tests/unit/compilation/test_copilot_instructions.py | New unit/integration tests for .github/copilot-instructions.md compilation. |
| tests/unit/compilation/test_context_optimizer.py | Verifies timing output routes through logger (not stdout). |
| tests/unit/compilation/test_compile_target_flag.py | Updates CLI behavior tests: no warning for empty applyTo. |
| tests/unit/compilation/test_compilation.py | Updates compilation tests for new build_conditional_sections signature and applyTo behavior. |
| tests/unit/compilation/test_claude_formatter.py | Switches CLAUDE.md header assertion to unified GENERATED_HEADER. |
| tests/unit/commands/compile/test_check_flag.py | New tests for apm compile --check exit codes and drift reporting. |
| tests/unit/commands/compile/init.py | Package init for compile command tests. |
| tests/AGENTS.md | Regenerated output for tests scope. |
| src/apm_cli/utils/diagnostics.py | Adds CATEGORY_DRIFT, collector API for drift, and ordering. |
| src/apm_cli/utils/init.py | Re-exports CATEGORY_DRIFT. |
| src/apm_cli/primitives/models.py | Removes “missing applyTo” validation error (root-scoped is valid). |
| src/apm_cli/integration/AGENTS.md | Regenerated output for integrator instructions. |
| src/apm_cli/core/target_detection.py | Adds should_compile_copilot_instructions() gate and updates target descriptions. |
| src/apm_cli/compilation/template_builder.py | Makes conditional section sorting deterministic via base_dir; adds root section builder; unifies header. |
| src/apm_cli/compilation/link_resolver.py | Hardens _resolve_path with traversal + containment checks via path_security guards. |
| src/apm_cli/compilation/distributed_compiler.py | Unifies generated header for distributed AGENTS.md output. |
| src/apm_cli/compilation/context_optimizer.py | Routes timing output through logger instead of print(). |
| src/apm_cli/compilation/constants.py | Introduces GENERATED_HEADER constant. |
| src/apm_cli/compilation/claude_formatter.py | Unifies CLAUDE.md generated header. |
| src/apm_cli/compilation/agents_compiler.py | Adds copilot-instructions emitter + preview_all_outputs() for --check. |
| src/apm_cli/commands/compile/cli.py | Implements --check mode, drift report rendering, and CI-friendly exit codes. |
| src/apm_cli/AGENTS.md | Regenerated output for CLI instructions. |
| docs/src/content/docs/reference/manifest-schema.md | Documents compilation.exclude in manifest schema reference. |
| docs/src/content/docs/reference/cli-commands.md | Documents apm compile --check contract and exit codes. |
| docs/src/CLAUDE.md | Adds generated CLAUDE.md under docs tree. |
| docs/src/AGENTS.md | Adds generated AGENTS.md under docs tree. |
| apm.yml | Defines repo as an APM project (name: apm-cli, target: all, compilation.exclude). |
| README.md | Adds “Dogfooding” section describing compile-based workflow + CI gate. |
| CONTRIBUTING.md | Documents .apm/ source-of-truth and regeneration workflow for contributors. |
| CHANGELOG.md | Adds Unreleased entries for --check, copilot-instructions emission, and related fixes. |
| AGENTS.md | Adds generated repo-root AGENTS.md as the agent-facing contract. |
| .gitignore | Ignores most CLAUDE.md outputs while allowing selected tracked exceptions. |
| .github/workflows/ci.yml | Adds compile drift gate step; adjusts self-check job to use uv run apm audit --ci. |
| .github/instructions/python.instructions.md | Removes hand-maintained source (moved to .apm/). |
| .github/instructions/encoding.instructions.md | Removes hand-maintained source (moved to .apm/). |
| .github/instructions/doc-sync.instructions.md | Removes hand-maintained source (moved to .apm/). |
| .github/instructions/changelog.instructions.md | Removes hand-maintained source (moved to .apm/). |
| .github/copilot-instructions.md | Becomes generated output with source attribution. |
| .github/agents/supply-chain-security-expert.agent.md | Removes hand-maintained agent primitive (moved to .apm/). |
| .github/agents/python-architect.agent.md | Removes hand-maintained agent primitive (moved to .apm/). |
| .github/agents/oss-growth-hacker.agent.md | Removes hand-maintained agent primitive (moved to .apm/). |
| .github/agents/doc-writer.agent.md | Removes hand-maintained agent primitive (moved to .apm/). |
| .github/agents/doc-analyser.agent.md | Removes hand-maintained agent primitive (moved to .apm/). |
| .github/agents/devx-ux-expert.agent.md | Removes hand-maintained agent primitive (moved to .apm/). |
| .github/agents/cli-logging-expert.agent.md | Removes hand-maintained agent primitive (moved to .apm/). |
| .github/agents/auth-expert.agent.md | Removes hand-maintained agent primitive (moved to .apm/). |
| .github/agents/apm-primitives-architect.agent.md | Removes hand-maintained agent primitive (moved to .apm/). |
| .github/agents/apm-ceo.agent.md | Removes hand-maintained agent primitive (moved to .apm/). |
| .github/agents/agentic-workflows.agent.md | Removes hand-maintained agent primitive (moved to .apm/). |
| .github/AGENTS.md | Regenerated GitHub workflows instruction output. |
| .gitattributes | Marks generated outputs as linguist-generated=true. |
| .apm/instructions/contributing.instructions.md | New source-of-truth for repo-wide contributor instructions. |
| self.assertEqual(instruction.validate(), []) | ||
|
|
||
| # Missing applyTo (instruction will apply globally) | ||
| # Empty applyTo — root-scoped instructions are now first-class (no warning). |
There was a problem hiding this comment.
Non-ASCII em dash (�) in a Python source comment violates the repo's "printable ASCII only" rule. Replace it with -- or - to keep files ASCII-clean.
| # --------------------------------------------------------------------------- | ||
| # 1. Mixed fixture — root + pattern-scoped instructions | ||
| # --------------------------------------------------------------------------- | ||
|
|
There was a problem hiding this comment.
This file introduces several non-ASCII em dashes in comments (e.g. this section header). The repo's encoding rule requires printable ASCII only; please replace with -- throughout this test file to avoid cross-platform encoding issues.
| All source code files and CLI output strings must stay within **printable ASCII** (U+0020–U+007E). | ||
|
|
||
| Do NOT use: | ||
| - Emojis (e.g. `🚀`, `✨`, `❌`) | ||
| - Unicode box-drawing characters (e.g. `─`, `│`, `┌`) | ||
| - Em dashes (`—`), en dashes (`–`), curly quotes (`"`, `"`, `'`, `'`) | ||
| - Any character outside the ASCII range (codepoint > U+007E) |
There was a problem hiding this comment.
This section includes emojis and other non-ASCII characters inside AGENTS.md itself (even as examples). The repo-wide encoding rule requires committed source/docs to remain printable ASCII; replace emoji examples with ASCII placeholders (e.g. "[emoji]" or plain text names) and use -- instead of an em dash.
|
|
||
| ## Dogfooding | ||
|
|
||
| APM uses APM to manage its own agent primitives. The `.apm/` tree is the source of truth. GitHub-consumed outputs (`AGENTS.md`, `.github/copilot-instructions.md`, `.github/instructions/**`, `.github/agents/**`, `.github/skills/**`) are pre-built and committed so GitHub Copilot, Agentic Workflows, and Cloud Agents work out of the box. `CLAUDE.md` is gitignored -- run `apm compile` after checkout to materialise it locally for Claude Code. CI gates drift via `apm compile -t copilot --check`. See [CONTRIBUTING.md -- Recompiling agent outputs](CONTRIBUTING.md#recompiling-agent-outputs). |
There was a problem hiding this comment.
This paragraph says "CLAUDE.md is gitignored" unconditionally, but .gitignore now has explicit exceptions (e.g. !docs/src/**/CLAUDE.md) and this PR adds committed docs/src/CLAUDE.md. Please clarify the statement (e.g. "most CLAUDE.md are ignored except ...") so contributors aren't surprised by tracked CLAUDE.md files.
| APM uses APM to manage its own agent primitives. The `.apm/` tree is the source of truth. GitHub-consumed outputs (`AGENTS.md`, `.github/copilot-instructions.md`, `.github/instructions/**`, `.github/agents/**`, `.github/skills/**`) are pre-built and committed so GitHub Copilot, Agentic Workflows, and Cloud Agents work out of the box. `CLAUDE.md` is gitignored -- run `apm compile` after checkout to materialise it locally for Claude Code. CI gates drift via `apm compile -t copilot --check`. See [CONTRIBUTING.md -- Recompiling agent outputs](CONTRIBUTING.md#recompiling-agent-outputs). | |
| APM uses APM to manage its own agent primitives. The `.apm/` tree is the source of truth. GitHub-consumed outputs (`AGENTS.md`, `.github/copilot-instructions.md`, `.github/instructions/**`, `.github/agents/**`, `.github/skills/**`) are pre-built and committed so GitHub Copilot, Agentic Workflows, and Cloud Agents work out of the box. Most generated `CLAUDE.md` files are gitignored, with explicit committed exceptions such as under `docs/src/`; run `apm compile` after checkout to materialise the local Claude Code output. CI gates drift via `apm compile -t copilot --check`. See [CONTRIBUTING.md -- Recompiling agent outputs](CONTRIBUTING.md#recompiling-agent-outputs). |
| compiler = AgentsCompiler(".") | ||
| config = CompilationConfig(local_only=True, target="all") | ||
| result = compiler.preview_all_outputs(config) | ||
| assert result == {} or all(v.strip() == "" for v in result.values()) or isinstance(result, dict) | ||
| finally: |
There was a problem hiding this comment.
The assertion on preview_all_outputs() is effectively a no-op: or isinstance(result, dict) makes this test pass even if the function returns an unexpected non-empty mapping. Tighten this to assert the exact expected behavior (e.g., {} when no primitives, or a dict whose values are empty strings if that's the contract).
|
|
||
| --- | ||
| *This file was generated by APM CLI. Do not edit manually.* | ||
| *To regenerate: `specify apm compile`* |
There was a problem hiding this comment.
The footer says To regenerate: specify apm compile`` which looks like a placeholder/mistake rather than a real command. This is user-facing and will be copied by contributors; change it to apm compile (and then regenerate outputs).
| *To regenerate: `specify apm compile`* | |
| *To regenerate: `apm compile`* |
| | Output | Committed? | Consumer | | ||
| |---|---|---| | ||
| | `.github/copilot-instructions.md` | **yes** | GitHub Copilot (chat / PR / cloud agent) | | ||
| | `.github/instructions/**` | **yes** | GitHub Copilot, Agentic Workflows | | ||
| | `.github/agents/**`, `.github/skills/**` | **yes** | GitHub Copilot agents and skills | | ||
| | `AGENTS.md`, `**/AGENTS.md` | **yes** | GitHub Copilot (repo-level instructions, read natively from the repo) | | ||
| | `CLAUDE.md`, `**/CLAUDE.md` | **no** (gitignored) | Claude Code (local only) | | ||
|
|
There was a problem hiding this comment.
The table states CLAUDE.md, **/CLAUDE.md are not committed (gitignored), but .gitignore now includes negation patterns that explicitly do track some CLAUDE.md paths (and this PR adds docs/src/CLAUDE.md). Update this table (and the note below) to reflect the actual ignore/track rules.
| | `1` | Drift detected -- content differs, or a file is stale (source removed but output still on disk). | Run `apm compile` for content drift; run `apm compile --clean` when the drift report lists stale files. | | ||
| | `2` | Unrecoverable error (invalid primitive, missing `apm.yml`, I/O failure). | Fix the reported error and re-run. | | ||
|
|
||
| Stdout is kept empty on exit `0` and `1` (reserved for a future `--json` report). The drift report is written to stderr and lists each drifted path plus whether the cause is content drift or a stale file. |
There was a problem hiding this comment.
The docs claim stdout is empty for exit code 0 and 1, but apm compile --check --verbose prints "All compiled outputs are up to date." and (on drift) the unified diff currently goes via _rich_echo to stdout. Either update this section to document the --verbose exception, or change the implementation so all reporting stays on stderr.
| Stdout is kept empty on exit `0` and `1` (reserved for a future `--json` report). The drift report is written to stderr and lists each drifted path plus whether the cause is content drift or a stale file. | |
| By default, stdout is kept empty on exit `0` and `1` (reserved for a future `--json` report). The drift report is written to stderr and lists each drifted path plus whether the cause is content drift or a stale file. When `--verbose` is also set, APM may print additional human-readable status output and unified diffs to stdout. |
| @@ -432,7 +432,25 @@ The `compilation` key is OPTIONAL. It controls `apm compile` behaviour. All fiel | |||
| | `exclude` | `list<string>` or `string` | `[]` | Glob patterns | Directories to skip during compilation (e.g. `apm_modules/**`). | | |||
| | `placement` | `object` | — | | Placement tuning. See §6.1. | | |||
There was a problem hiding this comment.
The placement row still says "See §6.1", but compilation.exclude is now §6.1 and compilation.placement is §6.2. Update the reference so readers land on the right section.
| | `placement` | `object` | — | | Placement tuning. See §6.1. | | |
| | `placement` | `object` | — | | Placement tuning. See §6.2. | |
| import difflib | ||
| import sys | ||
| from pathlib import Path | ||
| from typing import Dict, Optional |
There was a problem hiding this comment.
Optional is imported but not used in this module. Please remove it to keep imports clean.
Summary
Closes #695, closes #792. Supersedes closed #754.
Dogfoods APM on
microsoft/apmitself:.github/instructions/**+.github/agents/**into a.apm/source tree (9 instructions, 10 agents, 8 skills).apm.ymlat the repo root (name: apm-cli,target: all) drives compilation.apm compilenow regenerates every agent-tool output: rootAGENTS.md+CLAUDE.md, distributedAGENTS.md+CLAUDE.mdunder.github/,docs/src/,src/apm_cli/,src/apm_cli/integration/,tests/, and the new.github/copilot-instructions.md.apm compile --checkin Tier 1 so hand-edits to generated files or forgotten recompiles fail the build with a clear remediation hint.What's new
feat(compile):.github/copilot-instructions.mdemitter (apm compile should emit .github/copilot-instructions.md (dogfood gap) #792). Root-scoped instructions (noapplyTo) now compile into a single aggregated file that Copilot reads natively. Root-scoping is a first-class primitive -- theNo 'applyTo'warning was a bug masquerading as a lint.feat(compile):apm compile --checkflag. Read-only drift verification. Exit codes0match /1drift /2unrecoverable error. Drift report to stderr (stdout reserved for future--json), silent on success. Distinguishes content drift (apm compile) from stale files (apm compile --clean).fix(compilation):link_resolver._resolve_pathcontainment. Three independent gates (is_absolute,validate_path_segments,ensure_path_within) fail closed on traversal, symlink escape, and absolute paths. Supply-chain-security review: 0 blockers.fix(compilation): route timing output through logger and use deterministicbase_dirfor sort stability across platforms.How the dogfood works
.apm/**.apm compilelocally; commit the regenerated outputs in the same PR.apm compile --check-- drift fails the build and tells the contributor exactly which command to run.See
CONTRIBUTING.md-- Recompiling agent outputs and the new## Dogfoodingsection in the README.Commit structure
fbaa46979389ablink_resolver._resolve_path8372876.github/copilot-instructions.md(#792)7f8f95d--checkflag1ce108fapm.yml+ populate.apm/with repo primitives74b772bapm compile6d09d4eapm compile --checkgate to Tier 18f6aded--checkand the.apm/workflow125c48b## DogfoodingsectionEach commit is atomic and green.
Validation
uv run pytest tests/unit tests/test_console.py).uv run apm compile --checkexits 0 on HEAD.AGENTS.md/CLAUDE.mdpairs +.github/copilot-instructions.md)..gitattributesmarks all generated outputslinguist-generated=trueso GitHub diffs collapse them and language stats ignore them.Reviews run
Before opening this PR the following reviews were run and all findings addressed:
--checkcontract, exit codes, stderr, symbols).compilation.excludeinapm.yml.Follow-ups (filed, out of scope here)
.chatmode.mdprimitive type #840 -- deprecate and remove legacy.chatmode.mdprimitive type. No primitive in this repo uses it; the code paths and patterns add noise.link_resolver._resolve_pathinput guards (empty / whitespace-only strings) and expand test coverage for NUL bytes, backslash traversal, andfile://URIs.Known limitations (documented, not blocking)
--checkstale detection uses a hardcoded_WELL_KNOWN_OUTPUTSlist. DistributedAGENTS.md/CLAUDE.mdin subdirs need aTODO(stale-distributed-agents)follow-up once the distributed compiler exposes a "possible outputs" query. Content drift is fully covered; stale-only detection is the gap.verbose_detailin the drift report routes through Rich stdout (pre-existing infra constraint), not stderr. Accepted by cli-logging-expert.Breaking changes
None for consumers of APM.
For
microsoft/apmcontributors:.github/instructions/**and.github/agents/**no longer exist as source directories. Edit under.apm/instead, thenapm compile. CONTRIBUTING.md covers the workflow.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com