Dispatch-miss repair line branches on why a plugin is inactive (LLP 0099, issue #297)#298
Conversation
…+ repair, not unknown (LLP 0098) Fixes #294 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…296) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…099, issue #297) The dispatch-miss availability hint (LLP 0098) always advised `add {"name": "<plugin>"} to plugins[]`. That is correct only when the plugin is absent from plugins[]. When the effective config already contains `{"name": "<plugin>", "enabled": false}` the entry lands in the boot pool but not the selected set, so the miss path fires and told the user to add an entry that already exists (issue #297, deferred from PR #296). Classify the inactive plugin into absent / disabled-local / disabled-central (the disabled entry belongs to central iff central declares its name, per the additive merge model in LLP 0031) and emit a case-appropriate repair: - absent: unchanged, byte-identical to LLP 0098. - disabled-local: set "enabled": true on the existing entry. - disabled-central: the fleet config disables it; it cannot be enabled locally. computeBootSelection now also returns the resolved layered config so the miss path can read the effective + central documents it already resolved (no extra I/O). Mint LLP 0099 extending LLP 0098's repair wording; add an Extended-by forward-ref on 0098. Regression tests (fail on the old single-line output, pass now) cover the disabled-local and disabled-central cases alongside the existing absent case. @ref LLP 0099, LLP 0098 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t absent-case test assertion CLAUDE.md forbids @typedef in JSDoc; inline the 'absent'|'disabled-local'| 'disabled-central' union literal at each of its three use sites in dispatch.js instead of naming it. Also tighten the absent-plugin repair-line assertion in dispatch-inactive-plugin.test.js to a byte-exact full-line equality check, so any drift in the LLP-0098-pinned wording (issue #294) fails the test instead of slipping past a prefix/regex match.
neutral PR-review round 1 — PR #298 (own neutral PR; stacked on #296)Path: dual-review (Codex + Claude, both ran — not a Codex fallback). Verdict: Verified (not trusting self-report)
Findings (both minor; both fixed this round)
Note for the human merger: this PR is stacked on PR #296 (base |
neutral PR-review round 2 (confirmation) — PR #298 — cleanLight confirmation review of the moved head
CI green on Merge order: this PR is stacked on PR #296 (base |
# Conflicts: # llp/0098-inactive-not-unknown-dispatch-miss.decision.md # src/core/cli/dispatch.js # test/core/dispatch-inactive-plugin.test.js
Neutral review round — verdict:
|
What
Follow-up to PR #296 (deferred review finding). Fixes the dispatch-miss repair line when a plugin entry exists but is disabled.
LLP 0098 (shipping in #296) made a dispatch miss on a known-but-inactive plugin command print
add {"name": "<plugin>"} to plugins[]. That advice is correct only when the plugin is absent fromplugins[]. When the effective config already contains{"name": "<plugin>", "enabled": false}, the entry lands in the boot pool but not the selected set (computeSelectedPluginsskipsenabled === false), so the miss path fires and tells the user to add an entry that already exists (issue #297).Fix
findInactivePluginForCommandnow classifies the inactive plugin into three states and emits a case-appropriate repair:repair: add {"name": "<plugin>"} to plugins[] in <path>repair: set "enabled": true on the {"name": "<plugin>"} entry in plugins[] in <path>repair: <plugin> is disabled by the fleet (central) config and cannot be enabled locally; ask your fleet admin to enable itThe disabled entry belongs to central iff central declares its name, because the additive merge model keys
plugins[]by name and drops a local entry colliding with a central one (collides_with_central), so a fleet-disabled plugin cannot be enabled locally (@ref LLP 0031#merge-model).computeBootSelectionnow also returns the resolved layered config, so the miss path reads the effective + central documents it already resolved - no extra I/O. The first output line and LLP 0098's exact-match / inactive-only / boot-selection-reuse constraints are unchanged.Ground-truth (fail -> pass)
Two regression tests added alongside
test/core/dispatch-inactive-plugin.test.js. On the unmodified src they fail; with the fix they pass.Assertion (disabled-local):
/^ {2}repair: set "enabled": true on the \{"name": "@hypaware\/context-graph"\} entry in plugins\[\] in /mrepair: add {"name": "@hypaware/context-graph"} to plugins[] in <path>(wrong: entry already exists)repair: set "enabled": true on the {"name": "@hypaware/context-graph"} entry in plugins[] in <path>npm test: 2148 pass, 0 fail, 1 skipped.tsc -p tsconfig.build.jsonclean.LLP
Mints LLP 0099 (
decision, Accepted) extending LLP 0098's repair wording (@ref LLP 0098/@ref LLP 0031); adds anExtended-by: LLP 0099forward-ref on immutable LLP 0098. Code annotated with@ref LLP 0099#decision [implements].Stacking
Stacked on
fix/issue-294(PR #296), which is not yet merged and carries the LLP 0098 code this change extends. Retarget tomaster(or merge after #296 lands) - base will collapse to just this commit once #296 merges.Fixes #297