Apply PR #1020 review nits: type precision, reason constant, frozenset family validation#1035
Apply PR #1020 review nits: type precision, reason constant, frozenset family validation#1035danielmeppiel wants to merge 4 commits intomainfrom
Conversation
Co-authored-by: Copilot <copilot@github.com>
…set family validation - Parameterize CompileTargetType as Union[str, frozenset[str]] for precision - Extract REASON_NO_TARGET_FOLDER constant in target_detection; replace brittle substring match in compile CLI with equality comparison. User-facing log message is unchanged. - Add explicit family validation in AgentsCompiler when config.target is a frozenset. Previously the frozenset branch silently bypassed _KNOWN_TARGETS validation; an invalid family (e.g. via direct API use) could silently produce partial output. Now fails explicitly with a clear error listing the bad value and accepted families. - Add regression test test_unknown_frozenset_target_family_returns_failure. Docs sync: verified docs/src/content/docs/reference/cli-commands.md and packages/apm-guide/.apm/skills/apm-usage/commands.md already document the correct (post-fix) multi-target behavior; no edits needed. Refs #1020 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Applies follow-up review nits on top of PR #1020 by tightening the internal compile-target representation and validation, and by de-coupling CLI behavior from brittle reason-string substring checks.
Changes:
- Introduces
CompileTargetType(includingfrozenset[str]) and exportsREASON_NO_TARGET_FOLDERfor equality-based comparisons. - Updates compile CLI to support multi-target compilation via
frozensetrouting and reason-constant comparison. - Adds defensive validation for multi-target frozenset families in
AgentsCompiler, plus regression tests and a changelog entry.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/compilation/test_compile_target_flag.py | Adds/updates regression tests for multi-target resolution and frozenset validation behavior. |
| src/apm_cli/core/target_detection.py | Adds CompileTargetType, REASON_NO_TARGET_FOLDER, and updates should_compile_* helpers to accept frozenset targets. |
| src/apm_cli/compilation/agents_compiler.py | Validates frozenset-based multi-target families and returns a clear error on unknown families. |
| src/apm_cli/commands/compile/cli.py | Switches from substring matching to reason constant equality; adds frozenset-aware target handling and progress messaging. |
| CHANGELOG.md | Adds an Unreleased Fixed entry for the compile targeting behavior. |
Copilot's findings
- Files reviewed: 5/5 changed files
- Comments generated: 2
| if isinstance(target, list): | ||
| # Multi-target list: show what the compiler will produce | ||
| _target_label = ",".join(target) | ||
| if effective_target == "all": | ||
| logger.progress( | ||
| f"Compiling for AGENTS.md + CLAUDE.md (--target {_target_label})" | ||
| ) | ||
| elif effective_target == "claude": | ||
| logger.progress( | ||
| f"Compiling for CLAUDE.md (--target {_target_label})" | ||
| ) | ||
| else: | ||
| logger.progress( | ||
| f"Compiling for AGENTS.md (--target {_target_label})" | ||
| ) | ||
| elif detected_target == "minimal": | ||
| from ...core.target_detection import ( | ||
| should_compile_agents_md, | ||
| should_compile_claude_md, | ||
| should_compile_gemini_md, | ||
| ) | ||
| _parts = [] | ||
| if should_compile_agents_md(effective_target): | ||
| _parts.append("AGENTS.md") | ||
| if should_compile_claude_md(effective_target): | ||
| _parts.append("CLAUDE.md") | ||
| if should_compile_gemini_md(effective_target): | ||
| _parts.append("GEMINI.md") | ||
| logger.progress( | ||
| f"Compiling for {' + '.join(_parts)} (--target {_target_label})" | ||
| ) | ||
| elif ( | ||
| isinstance(effective_target, str) | ||
| and effective_target == "vscode" | ||
| and detection_reason == REASON_NO_TARGET_FOLDER | ||
| ): | ||
| logger.progress(f"Compiling for AGENTS.md only ({detection_reason})") | ||
| logger.progress( | ||
| " Create .github/, .claude/, .codex/, .opencode/ or .cursor/ folder for full integration", | ||
| symbol="light_bulb", | ||
| ) | ||
| else: | ||
| description = get_target_description(detected_target) | ||
| description = get_target_description(effective_target) | ||
| logger.progress( | ||
| f"Compiling for {description} - {detection_reason}" |
There was a problem hiding this comment.
When effective_target comes from apm.yml as a multi-target list (so _resolve_compile_target(config_target) returns a frozenset) and the CLI --target flag is not a list, this branch falls through to get_target_description(effective_target), which will render as "unknown target" in the progress log. Consider handling isinstance(effective_target, frozenset) (regardless of the original target type) by building the AGENTS.md/CLAUDE.md/GEMINI.md parts list the same way as the isinstance(target, list) branch, so config-driven multi-targets get an accurate progress message.
| - Remove redundant `seen` set from `_scan_patterns()` discovery walk (#918) | ||
| - Correct targeting of compiled artifacts so GEMINI.md is only created if requested (#1019) | ||
|
|
There was a problem hiding this comment.
This changelog entry appears to reference the issue number (#1019) rather than the PR that delivered the fix, and it doesn't end with a PR number as required by the project's Keep a Changelog convention. Update the line to end with the actual PR number (likely #1020 and/or this follow-up PR), and consider wrapping GEMINI.md in backticks for consistency with nearby entries.
TL;DR
Applies the three optional review nits from @apm-bot's Review Panel comment on #1020 on top of @tillig's HEAD (
292bda1). No behavior change for end users; tightens internals so future contributors and direct API callers can't trip over the same footguns.The required action (doc sync) was verified as a no-op —
docs/src/content/docs/reference/cli-commands.md:1712andpackages/apm-guide/.apm/skills/apm-usage/commands.md:28already document the correct multi-target behavior.Problem
PR #1020 fixed
apm compile --target claude,codexso it stops emitting an unrequestedGEMINI.md. The Review Panel approved it with a small list of optional cleanups that improve robustness without changing user-visible output:CompileTargetType = Union[str, frozenset]loses the inner element type that the rest of the module already assumes ({"agents", "claude", "gemini"}).cli.pyrelied on"no target" in detection_reasonto pick the "AGENTS.md only" log branch. If the reason string intarget_detection.detect_target()ever changes wording, that branch silently goes dead.AgentsCompiler.compile()skipped_KNOWN_TARGETSvalidation whenconfig.targetis a frozenset. Any direct API caller passing a bogus family (e.g.frozenset({"bogus"})) would succeed with empty/partial output instead of failing loudly.Changes
src/apm_cli/core/target_detection.pyUnion[str, frozenset]→Union[str, frozenset[str]]. AddedREASON_NO_TARGET_FOLDER = "no target folder found"constant;detect_target()returns it instead of a string literal.src/apm_cli/commands/compile/cli.pyREASON_NO_TARGET_FOLDER; replaces"no target" in detection_reasonwithdetection_reason == REASON_NO_TARGET_FOLDER. User-facing log message is unchanged ("Compiling for AGENTS.md only (no target folder found)").src/apm_cli/compilation/agents_compiler.py_KNOWN_COMPILE_FAMILIES = frozenset({"agents", "claude", "gemini"}). The frozenset branch now validates the set and returns an explicit error if any member is unknown.tests/unit/compilation/test_compile_target_flag.pytest_unknown_frozenset_target_family_returns_failureregression test.Why an explicit branch instead of
assertThe reviewer suggested an
assert. Rejected:assertis stripped underpython -O, and insidecompile()it would surface as a genericCompilation failed: ...— strictly worse UX than the existing unknown-target error path. The explicit branch costs ~10 lines, runs once per compile, and yields an actionable message for direct API callers (the error names the bad family and lists accepted families).Validation
Includes the new regression test plus all existing target-routing, multi-target, and detection tests.
Relationship to #1020
This branch is based on PR #1020's HEAD (
292bda1). It is a follow-up, not a competing PR — happy to:fb314d3) onto his branch and close this, orUNKNOWN).Whatever maintainers prefer.
How to test
Manual smoke (in any APM project):
Refs #1020.