14 KiB
v0.9 Finalisation Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Finalise v0.9 by hardening artifact downloads, enforcing checksum verification, making registry mutation safe, and shipping provider-extensible search with GitHub as the first provider while keeping custom-json deferred to v1.0.
Architecture: Push download, integrity, and registry safety down into aim-core, keep aim-cli as a thin dispatch and rendering layer, and add a provider-neutral search app flow that can grow to additional providers in phase 2 without changing the CLI contract.
Tech Stack: Rust, Cargo workspace, aim-core app/source/registry modules, aim-cli command parsing and rendering, reqwest blocking client, existing fixture-backed GitHub tests, CLI integration tests.
Task 1: Lock the v0.9 CLI and docs contract with failing tests
Files:
- Modify:
crates/aim-cli/src/cli/args.rs - Modify:
crates/aim-cli/tests/cli_commands.rs - Modify:
README.md - Modify:
.plans/008-v0-9-finalisation/2026-03-21-v0-9-finalisation-design.md
Step 1: Write the failing tests
Extend CLI help coverage so --help is expected to include search.
Step 2: Run test to verify it fails
Run: cargo test --package aim-cli --test cli_commands
Expected: FAIL because the CLI does not yet expose search.
Step 3: Write minimal implementation
Add a Search { query: String } subcommand to the CLI args and update the README command/query documentation to reflect:
aim search <query>exists in v0.9- SourceForge support is documented honestly
- search is GitHub-backed first and provider-extensible, not multi-provider complete
custom-jsonis not presented as a v0.9 feature
Step 4: Run test to verify it passes
Run: cargo test --package aim-cli --test cli_commands
Expected: PASS.
Step 5: Commit
git add crates/aim-cli/src/cli/args.rs crates/aim-cli/tests/cli_commands.rs README.md .plans/008-v0-9-finalisation/2026-03-21-v0-9-finalisation-design.md
git commit -m "feat: add v0.9 search command contract"
Task 2: Add failing GitHub search tests and a provider-neutral search model
Files:
- Create:
crates/aim-core/src/app/search.rs - Modify:
crates/aim-core/src/app/mod.rs - Create:
crates/aim-core/src/domain/search.rs - Modify:
crates/aim-core/src/domain/mod.rs - Modify:
crates/aim-core/src/source/github.rs - Create:
crates/aim-core/tests/search_github.rs
Step 1: Write the failing tests
Add search tests that assert:
- GitHub fixtures can return normalized remote search hits
- normalized results include provider id, display name, description, homepage/source locator, and install-ready query
- the app-level search result type can also carry installed/local matches and warnings
- default remote result limit is 10
- the install-ready query is canonical
owner/repo - remote hit ordering is stable under fixtures
Step 2: Run test to verify it fails
Run: cargo test --package aim-core --test search_github
Expected: FAIL because no search domain or app flow exists yet.
Step 3: Write minimal implementation
Add provider-neutral search domain types and the app-level search entry point in aim-core. Extend the GitHub source transport with the smallest search capability needed for fixture-backed repository search.
Keep the model narrow:
- one provider trait or equivalent provider entry shape
- one normalized result type
- no premature provider-specific knobs beyond what GitHub needs now
For v0.9, make the GitHub provider search repositories only. Preserve provider ranking order from fixtures or transport results, and use canonical locator as the deterministic tie-breaker when a secondary sort is needed.
Step 4: Run test to verify it passes
Run: cargo test --package aim-core --test search_github
Expected: PASS.
Step 5: Commit
git add crates/aim-core/src/app/search.rs crates/aim-core/src/app/mod.rs crates/aim-core/src/domain/search.rs crates/aim-core/src/domain/mod.rs crates/aim-core/src/source/github.rs crates/aim-core/tests/search_github.rs
git commit -m "feat: add provider-neutral search core"
Task 3: Wire aim search through dispatch and rendering
Files:
- Modify:
crates/aim-cli/src/lib.rs - Modify:
crates/aim-cli/src/ui/render.rs - Create:
crates/aim-cli/tests/search_cli.rs
Step 1: Write the failing tests
Add CLI integration tests that assert:
aim search batprints aSearch Resultsheading- remote GitHub hits render with provider label and install-ready query
- installed/local matches render in a separate section when the registry contains matching apps
- installed/local matches use case-insensitive substring matching across
stable_idanddisplay_name - installed/local matches are sorted deterministically by exact match, prefix match, substring match, then
stable_id - search remains read-only and does not mutate the registry
Step 2: Run test to verify it fails
Run: cargo test --package aim-cli --test search_cli
Expected: FAIL because dispatch and render do not know about search yet.
Step 3: Write minimal implementation
Add search dispatch to aim-cli, call into the new aim-core search flow, load registry state for local-match context, and render a stable read-only summary.
Do not add interactive selection or install-from-search behavior.
Step 4: Run test to verify it passes
Run: cargo test --package aim-cli --test search_cli
Expected: PASS.
Step 5: Commit
git add crates/aim-cli/src/lib.rs crates/aim-cli/src/ui/render.rs crates/aim-cli/tests/search_cli.rs
git commit -m "feat: wire search through cli"
Task 4: Add staged-download tests before changing the artifact pipeline
Files:
- Modify:
crates/aim-core/src/app/add.rs - Modify:
crates/aim-core/src/integration/install.rs - Modify:
crates/aim-core/tests/install_integration.rs - Create:
crates/aim-core/tests/download_pipeline.rs
Step 1: Write the failing tests
Add tests that assert:
- artifact download can stream into a staged path instead of returning full in-memory bytes
- the staged file reaches full byte count and still emits progress
- the install path can commit from a staged file source
- a failed download attempt does not leave a partial staged payload behind
Use fixture or local test doubles rather than real network calls.
Step 2: Run test to verify it fails
Run: cargo test --package aim-core --test download_pipeline
Expected: FAIL because the current add flow still downloads into Vec<u8>.
Step 3: Write minimal implementation
Refactor the add/install boundary so downloads are streamed into a staged file and the install integration path commits from disk.
Keep existing operation stages and user-facing progress events intact.
Make cleanup deterministic: if streaming, payload validation, or post-download verification fails, the staged file must be removed before returning the error.
Step 4: Run test to verify it passes
Run: cargo test --package aim-core --test download_pipeline
Expected: PASS.
Step 5: Commit
git add crates/aim-core/src/app/add.rs crates/aim-core/src/integration/install.rs crates/aim-core/tests/install_integration.rs crates/aim-core/tests/download_pipeline.rs
git commit -m "refactor: stream artifacts into staged payloads"
Task 5: Add retry and timeout policy to the download client
Files:
- Modify:
crates/aim-core/src/app/add.rs - Modify:
crates/aim-core/src/source/github.rs - Modify:
crates/aim-core/tests/download_pipeline.rs - Modify:
crates/aim-core/tests/github_source_discovery.rs
Step 1: Write the failing tests
Add focused tests that assert:
- the shared HTTP client is constructed with explicit timeout behavior
- download retries transient failures according to policy
- exhausted retries surface a clear failure
- retry exhaustion does not leave a staged payload behind
Prefer test doubles around client-building or download helpers over brittle timing assertions.
Step 2: Run test to verify it fails
Run: cargo test --package aim-core --test download_pipeline
Expected: FAIL because timeout and retry policy are not represented yet.
Step 3: Write minimal implementation
Introduce a small shared download client or helper configuration that both GitHub discovery and artifact download can use. Add explicit timeout configuration and retry loops for transient failures.
Do not add resume support in this slice unless it falls out naturally from the refactor; timeout and retry are the required behaviors.
Make the timeout contract explicit in code and tests. The implementation does not need user-facing configurability in v0.9, but it must use fixed non-infinite defaults.
Step 4: Run test to verify it passes
Run: cargo test --package aim-core --test download_pipeline
Expected: PASS.
Step 5: Commit
git add crates/aim-core/src/app/add.rs crates/aim-core/src/source/github.rs crates/aim-core/tests/download_pipeline.rs crates/aim-core/tests/github_source_discovery.rs
git commit -m "feat: add timeout and retry policy to downloads"
Task 6: Enforce checksum verification on install
Files:
- Modify:
crates/aim-core/src/app/add.rs - Modify:
crates/aim-core/src/integration/install.rs - Modify:
crates/aim-core/src/domain/update.rs - Modify:
crates/aim-core/tests/install_integration.rs - Create:
crates/aim-core/tests/checksum_verification.rs
Step 1: Write the failing tests
Add tests that assert:
- installs with a valid checksum succeed
- installs with a checksum mismatch fail before final payload commit
- installs without a checksum still succeed
- malformed trusted checksums fail before final payload commit
- checksum failure does not leave a staged payload behind
Use fixture metadata with deterministic payload bytes.
Step 2: Run test to verify it fails
Run: cargo test --package aim-core --test checksum_verification
Expected: FAIL because checksum hints are parsed but never enforced.
Step 3: Write minimal implementation
Thread checksum hints through artifact selection into install execution and verify the staged payload before the final rename. Surface a typed install failure for mismatch.
For v0.9, implement only the existing electron-builder checksum contract: compare the base64-encoded SHA-512 digest of the raw staged payload bytes against the trimmed sha512 metadata value. Treat malformed trusted checksum input as an install failure.
Step 4: Run test to verify it passes
Run: cargo test --package aim-core --test checksum_verification
Expected: PASS.
Step 5: Commit
git add crates/aim-core/src/app/add.rs crates/aim-core/src/integration/install.rs crates/aim-core/src/domain/update.rs crates/aim-core/tests/install_integration.rs crates/aim-core/tests/checksum_verification.rs
git commit -m "feat: verify artifact checksum before install"
Task 7: Make registry mutation atomic and locked
Files:
- Modify:
crates/aim-core/src/registry/store.rs - Modify:
crates/aim-cli/src/lib.rs - Create:
crates/aim-core/tests/registry_store.rs - Modify:
Cargo.toml - Modify:
crates/aim-core/Cargo.toml
Step 1: Write the failing tests
Add registry store tests that assert:
- saves write through a temp file and leave the final registry valid
- concurrent mutating access cannot silently race
- lock acquisition failure surfaces a clear error
- the locked mutation path reloads the latest registry before applying the final mutation
- read-only flows do not require the mutation lock
Step 2: Run test to verify it fails
Run: cargo test --package aim-core --test registry_store
Expected: FAIL because save is a direct fs::write with no lock semantics.
Step 3: Write minimal implementation
Implement atomic save and advisory locking in the registry store. Thread any needed lock lifecycle changes through the CLI mutating commands.
Keep read-only flows simple and avoid unnecessary lock retention.
The lock scope must be deterministic:
- do not hold the registry lock during network discovery, downloads, or desktop integration
- acquire the exclusive lock immediately before the final registry transaction
- reload the latest registry while the lock is held
- apply the mutation by
stable_id - save atomically, then release the lock
If a remove target disappears between pre-lock planning and the locked reload, fail cleanly instead of silently removing the wrong record.
Step 4: Run test to verify it passes
Run: cargo test --package aim-core --test registry_store
Expected: PASS.
Step 5: Commit
git add crates/aim-core/src/registry/store.rs crates/aim-cli/src/lib.rs crates/aim-core/tests/registry_store.rs Cargo.toml crates/aim-core/Cargo.toml
git commit -m "feat: add atomic and locked registry mutation"
Task 8: Run provider regression coverage and final verification
Files:
- Modify:
README.md - Modify:
.plans/008-v0-9-finalisation/2026-03-21-v0-9-finalisation-implementation-plan.md
Step 1: Add any missing regression expectations
If provider or CLI regressions appear during execution, add the smallest missing focused tests in the existing suites:
crates/aim-core/tests/query_resolution.rscrates/aim-core/tests/adapter_contract.rscrates/aim-core/tests/install_integration.rscrates/aim-core/tests/update_planning.rscrates/aim-cli/tests/end_to_end_cli.rs
Step 2: Run focused verification
Run:
cargo test --package aim-core --test search_github --test download_pipeline --test checksum_verification --test registry_store --test install_integration
cargo test --package aim-cli --test cli_commands --test search_cli --test end_to_end_cli
Expected: PASS.
Step 3: Run full verification
Run:
cargo fmt --all
cargo test --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
Expected: PASS.
Step 4: Commit
git add README.md .plans/008-v0-9-finalisation/2026-03-21-v0-9-finalisation-implementation-plan.md crates/
git commit -m "feat: finalize v0.9 reliability and search"