644 lines
No EOL
22 KiB
Markdown
644 lines
No EOL
22 KiB
Markdown
# GitHub Source End-to-End Implementation Plan
|
|
|
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
|
|
**Goal:** Add end-to-end GitHub source support in `aim-core` for shorthand, repo URLs, release URLs, and direct asset URLs, with source-agnostic metadata parsing, install-origin-first channel selection, and registry-backed fallback channels.
|
|
|
|
**Architecture:** Reshape the current GitHub skeleton from an adapter-centric model into explicit `source`, `metadata`, and `update` boundaries. Keep `aim-cli` thin by moving normalization, metadata interpretation, channel ranking, and recovery behavior into `aim-core`, then extend the registry so future updates can survive upstream changes.
|
|
|
|
**Tech Stack:** Rust, Cargo workspace, serde, toml, reqwest-compatible fetch abstractions, clap, dialoguer, assert_cmd, predicates, fixture-driven tests in `crates/aim-core/tests` and `crates/aim-cli/tests`.
|
|
|
|
---
|
|
|
|
### Task 1: Introduce the new core boundary modules and types
|
|
|
|
**Files:**
|
|
- Create: `crates/aim-core/src/source/mod.rs`
|
|
- Create: `crates/aim-core/src/source/input.rs`
|
|
- Create: `crates/aim-core/src/source/github.rs`
|
|
- Create: `crates/aim-core/src/metadata/mod.rs`
|
|
- Create: `crates/aim-core/src/metadata/document.rs`
|
|
- Create: `crates/aim-core/src/update/mod.rs`
|
|
- Modify: `crates/aim-core/src/lib.rs`
|
|
- Modify: `crates/aim-core/src/domain/source.rs`
|
|
- Modify: `crates/aim-core/src/domain/update.rs`
|
|
- Test: `crates/aim-core/tests/query_resolution.rs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::source::input::{classify_input, SourceInputKind};
|
|
|
|
#[test]
|
|
fn classifies_github_release_asset_url() {
|
|
let input = classify_input(
|
|
"https://github.com/pingdotgg/t3code/releases/download/v0.0.11/T3-Code-0.0.11-x86_64.AppImage",
|
|
)
|
|
.unwrap();
|
|
|
|
assert_eq!(input.kind, SourceInputKind::GitHubReleaseAssetUrl);
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test classifies_github_release_asset_url --package aim-core --test query_resolution`
|
|
Expected: FAIL because the `source` module and new input classification types do not exist yet
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Add the new top-level modules and export them from `aim_core`. Introduce the minimum source and update domain types needed to classify GitHub inputs without rewriting existing workflows yet.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test classifies_github_release_asset_url --package aim-core --test query_resolution`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/lib.rs crates/aim-core/src/source crates/aim-core/src/metadata crates/aim-core/src/update crates/aim-core/src/domain/source.rs crates/aim-core/src/domain/update.rs crates/aim-core/tests/query_resolution.rs
|
|
git commit -m "feat: add source metadata and update module boundaries"
|
|
```
|
|
|
|
### Task 2: Implement GitHub input normalization across all supported entry forms
|
|
|
|
**Files:**
|
|
- Modify: `crates/aim-core/src/source/input.rs`
|
|
- Modify: `crates/aim-core/src/source/github.rs`
|
|
- Modify: `crates/aim-core/src/app/query.rs`
|
|
- Modify: `crates/aim-core/src/app/identity.rs`
|
|
- Test: `crates/aim-core/tests/query_resolution.rs`
|
|
- Test: `crates/aim-core/tests/identity_resolution.rs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::app::query::resolve_query;
|
|
use aim_core::domain::source::{NormalizedSourceKind, SourceInputKind};
|
|
|
|
#[test]
|
|
fn resolves_owner_repo_to_github_repo_source() {
|
|
let source = resolve_query("sharkdp/bat").unwrap();
|
|
assert_eq!(source.input_kind, SourceInputKind::RepoShorthand);
|
|
assert_eq!(source.normalized_kind, NormalizedSourceKind::GitHubRepository);
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test resolves_owner_repo_to_github_repo_source --package aim-core --test query_resolution`
|
|
Expected: FAIL because normalized GitHub source kinds are not represented yet
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Teach query resolution and identity normalization to recognize:
|
|
- `owner/repo`
|
|
- GitHub repo URLs
|
|
- GitHub release URLs
|
|
- direct GitHub release asset URLs
|
|
|
|
Preserve the original input while returning a normalized source reference that can later drive discovery.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test resolves_owner_repo_to_github_repo_source --package aim-core --test query_resolution`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/source/input.rs crates/aim-core/src/source/github.rs crates/aim-core/src/app/query.rs crates/aim-core/src/app/identity.rs crates/aim-core/tests/query_resolution.rs crates/aim-core/tests/identity_resolution.rs
|
|
git commit -m "feat: normalize github input forms"
|
|
```
|
|
|
|
### Task 3: Add GitHub discovery records for releases, assets, and linked metadata
|
|
|
|
**Files:**
|
|
- Modify: `crates/aim-core/src/source/github.rs`
|
|
- Modify: `crates/aim-core/src/domain/source.rs`
|
|
- Create: `crates/aim-core/tests/github_source_discovery.rs`
|
|
- Modify: `crates/aim-core/src/adapters/test_support.rs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::source::github::discover_github_candidates;
|
|
|
|
#[test]
|
|
fn discovery_reports_appimage_assets_and_latest_linux_yml() {
|
|
let discovery = discover_github_candidates(/* mocked github response */).unwrap();
|
|
|
|
assert!(discovery
|
|
.assets
|
|
.iter()
|
|
.any(|asset| asset.name.ends_with(".AppImage")));
|
|
assert!(discovery
|
|
.metadata_documents
|
|
.iter()
|
|
.any(|doc| doc.url.ends_with("latest-linux.yml")));
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test discovery_reports_appimage_assets_and_latest_linux_yml --package aim-core --test github_source_discovery`
|
|
Expected: FAIL because source discovery does not yet return structured assets and metadata document records
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Add GitHub discovery result types that expose:
|
|
- releases
|
|
- AppImage assets
|
|
- discovered metadata document URLs
|
|
- enough provenance to support later prompt and ranking logic
|
|
|
|
Use existing test-support scaffolding rather than real network calls.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test discovery_reports_appimage_assets_and_latest_linux_yml --package aim-core --test github_source_discovery`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/source/github.rs crates/aim-core/src/domain/source.rs crates/aim-core/src/adapters/test_support.rs crates/aim-core/tests/github_source_discovery.rs
|
|
git commit -m "feat: add github source discovery records"
|
|
```
|
|
|
|
### Task 4: Add source-agnostic metadata document and parser contracts
|
|
|
|
**Files:**
|
|
- Modify: `crates/aim-core/src/metadata/mod.rs`
|
|
- Modify: `crates/aim-core/src/metadata/document.rs`
|
|
- Create: `crates/aim-core/src/metadata/parser.rs`
|
|
- Modify: `crates/aim-core/src/domain/update.rs`
|
|
- Create: `crates/aim-core/tests/metadata_contract.rs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::metadata::{parse_document, MetadataDocument, ParsedMetadataKind};
|
|
|
|
#[test]
|
|
fn unknown_document_returns_typed_warning_not_panic() {
|
|
let doc = MetadataDocument::plain_text("https://example.test/notes.txt", b"not metadata");
|
|
let result = parse_document(&doc).unwrap();
|
|
|
|
assert_eq!(result.kind, ParsedMetadataKind::Unknown);
|
|
assert!(!result.warnings.is_empty());
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test unknown_document_returns_typed_warning_not_panic --package aim-core --test metadata_contract`
|
|
Expected: FAIL because the metadata parsing contract does not exist yet
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Define:
|
|
- metadata document input type
|
|
- metadata parse result type
|
|
- source-agnostic parser entry point
|
|
- typed warnings for unsupported or malformed documents
|
|
|
|
Keep the implementation minimal and independent from GitHub-specific code.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test unknown_document_returns_typed_warning_not_panic --package aim-core --test metadata_contract`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/metadata crates/aim-core/src/domain/update.rs crates/aim-core/tests/metadata_contract.rs
|
|
git commit -m "feat: add metadata parser contract"
|
|
```
|
|
|
|
### Task 5: Implement `electron-builder` Linux metadata parsing
|
|
|
|
**Files:**
|
|
- Create: `crates/aim-core/src/metadata/electron_builder.rs`
|
|
- Modify: `crates/aim-core/src/metadata/mod.rs`
|
|
- Test: `crates/aim-core/tests/metadata_electron_builder.rs`
|
|
- Create: `crates/aim-core/tests/fixtures/latest-linux.yml`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::metadata::{parse_document, MetadataDocument, ParsedMetadataKind};
|
|
|
|
#[test]
|
|
fn parses_latest_linux_yml_into_download_hints() {
|
|
let raw = include_bytes!("fixtures/latest-linux.yml");
|
|
let doc = MetadataDocument::yaml("https://example.test/latest-linux.yml", raw);
|
|
let result = parse_document(&doc).unwrap();
|
|
|
|
assert_eq!(result.kind, ParsedMetadataKind::ElectronBuilder);
|
|
assert_eq!(result.hints.primary_download.as_deref(), Some("T3-Code-0.0.11-x86_64.AppImage"));
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test parses_latest_linux_yml_into_download_hints --package aim-core --test metadata_electron_builder`
|
|
Expected: FAIL because `electron-builder` metadata is not parsed yet
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Add an `electron_builder` parser that extracts:
|
|
- version
|
|
- primary download artifact
|
|
- checksum or digest when present
|
|
- architecture hints when available
|
|
- parser confidence and warnings
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test parses_latest_linux_yml_into_download_hints --package aim-core --test metadata_electron_builder`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/metadata/electron_builder.rs crates/aim-core/src/metadata/mod.rs crates/aim-core/tests/metadata_electron_builder.rs crates/aim-core/tests/fixtures/latest-linux.yml
|
|
git commit -m "feat: parse electron builder linux metadata"
|
|
```
|
|
|
|
### Task 6: Implement zsync metadata parsing and channel hints
|
|
|
|
**Files:**
|
|
- Create: `crates/aim-core/src/metadata/zsync.rs`
|
|
- Modify: `crates/aim-core/src/metadata/mod.rs`
|
|
- Test: `crates/aim-core/tests/metadata_zsync.rs`
|
|
- Create: `crates/aim-core/tests/fixtures/example.zsync`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::metadata::{parse_document, MetadataDocument, ParsedMetadataKind};
|
|
|
|
#[test]
|
|
fn parses_zsync_document_into_channel_hints() {
|
|
let raw = include_bytes!("fixtures/example.zsync");
|
|
let doc = MetadataDocument::plain_text("https://example.test/app.AppImage.zsync", raw);
|
|
let result = parse_document(&doc).unwrap();
|
|
|
|
assert_eq!(result.kind, ParsedMetadataKind::Zsync);
|
|
assert!(result.hints.primary_download.is_some());
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test parses_zsync_document_into_channel_hints --package aim-core --test metadata_zsync`
|
|
Expected: FAIL because zsync parsing does not exist yet
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Add a zsync parser that extracts download URL, filename, version-like hints where possible, and channel confidence without coupling it to one upstream source.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test parses_zsync_document_into_channel_hints --package aim-core --test metadata_zsync`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/metadata/zsync.rs crates/aim-core/src/metadata/mod.rs crates/aim-core/tests/metadata_zsync.rs crates/aim-core/tests/fixtures/example.zsync
|
|
git commit -m "feat: parse zsync metadata documents"
|
|
```
|
|
|
|
### Task 7: Add update-channel ranking and artifact scoring
|
|
|
|
**Files:**
|
|
- Modify: `crates/aim-core/src/update/mod.rs`
|
|
- Create: `crates/aim-core/src/update/channels.rs`
|
|
- Create: `crates/aim-core/src/update/ranking.rs`
|
|
- Modify: `crates/aim-core/src/app/update.rs`
|
|
- Modify: `crates/aim-core/src/domain/update.rs`
|
|
- Modify: `crates/aim-core/tests/update_planning.rs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::update::ranking::rank_channels;
|
|
|
|
#[test]
|
|
fn install_origin_match_beats_higher_level_fallback() {
|
|
let ranked = rank_channels(/* preferred direct asset lineage */, /* github releases */, /* electron-builder */);
|
|
assert_eq!(ranked[0].reason.as_str(), "install-origin-match");
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test install_origin_match_beats_higher_level_fallback --package aim-core --test update_planning`
|
|
Expected: FAIL because channels and ranking reasons are not modeled yet
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Implement channel and artifact ranking rules for:
|
|
- install-origin-first preference
|
|
- stable-over-prerelease by default
|
|
- metadata-guided artifact selection ahead of filename heuristics
|
|
- ordered alternates retained for fallback
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test install_origin_match_beats_higher_level_fallback --package aim-core --test update_planning`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/update crates/aim-core/src/app/update.rs crates/aim-core/src/domain/update.rs crates/aim-core/tests/update_planning.rs
|
|
git commit -m "feat: add update channel ranking"
|
|
```
|
|
|
|
### Task 8: Extend the registry model for source input, strategy, and fallback channels
|
|
|
|
**Files:**
|
|
- Modify: `crates/aim-core/src/registry/model.rs`
|
|
- Modify: `crates/aim-core/src/registry/store.rs`
|
|
- Modify: `crates/aim-core/src/domain/app.rs`
|
|
- Modify: `crates/aim-core/tests/registry_roundtrip.rs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::registry::store::RegistryStore;
|
|
|
|
#[test]
|
|
fn registry_round_trips_update_strategy_and_alternates() {
|
|
let store = RegistryStore::new(/* temp path */);
|
|
let original = sample_record_with_strategy();
|
|
|
|
store.save(&[original.clone()]).unwrap();
|
|
let loaded = store.load().unwrap();
|
|
|
|
assert_eq!(loaded[0].update_strategy.preferred.reason, "install-origin-match");
|
|
assert_eq!(loaded[0].update_strategy.alternates.len(), 2);
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test registry_round_trips_update_strategy_and_alternates --package aim-core --test registry_roundtrip`
|
|
Expected: FAIL because the registry cannot persist the new strategy fields yet
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Extend the registry model to persist:
|
|
- original source input
|
|
- normalized source reference
|
|
- preferred channel
|
|
- ordered alternates
|
|
- selected metadata hints or snapshot references
|
|
|
|
Keep loading backward-compatible for existing records that lack these fields.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test registry_round_trips_update_strategy_and_alternates --package aim-core --test registry_roundtrip`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/registry/model.rs crates/aim-core/src/registry/store.rs crates/aim-core/src/domain/app.rs crates/aim-core/tests/registry_roundtrip.rs
|
|
git commit -m "feat: persist update strategy and fallback channels"
|
|
```
|
|
|
|
### Task 9: Wire the add flow through source discovery, metadata parsing, and channel selection
|
|
|
|
**Files:**
|
|
- Modify: `crates/aim-core/src/app/add.rs`
|
|
- Modify: `crates/aim-core/src/app/identity.rs`
|
|
- Modify: `crates/aim-core/src/source/github.rs`
|
|
- Modify: `crates/aim-core/tests/github_add_flow.rs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::app::add::build_add_plan;
|
|
|
|
#[test]
|
|
fn add_plan_prefers_metadata_guided_appimage_when_available() {
|
|
let plan = build_add_plan(/* github shorthand with latest-linux.yml */).unwrap();
|
|
|
|
assert_eq!(plan.selected_artifact.selection_reason, "metadata-guided");
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test add_plan_prefers_metadata_guided_appimage_when_available --package aim-core --test github_add_flow`
|
|
Expected: FAIL because add planning does not yet route through metadata-aware ranking
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Update add planning to:
|
|
- resolve normalized GitHub source input
|
|
- perform discovery
|
|
- parse any fetched metadata documents
|
|
- rank channels and artifacts
|
|
- emit a plan that records why the winning artifact was chosen
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test add_plan_prefers_metadata_guided_appimage_when_available --package aim-core --test github_add_flow`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/app/add.rs crates/aim-core/src/app/identity.rs crates/aim-core/src/source/github.rs crates/aim-core/tests/github_add_flow.rs
|
|
git commit -m "feat: wire add flow through source and metadata pipeline"
|
|
```
|
|
|
|
### Task 10: Add prompt context for older releases and ambiguous artifacts
|
|
|
|
**Files:**
|
|
- Modify: `crates/aim-core/src/app/interaction.rs`
|
|
- Modify: `crates/aim-core/src/app/add.rs`
|
|
- Modify: `crates/aim-cli/src/ui/prompt.rs`
|
|
- Modify: `crates/aim-cli/tests/ui_summary.rs`
|
|
- Modify: `crates/aim-cli/tests/end_to_end_cli.rs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::app::add::build_add_plan;
|
|
|
|
#[test]
|
|
fn direct_old_release_url_requests_tracking_choice_prompt() {
|
|
let plan = build_add_plan(/* direct old github asset url with newer releases available */).unwrap();
|
|
|
|
assert!(plan
|
|
.interactions
|
|
.iter()
|
|
.any(|item| item.key == "tracking-preference"));
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test direct_old_release_url_requests_tracking_choice_prompt --package aim-core --test github_add_flow`
|
|
Expected: FAIL because the flow does not surface the new prompt context yet
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Add typed prompt requests for:
|
|
- older explicit release versus latest-supported tracking
|
|
- ambiguous artifact ties after metadata and heuristics
|
|
|
|
Keep prompt rendering in `aim-cli`, but define the request shape in `aim-core`.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test direct_old_release_url_requests_tracking_choice_prompt --package aim-core --test github_add_flow`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/app/interaction.rs crates/aim-core/src/app/add.rs crates/aim-cli/src/ui/prompt.rs crates/aim-cli/tests/ui_summary.rs crates/aim-cli/tests/end_to_end_cli.rs
|
|
git commit -m "feat: add prompt support for github tracking choices"
|
|
```
|
|
|
|
### Task 11: Teach update planning to fall back when the preferred channel fails
|
|
|
|
**Files:**
|
|
- Modify: `crates/aim-core/src/app/update.rs`
|
|
- Modify: `crates/aim-core/src/update/ranking.rs`
|
|
- Modify: `crates/aim-core/tests/update_planning.rs`
|
|
- Modify: `crates/aim-cli/tests/end_to_end_cli.rs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::app::update::build_update_plan;
|
|
|
|
#[test]
|
|
fn update_plan_uses_alternate_channel_after_preferred_failure() {
|
|
let plan = build_update_plan(/* registry entry with failing preferred channel */).unwrap();
|
|
|
|
assert_eq!(plan.updates[0].selected_channel.kind.as_str(), "electron-builder");
|
|
assert_eq!(plan.updates[0].selection_reason.as_str(), "preferred-channel-failed");
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test update_plan_uses_alternate_channel_after_preferred_failure --package aim-core --test update_planning`
|
|
Expected: FAIL because update planning does not yet retry alternates
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Teach update planning to:
|
|
- evaluate the preferred channel first
|
|
- fall back through ordered alternates when the preferred path is stale, broken, or incompatible
|
|
- preserve an explanation for the fallback decision
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test update_plan_uses_alternate_channel_after_preferred_failure --package aim-core --test update_planning`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/app/update.rs crates/aim-core/src/update/ranking.rs crates/aim-core/tests/update_planning.rs crates/aim-cli/tests/end_to_end_cli.rs
|
|
git commit -m "feat: add update fallback channel behavior"
|
|
```
|
|
|
|
### Task 12: Remove or slim the legacy GitHub adapter entry points
|
|
|
|
**Files:**
|
|
- Modify: `crates/aim-core/src/adapters/mod.rs`
|
|
- Modify: `crates/aim-core/src/adapters/github.rs`
|
|
- Modify: `crates/aim-core/src/adapters/traits.rs`
|
|
- Modify: `crates/aim-core/tests/adapter_contract.rs`
|
|
- Modify: `crates/aim-core/tests/adapter_smoke.rs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```rust
|
|
use aim_core::adapters::github::GitHubAdapter;
|
|
|
|
#[test]
|
|
fn legacy_github_adapter_delegates_to_source_pipeline() {
|
|
let adapter = GitHubAdapter::default();
|
|
let result = adapter.normalize("sharkdp/bat").unwrap();
|
|
assert_eq!(result.normalized_kind.as_str(), "github-repository");
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test legacy_github_adapter_delegates_to_source_pipeline --package aim-core --test adapter_contract`
|
|
Expected: FAIL because the legacy adapter layer has not been reconciled with the new boundaries
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Either:
|
|
- slim the GitHub adapter into a compatibility wrapper over `source::github`, or
|
|
- reduce the adapter layer so it no longer owns metadata or ranking responsibilities
|
|
|
|
Do not leave duplicated GitHub logic in both places.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test legacy_github_adapter_delegates_to_source_pipeline --package aim-core --test adapter_contract`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add crates/aim-core/src/adapters/mod.rs crates/aim-core/src/adapters/github.rs crates/aim-core/src/adapters/traits.rs crates/aim-core/tests/adapter_contract.rs crates/aim-core/tests/adapter_smoke.rs
|
|
git commit -m "refactor: reconcile legacy adapter layer with source pipeline"
|
|
```
|
|
|
|
### Task 13: Run full verification and update top-level docs if needed
|
|
|
|
**Files:**
|
|
- Modify: `README.md`
|
|
- Modify: `.plans/001-github-source-end-to-end/2026-03-19-github-source-end-to-end-design.md`
|
|
- Modify: `.plans/001-github-source-end-to-end/2026-03-19-github-source-end-to-end-implementation-plan.md`
|
|
|
|
**Step 1: Run focused test suites**
|
|
|
|
Run: `cargo test --package aim-core --test query_resolution --test identity_resolution --test github_source_discovery --test metadata_contract --test metadata_electron_builder --test metadata_zsync --test github_add_flow --test update_planning --test registry_roundtrip`
|
|
Expected: PASS
|
|
|
|
**Step 2: Run full workspace verification**
|
|
|
|
Run: `cargo test --workspace`
|
|
Expected: PASS
|
|
|
|
Run: `cargo fmt --check`
|
|
Expected: PASS
|
|
|
|
Run: `cargo clippy --workspace --all-targets --all-features -- -D warnings`
|
|
Expected: PASS
|
|
|
|
**Step 3: Update docs minimally**
|
|
|
|
Document any visible changes to supported GitHub input forms or update behavior in `README.md`. Only update the design or plan docs if implementation forced a justified divergence.
|
|
|
|
**Step 4: Re-run doc-relevant tests if docs changed code examples**
|
|
|
|
Run: `cargo test --workspace`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add README.md .plans/001-github-source-end-to-end/2026-03-19-github-source-end-to-end-design.md .plans/001-github-source-end-to-end/2026-03-19-github-source-end-to-end-implementation-plan.md
|
|
git commit -m "docs: finalize github source end-to-end support"
|
|
``` |