Data-driven integration dispatch: replace if-chain with target × primitive loop#494
Merged
danielmeppiel merged 9 commits intomainfrom Mar 30, 2026
Merged
Conversation
Agent-Logs-Url: https://github.com/microsoft/apm/sessions/12c01ced-bc96-4e31-a0fd-b6e147a0e167 Co-authored-by: danielmeppiel <51440732+danielmeppiel@users.noreply.github.com>
…t, Instruction, Hook, Prompt) Agent-Logs-Url: https://github.com/microsoft/apm/sessions/12c01ced-bc96-4e31-a0fd-b6e147a0e167 Co-authored-by: danielmeppiel <51440732+danielmeppiel@users.noreply.github.com>
…e uninstall sync, data-driven partition Agent-Logs-Url: https://github.com/microsoft/apm/sessions/12c01ced-bc96-4e31-a0fd-b6e147a0e167 Co-authored-by: danielmeppiel <51440732+danielmeppiel@users.noreply.github.com>
Add tests/unit/integration/test_data_driven_dispatch.py with 9 tests covering the data-driven integration dispatch refactoring: - TestTargetGatingRegression (5 tests): verify each target only dispatches its own primitives, empty targets return zeros, and all targets together dispatch all primitives. - TestExhaustivenessChecks (2 tests): structural guard ensuring every (target, primitive) pair has a dispatch path, and partition bucket keys match backward-compat aliases. - TestSyntheticTargetProfile (2 tests): prove a hand-built TargetProfile works end-to-end with real integrators, confirming the architecture is truly data-driven. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: danielmeppiel <51440732+danielmeppiel@users.noreply.github.com>
…thetic target tests, update CHANGELOG Agent-Logs-Url: https://github.com/microsoft/apm/sessions/12c01ced-bc96-4e31-a0fd-b6e147a0e167 Co-authored-by: danielmeppiel <51440732+danielmeppiel@users.noreply.github.com>
…files, fix test comment Agent-Logs-Url: https://github.com/microsoft/apm/sessions/12c01ced-bc96-4e31-a0fd-b6e147a0e167 Co-authored-by: danielmeppiel <51440732+danielmeppiel@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Refactor integrators to use TargetProfile data directly
Data-driven integration dispatch: replace if-chain with target × primitive loop
Mar 30, 2026
Collaborator
Contributor
There was a problem hiding this comment.
Pull request overview
Refactors integration/uninstall dispatch to a data-driven TargetProfile x primitive loop, replacing a large boolean-gated if-chain and reducing per-target boilerplate across integrators. This aligns integration behavior with KNOWN_TARGETS as the single source of truth and addresses prior target-gating regressions (e.g., opencode writing into .github/).
Changes:
- Replace boolean flag gating in
install.pywith a target-driven dispatch loop callingintegrate_*_for_target()methods. - Add target-driven APIs (
integrate_*_for_target,sync_for_target) to integrators while keeping legacy wrappers for backward compatibility. - Update uninstall sync/re-integration to iterate targets/primitives; add unit tests covering gating, dispatch exhaustiveness, and synthetic targets.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_uninstall_transitive_cleanup.py | Updates mocks to match new active_targets()-based uninstall reintegration flow. |
| tests/unit/integration/test_data_driven_dispatch.py | Adds regression/exhaustiveness tests for target x primitive dispatch and dynamic managed-file partitioning. |
| tests/unit/integration/test_command_integrator.py | Updates gating regression tests to use targets=[KNOWN_TARGETS[...]] and target-driven methods. |
| src/apm_cli/integration/prompt_integrator.py | Adds target-driven prompt integrate/sync entry points and keeps legacy API. |
| src/apm_cli/integration/instruction_integrator.py | Reworks instruction integration into integrate_instructions_for_target() with format_id-based transforms; adds sync_for_target() and legacy wrappers. |
| src/apm_cli/integration/hook_integrator.py | Adds a thin integrate_hooks_for_target() dispatcher preserving per-target hook logic. |
| src/apm_cli/integration/command_integrator.py | Adds integrate_commands_for_target() / sync_for_target() and rewires legacy methods to delegate. |
| src/apm_cli/integration/base_integrator.py | Makes partition_managed_files() generate buckets dynamically from KNOWN_TARGETS with backward-compat aliases. |
| src/apm_cli/integration/agent_integrator.py | Adds target-driven agent integrate/sync and consolidates filename logic via PrimitiveMapping. |
| src/apm_cli/commands/uninstall/engine.py | Updates uninstall cleanup + reintegration to target-driven loops using KNOWN_TARGETS / active_targets(). |
| src/apm_cli/commands/install.py | Implements target x primitive dispatch loop in _integrate_package_primitives() and switches call sites to pass targets. |
Comments suppressed due to low confidence (1)
src/apm_cli/commands/install.py:940
- CLI log messages use Unicode box-drawing characters (via \u2514\u2500) when reporting primitive integration results. This violates the repository ASCII-only output requirement and can cause encoding failures on Windows terminals. Use ASCII-only markers / bracket STATUS_SYMBOLS instead.
_log_integration(
f" \u2514\u2500 {_int_result.files_integrated} {_label} integrated -> {_deploy_dir}"
)
…target-gating Review comment fixes: - Replace Unicode box-drawing chars (U+2514, U+2500) with ASCII '|--' in install.py log messages (lines 913, 938) - Fix uninstall O(M*P) regression: use partition_bucket_key() for O(1) bucket lookup in engine.py instead of re-scanning sync_managed per (target, prim) - Make partition_managed_files truly O(M): replace linear prefix_map scan with (root_dir, subdir) component dict for O(1) path routing - Use mapping.extension instead of hardcoded '.md' in CommandIntegrator.integrate_commands_for_target() Issue #482 fix (skill target-gating): - Thread targets= parameter through SkillIntegrator.integrate_package_skill(), _integrate_native_skill(), _promote_sub_skills_standalone(), and standalone copy_skill_to_target(). Previously these called active_targets() internally, ignoring --target flag. Now the dispatch loop's target list is respected. Tests: - 8 new tests: 3 for skill target-gating (#482), 5 for partition_bucket_key Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Mar 30, 2026
This was referenced Mar 30, 2026
Merged
danielmeppiel
added a commit
that referenced
this pull request
Mar 31, 2026
…er, deps update) Merge main into PR #452 branch to resolve 11 conflict markers across 3 files: - CHANGELOG.md: trivial reorder of entries - install.py: merge scope + auth_resolver params, preserve both --global and data-driven dispatch architecture from PR #494 - engine.py: take main's data-driven sync loop which already uses project_root-relative paths (inherently scope-aware) Fix Rich line-wrapping in test_global_without_packages_and_no_manifest_errors by setting COLUMNS=200 to prevent mid-word path breaks. All 3198 unit tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
7 tasks
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.
Description
The ~200-line if-chain in
_integrate_package_primitives()used boolean flags (integrate_vscode,integrate_claude,integrate_opencode) to gate per-target method calls. Missing guards caused--target opencodeto write to.github/(#470). The integrators themselves had 20+ near-identical per-target methods (70–95% boilerplate), and path data was triple-encoded acrossKNOWN_TARGETS, the dispatch chain, and method bodies.This PR makes integrators consume
TargetProfiledirectly, collapsing per-target methods into parameterized ones.KNOWN_TARGETSbecomes the single source of truth.Integrators
Each file integrator gains
integrate_*_for_target(target: TargetProfile, ...)andsync_for_target(target, ...). Old per-target methods become thin wrappers for backward compat.integrate_package_agents(); dispatch loop handles each target independently.format_idselects content transform (cursor_rules→_convert_to_cursor_rules, else identity).integrate_hooks_for_target()dispatches bytarget.name(genuine algorithmic diversity preserved).Dispatch (
install.py)Uninstall (
engine.py)Phase 1 sync and Phase 2 re-integration both use target-driven loops over
KNOWN_TARGETS/active_targets()instead of per-integrator calls withshould_integrate_claude().Partition (
base_integrator.py)partition_managed_files()generates buckets dynamically fromKNOWN_TARGETSwith backward-compat aliases (agents_copilot→agents_github,instructions_cursor→rules_cursor, etc.). Adding a target or primitive auto-creates the bucket.Type of change
Testing
9 new tests added in
test_data_driven_dispatch.py:.github/, cursor-only skips.claude/, etc.(target, primitive)has a dispatch path; dynamic partition matches old hardcoded bucket keysTargetProfilewith customroot_dirworks with real integrators — proves adding a target needs no code changes