aim/.plans/007-source-provider-expansion/2026-03-20-source-provider-expansion-design.md

227 lines
No EOL
7.2 KiB
Markdown

# Source And Provider Expansion Design
## Goal
Expand install-source coverage beyond the current GitHub-centric path without collapsing providers, exact artifact sources, and update metadata into one abstraction.
## Problem Statement
The current codebase has a real mismatch between what the domain and adapter layers suggest is possible and what the end-to-end install pipeline actually treats as first-class:
- the domain source model already includes GitHub, GitLab, direct URL, and file
- the adapter layer also advertises SourceForge and zsync shapes
- the public source pipeline and most end-to-end behavior are still effectively GitHub-shaped
That creates two problems:
- adding new install origins risks becoming a copy of the GitHub path with provider-specific exceptions bolted on later
- `zsync` is at risk of being modeled as a provider even though the current code treats it primarily as update metadata
## Design Goals
- make `GitLab` a real repository-backed install source
- make `SourceForge` a real repository-backed install source
- preserve `direct-url` as a first-class exact-resolution source
- keep install origin semantics truthful in the registry
- allow provider-native update re-resolution where it fits naturally
- keep `zsync` as update metadata rather than forcing it into the install-source model
## Non-Goals
- generic search UX across all providers
- full behavioral parity across every provider in the first slice
- rewriting the CLI presentation layer
- promoting `zsync` into a first-class install source
- inventing a universal provider abstraction that erases real capability differences
## Architectural Decision
Separate three concerns explicitly:
- `source kind`: how the user identified the install origin
- `resolution strategy`: how the system turns that origin into a concrete installable artifact
- `update channel`: how an installed application later discovers newer payloads
Under this model:
- `GitHub`, `GitLab`, and `SourceForge` are repository-backed source kinds
- `direct-url` is an exact artifact source kind
- `file` remains a local artifact source kind
- `zsync` remains an update-channel and metadata mechanism
This keeps install and update semantics aligned without pretending every source type has provider-like behavior.
## Source Taxonomy
The input classification layer should classify user queries into a small, stable taxonomy:
- repository-backed sources
- GitHub
- GitLab
- SourceForge
- exact artifact sources
- direct URL
- local artifact sources
- file
Classification should answer only:
- what kind of source the user provided
- what canonical locator can be derived
- whether release or asset hints are present
- whether the origin is inherently trackable
Classification should not try to encode provider-specific release discovery beyond those normalized hints.
## Resolution Model
After classification, a resolver layer should convert a `SourceRef` into an installable release candidate.
### Repository-backed sources
Repository-backed resolution should:
- accept a canonical repository or project locator
- discover release or download candidates using provider-specific logic
- select a concrete AppImage payload when confidence is sufficient
- return explicit structured failures when the repository exists but no installable AppImage is available
This applies to:
- GitHub
- GitLab
- SourceForge
### Exact artifact sources
Exact-resolution sources should:
- treat the user-provided locator as the concrete payload origin
- derive best-effort metadata without pretending release discovery exists
- remain installable even when rich update tracking is unavailable
This applies to:
- direct URL
- file
## Registry Semantics
Registry persistence should preserve the truth about where the install came from.
Each installed record should continue to store:
- original source kind
- original source locator
- canonical locator when one exists
- installed version
- installed file metadata
The key rule is:
- install origin remains the origin the user chose
- update mechanisms are additive metadata, not a replacement source identity
That means a direct URL install remains a direct URL install even if metadata later yields a richer update channel. A GitLab install remains a GitLab install even if update planning later uses provider-specific release rediscovery.
## Update Strategy
Update planning should use the install origin as the primary re-entry point.
For repository-backed sources:
- prefer provider-native re-resolution using the canonical locator
- attach update channels discovered during metadata inspection as additional evidence
For exact-resolution sources:
- keep update support weak by default unless post-install metadata offers something stronger
For `zsync`:
- keep it as discovered metadata and update-channel input
- do not rewrite the install source as `zsync`
- do not require `zsync` install-source tests in this phase
This preserves a clean distinction between install origin and update mechanism.
## Error Handling
The design should distinguish unsupported semantics from runtime failure.
### Unsupported source semantics
Examples:
- malformed provider URL shapes
- a project URL form we do not support yet
- a provider source kind sent to the wrong resolver
These should fail early during classification or resolver selection with provider-aware messages.
### Resolvable source, but no installable artifact
Examples:
- repository exists but has no AppImage asset
- release metadata is present but incomplete
- multiple assets exist but none match install heuristics confidently
These should be structured resolution failures rather than generic unsupported errors.
### Transport or integration failure
Examples:
- HTTP download failures
- metadata fetch failures
- local staging or desktop integration failures
These remain operational failures in the existing install and update flow.
## Testing Strategy
Testing should expand along capability lines rather than provider-specific copy-paste.
### Classification tests
Add coverage for:
- GitLab source forms
- SourceForge source forms
- direct URL edge cases
- unsupported or malformed provider inputs
### Resolver contract tests
Each resolver should satisfy a shared contract:
- accepts valid source refs for its own kind
- rejects source refs for other kinds
- returns a concrete install candidate or a structured no-artifact result
### End-to-end flow tests
Add focused flow coverage for:
- install from GitLab source
- install from direct URL
- install from SourceForge source
- truthful registry origin persistence
- update planning that uses install origin plus additive metadata
### Non-goal tests
Do not force `zsync` into install-source tests for this phase.
## Rollout
Recommended rollout order:
1. normalize the source taxonomy and resolver interfaces
2. wire GitLab and direct URL cleanly through install and registry persistence
3. add SourceForge using the same resolver contract, limited to supported URL and project forms
4. extend update planning only where the source kind supports provider-native re-resolution naturally
5. leave `zsync` unchanged except to ensure it remains additive update metadata
This keeps the product honest: each added source gets explicit semantics instead of being forced through a renamed GitHub pathway.