A plugin.yaml with no __init__.py, desktop/plugin.js or plugin.json beside it
installs "successfully" and does nothing (pip-layout repos whose code sits under
src/ behind an entry point). The validator and catalog CI now fail that shape
and check declared Python dependencies parse and are index specs; direct-URL
requirements warn.
Tests: conflicting candidate refused with peers untouched; post-update re-apply
drops only the culprit and keeps the memory provider. Loader wording test
updated to the new hint.
Plugin dependency installs need two things the shared installer ladder did not
expose: a constraints file (so a plugin can never move a core pin) and a dry run
(so a conflict can be detected before anything is written). Both are threaded
through _venv_pip_install; the durable-target path keeps its own core
constraints and a dry run skips syspath activation and bytecode warming.