feat(pulse): make every optional module switchable, and fix three flags that never worked - #1748
Open
elhoim wants to merge 1 commit into
Open
feat(pulse): make every optional module switchable, and fix three flags that never worked#1748elhoim wants to merge 1 commit into
elhoim wants to merge 1 commit into
Conversation
…d flags loadModules() gates on config.local_intelligence, config.hypotheses and config.upgrades, but loadPulseConfig() builds its return object key by key and never copies those three through. The gates read undefined, every one of them is written '?.enabled !== false', and undefined !== false is true — so all three modules always loaded and setting [local_intelligence] enabled = false in PULSE.toml silently did nothing. Fourteen more user-facing modules (docs, memory, conduit, books, synapse, ledger, projects, gear, atlas, threatmodel, usage, evals, algorithm, hermes) had no switch at all, and the HEALTH/FINANCES/BUSINESS/GROWTH surfaces have no module of their own to switch. Adds a [modules] table as the single place to turn a surface off, resolved in lib/modules.ts from three layers: defaults, the older [section].enabled flags, then [modules]. Existing configs need no changes and behave identically — the shipped defaults leave everything on except the opt-in imessage and syslog. GET /api/config/modules exposes the resolved map so the dashboard can hide a disabled module's tab. Infrastructure Pulse needs to serve anything at all (observability, hooks, tab-freshness, menubar, siri, doctor) is deliberately not switchable.
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.
The bug underneath this
loadModules()gates three modules on config thatloadPulseConfig()never supplies:loadPulseConfig()builds its return object key by key and copies throughvoice,imessage,observability,performance,syslog,work,bunker,content,telos,hooks,da— but not those three. They're declared onPulseConfig, so it typechecks. At runtime the gate readsundefined,undefined !== falseistrue, and the module loads every time.Net effect:
[local_intelligence] enabled = falsein PULSE.toml has never done anything. Same for[hypotheses]and[upgrades].The wider gap
Fourteen more user-facing modules had no switch at all —
wiki,memory,conduit,books,synapse,ledger,projects,assets,atlas,threatmodel,usage,evals,algorithm-tab,hermesare unconditionalawait import(...). And HEALTH / FINANCES / BUSINESS / GROWTH have no module of their own —observability.tsserves them at/api/life/*— so there was nothing to switch even in principle. GROWTH is the sharpest case: it's backed by an optional USER customization that isn't shipped, so out of the box its API returnsnote: "Growth is an optional customization; not installed."and the tab renders an empty page with no way to remove it.Change
lib/modules.ts(new) —MODULE_DEFAULTSplusresolveModules(), layering defaults ← legacy[section].enabledflags ← the[modules]table. Pure and importable;pulse.tscallsmain()at import time so nothing in it can be unit-tested.lib.ts— re-export.pulse.ts—PulseConfig.modules;loadPulseConfig()returnsresolveModules(parsed)(this is the passthrough fix); 12 existing gates repointed at the map; 14 previously ungateable modules wrapped;GET /api/config/modules; a route guard for the four/api/life/*surfaces that have no module.PULSE.toml— documented[modules]table.Infrastructure Pulse needs to serve anything at all — observability, hooks, tab-freshness, menubar, siri, doctor — is deliberately not switchable; a disabled one leaves a dashboard that can't render.
Compatibility
Existing configs need no changes. Legacy
[section].enabledflags still work and still win over the defaults. Shipped defaults leave everything on except the already-opt-inimessageandsyslog.Verification
resolveModulesagainst the shipped PULSE.toml and four synthetic configs:imessage,syslogoff — no behaviour change[modules]local/growth = false[local_intelligence].enabled = falselocalfalse — the switch that previously did nothingtelos = "yes")MODULE_DEFAULTSbun build --target=bun --no-bundleparses clean onpulse.tsandlib/modules.ts.Ported to my own install (which predates the synapse/ledger/atlas/hermes split, so the key set differs) and ran it live with
local = false: Pulse boots,LocalIntelligence module loadedis absent from the current boot's journal,/api/local-intelligence/latest→ 404,/api/config/modulesreportslocaloff among 26 keys.Not run: a fresh-system install verification (step 3 of the contributing process).