# Source And Provider Expansion Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** Make GitLab and SourceForge real repository-backed install sources, preserve direct URL as a first-class exact-resolution source, and keep zsync as update metadata rather than an install provider. **Architecture:** Normalize the source taxonomy first, then add a capability-shaped resolver layer that distinguishes repository-backed sources from exact artifact sources. Preserve truthful install origin data in the registry and let update planning attach richer metadata without rewriting source identity. **Tech Stack:** Rust, Cargo workspace, `aim-core` source and adapter modules, existing fixture-backed integration tests in `crates/aim-core/tests`, CLI end-to-end tests in `crates/aim-cli/tests`, existing registry and update planning code. ## Follow-up Status Task 1 hit a classification ambiguity blocker after the initial rollout. The follow-up design and execution live in `.plans/007-source-provider-expansion/2026-03-20-task-1-ambiguity-handoff-addendum.md`. Current state on this branch: - ambiguous GitLab deep paths and one SourceForge nested download path are now preserved as provider-owned candidate kinds during classification - the first GitLab candidate slice now resolves as a concrete repository-backed install source at the adapter layer - the SourceForge `files/releases/stable/download` candidate slice now resolves as a concrete latest-download install source at the adapter layer - the SourceForge `files/releases/v*/download` slice is now preserved as a provider-owned candidate and reports `NoInstallableArtifact` - unsupported queries remain distinct from provider-owned no-artifact outcomes Classifier policy for follow-up work: - accept explicit concrete shapes - accept explicit provider-candidate shapes - reject everything else Future changes should expand the allowlist deliberately rather than adding broad negative-rule coverage for every unsupported provider page family. --- ### Task 1: Lock down source taxonomy with failing classification tests **Files:** - Modify: `crates/aim-core/tests/query_resolution.rs` - Modify: `crates/aim-core/src/source/input.rs` - Modify: `crates/aim-core/src/domain/source.rs` **Step 1: Write the failing tests** Add classification tests that cover: - GitLab repository and release-like URL forms that should classify as `GitLab` - supported SourceForge URL forms that should classify as `SourceForge` - direct URLs that must remain `DirectUrl` - malformed provider URLs that must fail as unsupported **Step 2: Run test to verify it fails** Run: `cargo test --package aim-core --test query_resolution` Expected: FAIL because SourceForge is not yet part of the public source taxonomy and current classification rules are too narrow. **Step 3: Write minimal classification changes** Update the source domain and classifier so the public source taxonomy includes the approved source kinds and supported input forms without introducing zsync as an install source. **Step 4: Run test to verify it passes** Run: `cargo test --package aim-core --test query_resolution` Expected: PASS. **Step 5: Commit** ```bash git add crates/aim-core/tests/query_resolution.rs crates/aim-core/src/source/input.rs crates/aim-core/src/domain/source.rs git commit -m "test: cover expanded source taxonomy" ``` ### Task 2: Add a shared resolver contract for source capabilities **Files:** - Modify: `crates/aim-core/src/adapters/traits.rs` - Modify: `crates/aim-core/src/adapters/mod.rs` - Modify: `crates/aim-core/tests/adapter_contract.rs` - Modify: `crates/aim-core/src/app/query.rs` **Step 1: Write the failing tests** Add contract tests that assert: - repository-backed resolvers accept only their own source kinds - exact-resolution resolvers accept only exact artifact kinds - resolvers can return structured “no installable artifact” outcomes rather than collapsing to unsupported **Step 2: Run test to verify it fails** Run: `cargo test --package aim-core --test adapter_contract` Expected: FAIL because the current adapter trait does not distinguish source capability outcomes cleanly enough. **Step 3: Write minimal resolver contract changes** Refine the shared adapter or resolver contract to represent: - unsupported source kind - supported source with successful artifact resolution - supported source with no installable artifact found Keep the API small and do not add terminal concerns. **Step 4: Run test to verify it passes** Run: `cargo test --package aim-core --test adapter_contract` Expected: PASS. **Step 5: Commit** ```bash git add crates/aim-core/src/adapters/traits.rs crates/aim-core/src/adapters/mod.rs crates/aim-core/tests/adapter_contract.rs crates/aim-core/src/app/query.rs git commit -m "feat: add capability-shaped resolver contract" ``` ### Task 3: Make GitLab a real repository-backed install source **Files:** - Modify: `crates/aim-core/src/adapters/gitlab.rs` - Modify: `crates/aim-core/src/app/add.rs` - Modify: `crates/aim-core/tests/adapter_contract.rs` - Modify: `crates/aim-core/tests/install_integration.rs` - Modify: `crates/aim-cli/tests/end_to_end_cli.rs` **Step 1: Write the failing tests** Add tests that assert: - a GitLab source resolves to a concrete install candidate - install flow persists a truthful GitLab install origin - CLI integration can install a fixture-backed GitLab source end to end **Step 2: Run test to verify it fails** Run: `cargo test --package aim-core --test install_integration` Expected: FAIL because GitLab resolution is currently placeholder-level and not wired into the add flow meaningfully. **Step 3: Write minimal implementation** Implement GitLab-specific repository-backed resolution using the new resolver contract and thread the result through the add flow without changing direct URL or zsync semantics. **Step 4: Run test to verify it passes** Run: `cargo test --package aim-core --test install_integration` Expected: PASS. **Step 5: Commit** ```bash git add crates/aim-core/src/adapters/gitlab.rs crates/aim-core/src/app/add.rs crates/aim-core/tests/adapter_contract.rs crates/aim-core/tests/install_integration.rs crates/aim-cli/tests/end_to_end_cli.rs git commit -m "feat: add gitlab install source resolution" ``` ### Task 4: Preserve direct URL as an exact-resolution source **Files:** - Modify: `crates/aim-core/src/adapters/direct_url.rs` - Modify: `crates/aim-core/src/app/add.rs` - Modify: `crates/aim-core/tests/install_integration.rs` - Modify: `crates/aim-cli/tests/end_to_end_cli.rs` **Step 1: Write the failing tests** Add tests that assert: - direct URL installs continue to resolve exactly to the provided artifact - registry persistence keeps the original direct URL source kind and locator - no provider-like reclassification occurs after install **Step 2: Run test to verify it fails** Run: `cargo test --package aim-core --test install_integration` Expected: FAIL if the new resolver contract or registry changes accidentally regress exact-resolution behavior. **Step 3: Write minimal implementation** Adjust the direct URL path to use the new resolver interfaces while preserving exact-resolution semantics and best-effort metadata only. **Step 4: Run test to verify it passes** Run: `cargo test --package aim-core --test install_integration` Expected: PASS. **Step 5: Commit** ```bash git add crates/aim-core/src/adapters/direct_url.rs crates/aim-core/src/app/add.rs crates/aim-core/tests/install_integration.rs crates/aim-cli/tests/end_to_end_cli.rs git commit -m "feat: preserve direct url exact resolution semantics" ``` ### Task 5: Add SourceForge as a repository-backed source for supported project forms **Files:** - Modify: `crates/aim-core/src/adapters/sourceforge.rs` - Modify: `crates/aim-core/src/source/input.rs` - Modify: `crates/aim-core/src/app/add.rs` - Modify: `crates/aim-core/tests/adapter_contract.rs` - Modify: `crates/aim-core/tests/install_integration.rs` - Modify: `crates/aim-cli/tests/end_to_end_cli.rs` **Step 1: Write the failing tests** Add tests that assert: - supported SourceForge URL or project forms classify correctly - SourceForge resolution can produce a concrete install candidate - SourceForge installs persist truthful origin data **Step 2: Run test to verify it fails** Run: `cargo test --package aim-core --test adapter_contract` Expected: FAIL because SourceForge currently returns unsupported from its adapter. **Step 3: Write minimal implementation** Implement only the supported SourceForge project or download forms needed for exact current-product scope. Return structured no-artifact failures for valid-but-non-installable projects. **Step 4: Run test to verify it passes** Run: `cargo test --package aim-core --test adapter_contract` Expected: PASS. **Step 5: Commit** ```bash git add crates/aim-core/src/adapters/sourceforge.rs crates/aim-core/src/source/input.rs crates/aim-core/src/app/add.rs crates/aim-core/tests/adapter_contract.rs crates/aim-core/tests/install_integration.rs crates/aim-cli/tests/end_to_end_cli.rs git commit -m "feat: add sourceforge install source resolution" ``` ### Task 6: Keep registry origin truthful and update metadata additive **Files:** - Modify: `crates/aim-core/src/registry/model.rs` - Modify: `crates/aim-core/src/app/add.rs` - Modify: `crates/aim-core/src/app/update.rs` - Modify: `crates/aim-core/src/update/channels.rs` - Modify: `crates/aim-core/tests/update_planning.rs` - Modify: `crates/aim-core/tests/registry_roundtrip.rs` **Step 1: Write the failing tests** Add tests that assert: - GitLab and SourceForge installs preserve original source kind and locator after roundtrip persistence - direct URL installs remain direct URL installs after metadata inspection - discovered update channels augment stored state without rewriting source identity - zsync remains update metadata only **Step 2: Run test to verify it fails** Run: `cargo test --package aim-core --test update_planning` Expected: FAIL because update planning and registry expectations do not yet fully encode the approved source-versus-update split. **Step 3: Write minimal implementation** Adjust registry and update planning logic so install origin remains canonical and update channels remain additive metadata. **Step 4: Run test to verify it passes** Run: `cargo test --package aim-core --test update_planning` Expected: PASS. **Step 5: Commit** ```bash git add crates/aim-core/src/registry/model.rs crates/aim-core/src/app/add.rs crates/aim-core/src/app/update.rs crates/aim-core/src/update/channels.rs crates/aim-core/tests/update_planning.rs crates/aim-core/tests/registry_roundtrip.rs git commit -m "feat: preserve source identity through update planning" ``` ### Task 7: Improve provider-aware error reporting without changing CLI shape **Files:** - Modify: `crates/aim-core/src/adapters/traits.rs` - Modify: `crates/aim-core/src/app/add.rs` - Modify: `crates/aim-cli/src/lib.rs` - Modify: `crates/aim-core/tests/install_failures.rs` - Modify: `crates/aim-cli/tests/end_to_end_cli.rs` **Step 1: Write the failing tests** Add tests that distinguish: - unsupported source semantics - supported source with no installable artifact - transport or integration failure **Step 2: Run test to verify it fails** Run: `cargo test --package aim-core --test install_failures` Expected: FAIL because failure reasons are not yet structured enough to preserve those distinctions. **Step 3: Write minimal implementation** Introduce explicit failure categories and thread them through the add flow so the CLI can render clearer provider-aware messages without changing the progress UI architecture. **Step 4: Run test to verify it passes** Run: `cargo test --package aim-core --test install_failures` Expected: PASS. **Step 5: Commit** ```bash git add crates/aim-core/src/adapters/traits.rs crates/aim-core/src/app/add.rs crates/aim-cli/src/lib.rs crates/aim-core/tests/install_failures.rs crates/aim-cli/tests/end_to_end_cli.rs git commit -m "feat: clarify provider-aware source resolution failures" ``` ### Task 8: Full verification **Files:** - Modify: `README.md` - Modify: `crates/aim-core/tests/github_source_discovery.rs` - Modify: `crates/aim-core/tests/query_resolution.rs` - Modify: `crates/aim-core/tests/install_integration.rs` - Modify: `crates/aim-core/tests/update_planning.rs` - Modify: `crates/aim-cli/tests/end_to_end_cli.rs` **Step 1: Tighten any stale expectations** Update docs and tests so the product contract matches the approved design: - GitLab and SourceForge are install sources - direct URL remains exact-resolution - zsync remains update metadata **Step 2: Run focused workspace verification** Run: `cargo test --package aim-core --test query_resolution --test adapter_contract --test install_integration --test update_planning --test install_failures` Expected: PASS. **Step 3: Run CLI verification** Run: `cargo test --package aim-cli --test end_to_end_cli` Expected: PASS. **Step 4: Run full workspace verification** Run: `cargo fmt --all && cargo test --workspace` Expected: PASS. **Step 5: Commit** ```bash git add README.md crates/aim-core/tests/github_source_discovery.rs crates/aim-core/tests/query_resolution.rs crates/aim-core/tests/install_integration.rs crates/aim-core/tests/update_planning.rs crates/aim-core/tests/install_failures.rs crates/aim-cli/tests/end_to_end_cli.rs git commit -m "docs: align source provider contract and tests" ```