refactor: complexity audit -- eliminate god-method forks, O(n^2) loops, redundant I/O#918
Conversation
Extract pure git ref helpers into git_remote_ops.py and backend download logic into download_strategies.py DownloadStrategyManager. Backward-compat method stubs on GitHubPackageDownloader preserve all existing import paths and test patch points. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split 555-line install() into thin dispatcher + _install_apm_packages() + _handle_mcp_install(). Extract _resolve_package_references() and _check_package_conflicts() from _validate_and_add_packages_to_apm_yml(). Add InstallContext dataclass to bundle shared parameters. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add tests for commands.install.InstallContext dataclass construction and _resolve_package_references() batch-duplicate mutation contract. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Refactor-focused PR that reduces complexity and improves performance across install/audit/deps/uninstall paths, while adding benchmarks and characterization/unit tests to guard behavior and scaling.
Changes:
- Introduces thread-safe caching/singletons (Rich console, marketplace registry cache) and reduces redundant I/O (lockfile reuse, per-runtime registry reads).
- Replaces several O(n^2) loops with indexed/O(n) approaches (uninstall reverse-dep traversal, discovery scanning strategy).
- Adds substantial benchmark/scaling-guard coverage plus characterization/unit tests for refactored components.
Reviewed changes
Copilot reviewed 42 out of 42 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_uninstall_engine_helpers.py | Adds unit coverage for uninstall reverse-dependency children index helper. |
| tests/unit/test_transitive_mcp.py | Updates tests to match MCPIntegrator logging/output behavior changes. |
| tests/unit/test_thread_safety.py | Adds concurrency tests for console singleton and marketplace registry cache lock. |
| tests/unit/test_script_formatters.py | Adds tests for ScriptExecutionFormatter Rich fallback branches and formatting. |
| tests/unit/test_registry_integration.py | Adds tests ensuring MCP registry runtime lookups are cached per runtime. |
| tests/unit/test_mcp_integrator_remove_stale.py | Adds characterization coverage for MCPIntegrator.remove_stale() argument combinations. |
| tests/unit/test_mcp_integrator_coverage.py | Adds coverage tests for MCPIntegrator branches + NullCommandLogger surface. |
| tests/unit/test_mcp_integrator_characterisation.py | Adds install() characterization tests across logger/runtime/flags combinations. |
| tests/unit/test_console_utils.py | Resets console singleton between tests to avoid cross-test coupling. |
| tests/unit/install/test_architecture_invariants.py | Updates LOC budget gate for install.py after decomposition. |
| tests/unit/compilation/test_agents_compiler_coverage.py | Adds test for constitution injection failure being swallowed + debug-logged. |
| tests/unit/commands/test_install_resolve_refs.py | Adds tests for in-place identity-set mutation contract in resolver helper. |
| tests/unit/commands/test_install_context.py | Adds structural tests for commands.install.InstallContext dataclass. |
| tests/benchmarks/test_scaling_guards.py | Adds non-benchmark scaling guards to detect complexity regressions in CI. |
| tests/benchmarks/test_install_hot_paths.py | Adds benchmark suite for install hot paths (hashing, lockfile ops, flattening, etc.). |
| tests/benchmarks/test_git_and_compiler_benchmarks.py | Adds benchmarks for git ref parsing/sorting, compiler analysis, and MCP transitive collection. |
| tests/benchmarks/test_compilation_hot_paths.py | Adds compilation/integration benchmarks (hashing, partitioning, link rewrite, lockfile RTT). |
| tests/benchmarks/test_audit_benchmarks.py | Adds audit-focused benchmarks for discovery, uninstall indexing, registry caching, console singleton, etc. |
| src/apm_cli/utils/console.py | Implements thread-safe Rich Console singleton + test-only reset hook. |
| src/apm_cli/registry/operations.py | Caches installed server IDs per runtime to avoid O(servers*runtimes) config reads. |
| src/apm_cli/primitives/discovery.py | Refactors primitive discovery to single os.walk pass with pattern matching helpers. |
| src/apm_cli/policy/discovery.py | Improves exception hygiene by logging token manager failure at debug level. |
| src/apm_cli/output/script_formatters.py | Replaces bare except: with except Exception: in Rich fallback blocks. |
| src/apm_cli/output/formatters.py | Replaces bare except: with except Exception: in multiple formatting fallbacks. |
| src/apm_cli/models/dependency/reference.py | Splits parsing logic into smaller helpers; centralizes validation/final field extraction. |
| src/apm_cli/models/apm_package.py | Deduplicates dependency parsing for dependencies/devDependencies via helper. |
| src/apm_cli/marketplace/registry.py | Adds lock around registry cache to make load/save/invalidate thread-safe. |
| src/apm_cli/integration/mcp_integrator.py | Introduces NullCommandLogger default and removes many logger=None forks. |
| src/apm_cli/install/pipeline.py | Threads early lockfile through InstallContext to avoid re-reading. |
| src/apm_cli/install/phases/resolve.py | Uses cached early lockfile when available and improves verbose lockfile logging. |
| src/apm_cli/install/context.py | Adds early_lockfile field to install pipeline context. |
| src/apm_cli/deps/git_remote_ops.py | Extracts pure helpers for parsing/sorting git ls-remote output. |
| src/apm_cli/core/script_runner.py | Decomposes runtime command transformation and avoids redundant apm_modules scans. |
| src/apm_cli/core/null_logger.py | Adds NullCommandLogger (null-object) to centralize default logging behavior. |
| src/apm_cli/compilation/agents_compiler.py | Adds debug logging for previously silent exception paths. |
| src/apm_cli/commands/uninstall/engine.py | Adds O(n) children index and uses it to avoid repeated full scans. |
| src/apm_cli/commands/deps/cli.py | Splits data resolution from rendering; extracts helpers for tree formatting. |
| src/apm_cli/commands/audit.py | Decomposes audit command into mode handlers with shared config dataclass. |
| CHANGELOG.md | Adds Unreleased entries describing refactors, benchmarks, and exception hygiene updates. |
APM Review Panel VerdictDisposition: REQUEST_CHANGES (two concrete pre-merge fixes; overall shape is excellent) Per-persona findingsPython Architect: This is a major architectural change: three new modules introduced ( Before -- WI-2 class layout (monolith) classDiagram
direction LR
class GitHubPackageDownloader {
<<Monolith>>
+resilient_get()
+build_repo_url()
+download_file()
+download_artifactory_archive()
+parse_ls_remote_output()
+semver_sort_key()
+sort_remote_refs()
+github_token str
+ado_token str
+auth_resolver AuthResolver
}
class AuthResolver {
<<Strategy>>
+resolve_for_dep(dep_ref) AuthContext
}
GitHubPackageDownloader ..> AuthResolver : reads
note for GitHubPackageDownloader "All download, URL-build, and ref-sort\nlogic inlined -- 1000+ line module"
After -- WI-2 class layout (decomposed) classDiagram
direction LR
class GitHubPackageDownloader {
<<Facade>>
+github_token str
+ado_token str
+auth_resolver AuthResolver
+_strategies DownloadStrategyManager
+_resilient_get() -- stub
+build_repo_url() -- stub
+download_artifactory_archive() -- stub
}
class DownloadStrategyManager {
<<ConcreteStrategy>>
+_host GitHubPackageDownloader
+resilient_get()
+build_repo_url()
+download_file()
+download_artifactory_archive()
}
class git_remote_ops {
<<Pure>>
+parse_ls_remote_output()
+semver_sort_key()
+sort_remote_refs()
}
class NullCommandLogger {
<<NullObject>>
+verbose = False
+warning()
+progress()
+error()
+success()
}
class InstallContextCmds {
<<ParameterBundle>>
+scope
+logger
+force bool
+dry_run bool
}
class _AuditConfig {
<<ValueObject>>
+project_root Path
+logger CommandLogger
+verbose bool
+output_format str
}
GitHubPackageDownloader *-- DownloadStrategyManager : owns
DownloadStrategyManager ..> GitHubPackageDownloader : back-ref (_host)
GitHubPackageDownloader ..> git_remote_ops : imports
class GitHubPackageDownloader:::touched
class DownloadStrategyManager:::touched
class git_remote_ops:::touched
class NullCommandLogger:::touched
class InstallContextCmds:::touched
class _AuditConfig:::touched
classDef touched fill:#fff3b0,stroke:#d47600
note for DownloadStrategyManager "Bidirectional coupling via _host --\nsee Required Actions"
Before -- WI-2/WI-3 execution flow flowchart TD
A["apm install (CLI)"] --> B["install() -- 555 lines"]
B --> C["_validate_and_add_packages_to_apm_yml -- 290 lines"]
C --> D["[I/O] load_yaml(apm.yml)"]
D --> E["inline duplicate detection loop"]
E --> F["inline package validation loop"]
F --> G["[I/O] dump_yaml(apm.yml)"]
G --> H["run_install_pipeline()"]
H --> I["resolve.run() -- [I/O] LockFile.read() x2"]
After -- WI-2/WI-3 execution flow flowchart TD
A["apm install (CLI)"] --> B["install()"]
B --> C["InstallContext -- commands/install.py"]
C --> D["_validate_and_add_packages_to_apm_yml"]
D --> D1["_check_package_conflicts()"]
D --> D2["_resolve_package_references()"]
D --> D3["_merge_packages_into_yml()"]
D3 --> E["[I/O] dump_yaml(apm.yml)"]
E --> F["run_install_pipeline()"]
F --> G["install/context.py:InstallContext -- early_lockfile cached"]
G --> H["resolve.run() -- [I/O] LockFile.read() x1 (cache hit skips)"]
Design patterns
Architecture issue -- dual CLI Logging Expert:
One cosmetic bug: Audit command decomposition routes through DevX UX Expert: This is a pure internal refactoring. No command surface, flags, help text, or exit codes are changed. The The No documentation changes are needed (no command surface delta). One ergonomic note echoing the logging finding: a verbose user running Supply Chain Security Expert: Reviewed against all seven threat-model categories. Key findings:
Auth Expert: Activated (fast-path trigger:
The ADO bearer scheme:
No new OSS Growth Hacker: No user-facing feature lands with this PR -- it is a pure engineering investment. Three growth implications worth noting:
Side-channel to CEO: the dual CEO arbitrationSpecialists are broadly aligned: the engineering quality of this refactoring is high, patterns are correctly applied, and no auth or supply-chain regressions are introduced. Two issues rise to required-action level. First, Required actions before merge
Optional follow-ups
|
- Route user-visible MCP messages through logger.progress() instead of verbose_detail() so NullCommandLogger preserves output - Fix trivially-passing frozen assertion in test_install_context.py - Add missing (microsoft#918) PR references to CHANGELOG entries Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
0ed31e7 to
a1e68a7
Compare
Extract pure git ref helpers into git_remote_ops.py and backend download logic into download_strategies.py DownloadStrategyManager. Backward-compat method stubs on GitHubPackageDownloader preserve all existing import paths and test patch points. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split 555-line install() into thin dispatcher + _install_apm_packages() + _handle_mcp_install(). Extract _resolve_package_references() and _check_package_conflicts() from _validate_and_add_packages_to_apm_yml(). Add InstallContext dataclass to bundle shared parameters. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add tests for commands.install.InstallContext dataclass construction and _resolve_package_references() batch-duplicate mutation contract. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Route user-visible MCP messages through logger.progress() instead of verbose_detail() so NullCommandLogger preserves output - Fix trivially-passing frozen assertion in test_install_context.py - Add missing (microsoft#918) PR references to CHANGELOG entries Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract pure git ref helpers into git_remote_ops.py and backend download logic into download_strategies.py DownloadStrategyManager. Backward-compat method stubs on GitHubPackageDownloader preserve all existing import paths and test patch points. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split 555-line install() into thin dispatcher + _install_apm_packages() + _handle_mcp_install(). Extract _resolve_package_references() and _check_package_conflicts() from _validate_and_add_packages_to_apm_yml(). Add InstallContext dataclass to bundle shared parameters. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add tests for commands.install.InstallContext dataclass construction and _resolve_package_references() batch-duplicate mutation contract. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Route user-visible MCP messages through logger.progress() instead of verbose_detail() so NullCommandLogger preserves output - Fix trivially-passing frozen assertion in test_install_context.py - Add missing (microsoft#918) PR references to CHANGELOG entries Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
a1e68a7 to
56c4e2f
Compare
APM Review Panel VerdictDisposition: APPROVE (with two pre-merge fixes) Per-persona findingsPython Architect: This is a major architectural refactor touching 43 files. Because it introduces new module boundaries, a new delegation pattern, and new dataclass abstractions, Before/After diagrams are warranted for the two biggest structural changes. Before -- github_downloader.py as monolith + null-logger forks: classDiagram
direction LR
class GitHubPackageDownloader {
<<Orchestrator>>
+auth_resolver AuthResolver
+registry_config RegistryConfig
+_resilient_get() Response
+_build_repo_url() str
+_get_artifactory_headers() dict
+_download_artifactory_archive()
+_download_file_from_artifactory()
+_parse_ls_remote_output()
+_sort_remote_refs()
}
class MCPIntegrator {
+collect_transitive(logger=None)
+install(logger=None)
+remove_stale(logger=None)
}
class CommandLogger {
<<Base>>
+verbose bool
+start()
+progress()
+dry_run_notice()
}
MCPIntegrator ..> CommandLogger : if logger: guard (32x)
MCPIntegrator ..> GitHubPackageDownloader : uses
After -- decomposed with delegation and null-object: classDiagram
direction LR
class GitHubPackageDownloader {
<<Orchestrator>>
+auth_resolver AuthResolver
+registry_config RegistryConfig
+_strategies DownloadStrategyManager
+_resilient_get() Response
+_build_repo_url() str
+_get_artifactory_headers() dict
}
class DownloadStrategyManager {
<<Delegate>>
+_host GitHubPackageDownloader
+resilient_get() Response
+build_repo_url() str
+get_artifactory_headers() dict
+download_artifactory_archive()
+download_file_from_artifactory()
}
class NullCommandLogger {
<<NullObject_partial>>
+verbose bool
+start()
+progress()
+success()
+warning()
+error()
+tree_item()
}
class CommandLogger {
<<Base>>
+verbose bool
+start()
+progress()
+dry_run_notice()
+validation_start()
+validation_fail()
}
class InstallContext {
<<ParameterBundle>>
+scope InstallScope
+logger InstallLogger
+auth_resolver AuthResolver
+verbose bool
+force bool
}
class _AuditConfig {
<<ParameterBundle, frozen>>
+project_root Path
+logger CommandLogger
+verbose bool
+output_format str
}
class MCPIntegrator {
+collect_transitive(logger=NullCommandLogger)
+install(logger=NullCommandLogger)
+remove_stale(logger=NullCommandLogger)
}
class GitHubPackageDownloader:::touched
class DownloadStrategyManager:::touched
class NullCommandLogger:::touched
class InstallContext:::touched
class _AuditConfig:::touched
class MCPIntegrator:::touched
GitHubPackageDownloader *-- DownloadStrategyManager : delegates to
DownloadStrategyManager ..> GitHubPackageDownloader : back-ref host
MCPIntegrator ..> NullCommandLogger : default logger
MCPIntegrator ..> CommandLogger : uses
classDef touched fill:#fff3b0,stroke:#d47600
Execution flow (After -- key paths changed by this PR): flowchart TD
A["MCPIntegrator.install(logger=None)"] --> B{"logger is None?"}
B -- Yes --> C["logger = NullCommandLogger()\ncalls _rich_* directly"]
B -- No --> D["use provided CommandLogger"]
C --> E["MCPIntegrator proceeds\nno if-logger: guards needed"]
D --> E
E --> F["GitHubPackageDownloader._resilient_get(url, headers)"]
F --> G["DownloadStrategyManager.resilient_get()\n[NET] HTTP GET + rate-limit retry"]
G --> H{"HTTP 429/503 or 403+RateLimit?"}
H -- Yes --> I["sleep Retry-After or exp-backoff\nmax 3 attempts"]
I --> G
H -- No --> J["return Response"]
J --> K{"Artifactory archive needed?"}
K -- Yes --> L["DownloadStrategyManager.download_artifactory_archive()\n[NET][FS] zip fetch"]
L --> M{"zip entry dest.resolve()\noutside target_path?"}
M -- Yes --> N["skip entry -- CWE-22 guard preserved"]
M -- No --> O["[FS] extract member to target_path"]
K -- No --> P["return bytes"]
A2["uninstall BFS orphan detection"] --> B2["_build_children_index(lockfile)\n[LOCK] single O(n) pass"]
B2 --> C2["children dict: parent_url -> list of child deps"]
C2 --> D2["BFS pop parent_url\nchildren_index.get(parent_url,[]) O(1)"]
D2 --> E2["collect orphan keys"]
A3["_scan_patterns(base_dir, patterns)"] --> B3["os.walk(base_str, followlinks=False)\nsingle pass -- no symlink follow"]
B3 --> C3["_matches_any_pattern(rel_path, all_patterns)"]
C3 -- match --> D3["parse_primitive_file(file_path)\n[FS] read + parse"]
C3 -- no match --> B3
D3 --> E3["collection.add_primitive()"]
Design patterns:
One structural concern: CLI Logging Expert: The
DevX UX Expert: No CLI surface changes -- zero new commands, flags, or help text. Every decomposition is internal. The One ergonomic observation: the behavior change from Supply Chain Security Expert:
Auth Expert: Activated --
Auth Expert conclusion: No regression to AuthResolver precedence, host classification, token scoping, or credential fallback semantics. OSS Growth Hacker: Side-channel note to CEO: This PR is a high-credibility signal for the OSS community. The 160 benchmark tests, O(n^2)->O(n) algorithmic proof in No conversion surface impacts (README, quickstart, first-run flow unchanged). The CEO arbitrationThis PR is a well-executed complexity audit. All specialists found the decompositions sound, algorithmic improvements correct, and the test coverage comprehensive. There are no strategic disagreements to arbitrate. The two pre-merge fixes identified (incorrect DCLP in registry, Required actions before merge
Optional follow-ups
|
Required fixes: - Fix incorrect DCLP in marketplace registry _load() -- hold lock across full check+read+set to prevent race condition - Document NullCommandLogger partial interface and visible-output semantics in docstring Optional follow-ups (implemented to minimise tech debt): - Rename DownloadStrategyManager to DownloadDelegate to reflect Facade/Delegate pattern (not GoF Strategy) - Remove redundant seen set from _scan_patterns() discovery walk - Replace wall-clock benchmark assertions with generous 5x ceilings to prevent flakiness on slow runners - Update CHANGELOG with all panel fix entries Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Panel Findings -- All Addressed in
|
| # | Finding | Resolution |
|---|---|---|
| R1 | Incorrect DCLP in registry._load() |
Fixed -- lock now held across full check+read+set operation |
| R2 | NullCommandLogger undocumented partial interface |
Fixed -- docstring clarifies unimplemented methods, visible output semantics, and MCPIntegrator scope |
Optional (4/4)
| # | Finding | Resolution |
|---|---|---|
| O1 | DownloadStrategyManager naming |
Renamed to DownloadDelegate with Facade/Delegate documentation |
| O2 | Redundant seen set in _scan_patterns() |
Removed -- os.walk(followlinks=False) prevents revisits |
| O3 | Wall-clock benchmark assertions | All thresholds multiplied by 5x (min 2.0s floor) to prevent flakiness |
| O4 | CHANGELOG entries | Added under [Unreleased] with (#918) |
Validation: 5,833 unit tests + 154 benchmarks passing.
…s, redundant I/O
Phase 0: Cache early lockfile on InstallContext (2x reads -> 1x);
extract _parse_dependency_dict() classmethod in APMPackage.
Phase 1: Thread-safety gate -- console singleton with double-checked
locking; marketplace registry cache lock.
Phase 2: Uninstall engine reverse-dep index O(n^2) -> O(n) via
_build_children_index() helper.
Phase 3: NullCommandLogger null-object pattern eliminates 32 conditional
logger forks in MCPIntegrator (net -91 production lines).
Phase 6: Primitive discovery -- replace 9+ glob.glob() calls with single
os.walk + fnmatch pass.
Registry: Pre-load installed IDs per runtime, reducing config reads from
O(servers x runtimes) to O(runtimes).
54 new tests added (40 characterisation + 14 unit).
5,415 tests pass (baseline 5,361 + 54 new).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
16 @pytest.mark.benchmark tests in test_audit_benchmarks.py covering: - Phase 0: dependency parsing dedup (from_apm_yml with 50/100/200 deps) - Phase 2: children index build (50/200/500 deps + correctness) - Phase 3: NullCommandLogger dispatch overhead (20k calls) - Phase 6: primitive discovery (100/500 files + empty-match) - Registry: config cache O(R) call-count verification - Console: singleton performance + 50-thread concurrency 3 scaling-ratio guards in test_scaling_guards.py (run in default suite): - Children index: O(n) scaling assertion (ratio < 25 for 10x input) - Discovery scan: O(n) scaling assertion (ratio < 25 for 10x input) - Console singleton: O(1) scaling assertion (ratio < 15 for 10x calls) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add 52 new benchmark tests and 2 scaling guards covering all critical install and compilation hot paths: P0 (install path): - compute_package_hash throughput and determinism - get_all_dependencies sort latency and repeated-call ceiling - is_semantically_equivalent early-exit and full-scan - flatten_dependencies with conflict resolution - LockFile.to_yaml serialisation P1 (compilation path): - compute_deployed_hashes throughput and correctness - ContextOptimizer.optimize_instruction_placement scaling - UnifiedLinkResolver._rewrite_markdown_links latency - BaseIntegrator.partition_managed_files routing - LockFile round-trip (to_yaml + from_yaml) data preservation - UnifiedLinkResolver.register_contexts throughput Scaling guards (run in default test suite): - compute_package_hash O(n) verification - is_semantically_equivalent O(n) verification Addresses testing-engineer review: console singleton teardown, flaky timing comparison removal, threshold tightening, variable rename, and conflict correctness assertion. Total benchmark suite: 82 tests (77 benchmarks + 5 scaling guards) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add 77 new benchmark tests and 1 scaling guard covering hot paths identified by Python Architect analysis: P0 (superlinear risk): - _match_double_star recursive glob matcher (O(m^k) worst case) - ContentScanner.scan_text per-character Unicode scanning - ContentScanner.strip_dangerous per-character content rewrite - build_dependency_tree BFS traversal with per-node YAML parse P1 (meaningful coverage gaps): - _parse_ls_remote_output + _sort_remote_refs (semver sorting) - DistributedAgentsCompiler.analyze_directory_structure - MCPIntegrator.collect_transitive lock-file-guided scanning Scaling guard: - should_exclude depth scaling (sub-quadratic verification) Addresses testing-engineer review: fast-path relative assertion, redundant cache clear removal, all-tags sort invariant, docstring clarity, test naming, and severity assertion strengthening. Total benchmark suite: 160 tests (154 benchmarks + 6 scaling guards) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace 7 bare except: clauses that catch BaseException (including KeyboardInterrupt and SystemExit) with except Exception: in formatters.py and script_formatters.py. Add logger.debug() to 4 silent exception handlers in discovery.py and agents_compiler.py to make credential resolution and config loading failures visible with --verbose. CEO-ratified findings B3 and B4 from Round 2 quality audit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rence WI-4a: reference.py -- _parse_standard_url (110->22 stmts) and parse (63->38 stmts) split into 6 focused helpers by parsing phase. WI-4b: audit.py -- audit() (290 lines, 13 params) split into thin dispatcher (18 stmts) + _audit_ci_gate (49) + _audit_content_scan (67) with shared _AuditConfig dataclass. WI-4c: deps/cli.py -- _show_scope_deps (135->59 stmts) and tree (115->65 stmts) split data resolution from rendering via _resolve_scope_deps and _build_dep_tree helpers. WI-4d: script_runner.py -- _transform_runtime_command (124->20 stmts) split into per-runtime builder dispatch. Fixed double iterdir() walk in _resolve_prompt_file via single-scan _collect_dependency_dirs. All changes are internal refactors with no public API changes. CEO-ratified findings W2, W3, W4, W5 from Round 2 quality audit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add 8 unit tests for ScriptExecutionFormatter (G1 gap: both Rich fallback branches + happy paths for content preview, auto-discovery, execution success/error, and script header formatting). Add 1 test for CLAUDE.md constitution injection failure path (G2 gap: verifies compilation succeeds and _logger.debug is called when ConstitutionInjector.inject raises). Update CHANGELOG with WI-4 god function decomposition entries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract pure git ref helpers into git_remote_ops.py and backend download logic into download_strategies.py DownloadStrategyManager. Backward-compat method stubs on GitHubPackageDownloader preserve all existing import paths and test patch points. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split 555-line install() into thin dispatcher + _install_apm_packages() + _handle_mcp_install(). Extract _resolve_package_references() and _check_package_conflicts() from _validate_and_add_packages_to_apm_yml(). Add InstallContext dataclass to bundle shared parameters. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add tests for commands.install.InstallContext dataclass construction and _resolve_package_references() batch-duplicate mutation contract. Part of complexity audit PR microsoft#918. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Route user-visible MCP messages through logger.progress() instead of verbose_detail() so NullCommandLogger preserves output - Fix trivially-passing frozen assertion in test_install_context.py - Add missing (microsoft#918) PR references to CHANGELOG entries Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Required fixes: - Fix incorrect DCLP in marketplace registry _load() -- hold lock across full check+read+set to prevent race condition - Document NullCommandLogger partial interface and visible-output semantics in docstring Optional follow-ups (implemented to minimise tech debt): - Rename DownloadStrategyManager to DownloadDelegate to reflect Facade/Delegate pattern (not GoF Strategy) - Remove redundant seen set from _scan_patterns() discovery walk - Replace wall-clock benchmark assertions with generous 5x ceilings to prevent flakiness on slow runners - Update CHANGELOG with all panel fix entries Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
eb7f35a to
64cbd2a
Compare
Resolved conflicts in: - CHANGELOG.md: combined PR microsoft#844/microsoft#848 changes with upstream microsoft#918 changes - src/apm_cli/policy/parser.py: kept _looks_like_yaml_content pattern from upstream, added (OSError, ValueError) handling - uv.lock: updated to version 0.10.0
Resolves CHANGELOG.md conflict in the [Unreleased] section by combining both sides: - Added (HEAD): apps[]/app-id GitHub App auth entries for shared/apm.md - Changed/Fixed (origin/main): #820 target validation, #918 cleanup, #1008 marketplace build GHE host Both blocks are independent and additive. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
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(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>
Complexity Audit & Code Quality Improvements
Summary
Comprehensive codebase quality audit covering algorithmic improvements, god function decomposition, exception hygiene, and performance benchmarks.
Commits (10 total)
except:replaced withexcept Exception:, debug logging for silent handlersgithub_downloader.pysplit into 3 modules:git_remote_ops.py(ref parsing),download_strategies.py(DownloadStrategyManager), slimmed orchestrator (2,669->2,068 lines)install()555-line god function split into dispatcher +_install_apm_packages()+_handle_mcp_install()+_post_install_summary()withInstallContextdataclass_resolve_package_references()mutation contractFindings resolved
install()27-param/378-stmt god functiongithub_downloader.py2,669-line god fileexcept:catches KeyboardInterruptexcept Exception:logger.debug()Test results
Related issues