Three plugin-deploy failures shared one root cause and one symptom:
1. The native adapter called Plugin.create / Plugin.update, which do not
exist in Saltcorn's Plugin model — so every install_plugin / update_plugin
was skipped with "method unavailable", leaving plugins uninstalled.
2. Because the json plugin never installed, the JSON field type it
registers was unavailable, cascading into "Unable to get the sql_type:
JSON" when creating dependent fields (e.g. metadata).
3. comparablePlugin compared source with strict equality, so a plugin that
is "local" in dev and "npm" in prod (same name + version) produced a
perpetual update_plugin that could never converge.
Fixes:
- tenant-adapters: route plugin install/update through the real Saltcorn API
(Plugin.loadAndSaveNewPlugin for installs, force=true for updates), with
an instance.upsert() fallback for older builds. Refresh state after each
install so plugin-provided types are registered before table/field ops.
- tenant-adapters: drop dead duplicate plugin branch in nonTableOps loop;
simplify drop_plugin to instance.delete(); align standalone installPlugin
and the capability report.
- planner: comparablePlugin now returns { name, version } only — source is
machine-specific and not portable. Filter builtin/bundled plugins from
both sides before diffing so they never surface as orphaned drift.
- routes/sync: pull per-row plugin adopts to plugins.lock.json (was writing
a stray objects/plugins/ file the loader ignores).
Adds 6 tests covering the installer path, upsert fallback, drop, and the
local-vs-npm no-drift case.