fix(pm): review fixes — enabled-state union, recency tiebreak, gated bridge, sync authority
Spec + standards review (2-subagent /code-review) found five real gaps against the settled design; all fixed: - enabled_member_dirs() now FILTERS by enabled state: only plugins in some profile's plugins.enabled join the union (a disabled plugin never syncs). Result is ENABLE-RECENCY-ORDERED (newest last) via new pm/plugins_state.py — order-preserving reads of every profile's enabled list — so the bisect's incumbent-wins tiebreak (pop last) now disables the most-recently-enabled, not the alphabetical last. - materialize_legacy_pyproject() is gated on lazy_installs_allowed(): lazy-off installs keep the plugin dir untouched (materializing would create a member candidate and then hard-fail every sealed sync). Settled: 'never runs when lazy installs are disabled'. - plugins_cmd dep install routes through resolve_union + the lazy gate (it previously drove lock_and_sync directly, bypassing both): the would-be union resolves as a check before enable, with the plugin's own bisect decision surfaced as the refusal reason. The real sync after enable still runs through sync_venv (the one authority, with receipt + write-back). - resolve_union disable decisions are written back to the plugins enabled config (record_disabled_plugins → pm.plugins_state. disable_plugins) so hermes plugins list reflects reality and re-enable retries; best-effort, never breaks the sync. tests: member discovery now asserts enabled-filter + recency order + orphan exclusion; plugins_state suite (5: cross-home reads, order preservation, disable write-back across homes, noop, garbage-config); materialize lazy-off test; deps_flow updated to the resolve_union shape. tests/pm + deps_flow: 193 passed, 0 failed.
This commit is contained in:
@@ -420,7 +420,7 @@ class Venv(StatePackage):
|
||||
# conflict, resolve_union bisects: fail-alone plugins and
|
||||
# mutual-conflict losers (incumbent wins) are dropped with
|
||||
# their resolver reasons, and the union retries.
|
||||
from pm.workspace import resolve_union
|
||||
from pm.workspace import record_disabled_plugins, resolve_union
|
||||
|
||||
import logging
|
||||
|
||||
@@ -433,6 +433,16 @@ class Venv(StatePackage):
|
||||
decision["plugin"],
|
||||
decision["reason"],
|
||||
)
|
||||
# Write bisect disables back to the plugins enabled config —
|
||||
# `hermes plugins list` must reflect reality and re-enable
|
||||
# must retry. Best-effort: a config write failure never
|
||||
# breaks the sync.
|
||||
try:
|
||||
record_disabled_plugins(decisions)
|
||||
except Exception:
|
||||
logging.getLogger(__name__).warning(
|
||||
"could not persist bisect disable decisions", exc_info=True
|
||||
)
|
||||
# Receipt: the machine-readable surface for this rebuild
|
||||
# (same schema/dir as update receipts; the updater embeds
|
||||
# these sections via pm.receipt.snapshot()).
|
||||
|
||||
Reference in New Issue
Block a user