Repository navigation
fix(marketplace): repo-scoped plugin ids — one contract for browse, install, and update - #43
Merged
Merged
Conversation
…nstall, and update
Multi-repo duplicate-id handling was incoherent: browse de-duplicated by id
("newest/whatever-wins"), install picked the FIRST repository that had the
id, and update flags scanned every repo. Ordering (repo insertion time) was
an implicit side effect and there was no provenance in install requests.
New, documented contract (docs/architecture.md, "Marketplace identity"):
- Browse returns ONE entry per (repository, plugin) — duplicate ids across
enabled repositories are never merged; every entry lists the other
publishers (`also_in_repos`) and is labelled `installed_elsewhere` when
the id is installed from a different repository.
- install(plugin_id, version, source_repo_id) — provenance is explicit and
recorded on InstalledPlugin.source_repo_id. Without a source, an id
published by >1 enabled repository is REFUSED as ambiguous (candidates
listed); a version/id the chosen repo does not publish is refused.
- update() re-installs from the repository the plugin was INSTALLED from —
never from whichever repo is checked first. latest_versions() is
source-aware so duplicate ids elsewhere never drive update badges.
- Duplicates are detected, not ignored: add/refresh-repository responses
carry conflict warnings; marketplace cards show "Also in: <repo>" inline.
- Config-as-code export now records source_repo_url per plugin; import
re-installs from the same repository URL.
UI: install/update/switch buttons pass source_repo_id; switching an id
installed from another repository is an explicit labelled action; conflict
warnings render as toasts + inline card warnings.
New arch test tests/architecture/test_marketplace_repo_identity.py pins the
contract (per-repo browse, ambiguity refusal, provenance recording, source-
aware update, conflict detection).
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.
Problem
Two halves of the same API disagreed about what a plugin id means: browse de-duplicated by id (last repo in query order wins, docstring claimed "newest"), install picked the first repository that had the id, and update/
latest_versions()scanned every repo. Repo insertion order was an implicit side effect; install requests carried no provenance (source_repo_idwas ignored).The contract (now single, documented in
docs/architecture.md→ "Marketplace identity")also_in_repos), and is flaggedinstalled_elsewherewhen the id is installed from a different repo.install(plugin_id, version, source_repo_id)records the source onInstalledPlugin.source_repo_id. Without a source, an id published by >1 enabled repo is refused as ambiguous (candidates listed) — never "first repo that has it". A version/id the chosen repo doesn't publish is refused.update()re-installs from the repo the plugin was installed from;latest_versions()is source-aware, so a duplicate id in a second repo never drives update badges or pulls in a different fork.source_repo_url; import re-installs from the same repository URL.Files
plugins/registry.py—list_available()per-repo;install(..., source_repo_id);_repos_publishing();repository_conflicts(); source-awareupdate()/latest_versions().plugins/api.py—/installacceptssource_repo_id; add/refresh return conflict warnings; export/import provenance.static/app.js— install/update/switch buttons send provenance; "Also in" + "installed from another repo" UI; warning toasts.docs/architecture.md— new "Marketplace identity" section.tests/architecture/test_marketplace_repo_identity.py— new: per-repo browse, ambiguity refusal, provenance, source-aware update, conflict detection.Verification