The mandate
Per the project architecture (CLAUDE.md): all state that can change uses
Signals for reactivity — no stale state on screen — and all state is centralised
in the single store file. Every panel must subscribe to centralised store
Signals; none may hold its own ad-hoc state or poll on a timer.
([EXTACT-REACTIVE-STATE], #58.)
The violation
The Python Processes panel breaks this. It is the only sidebar tree panel
that does not subscribe to the store's Signals — it refreshes itself on a
2-second setInterval poll:
- process-explorer.ts:442-468
— wireVisibilityRefresh() → setInterval(() => provider.refresh(), 2000)
(DEFAULT_REFRESH_MS = 2000). No effect(), no store signal.
Contrast with the two compliant panels:
The process panel is the odd one out, and the timer is exactly the "stale state /
poll" pattern the architecture forbids.
Secondary: panel-local state is not centralised
Even the compliant panels keep their data in local instance fields rather than
the single store file:
CLAUDE.md: "Each app has a single file for global state. No state should live
outside this file." This mutable view/data state belongs in the store as Signals,
with panels rendering from them — not held privately per provider.
(On-demand webviews — memory-dashboard.ts, memory-ref-graph.ts,
reference-graph.ts — render one-shot snapshots and likewise don't subscribe to
state. Lower priority, but same principle; track here.)
Required fix
- Python Processes must be reactive via centralised Signals, not a timer. Add
a centralised process-list signal to the store, fed by whatever source drives
it (the LSP basilisk.profiler.processes round-trip), and subscribe the panel
with an effect() exactly like Modules/Info. Delete the setInterval poll. If
the only available source is genuinely a poll (OS processes have no push event),
the poll belongs in the store updating a signal — not in the panel — so the
view stays a pure projection of centralised state.
- Move panel-local mutable state into the store as Signals; providers render
from store signals and own no mutable data of their own.
Cross-references
Acceptance criteria
The mandate
Per the project architecture (CLAUDE.md): all state that can change uses
Signals for reactivity — no stale state on screen — and all state is centralised
in the single store file. Every panel must subscribe to centralised store
Signals; none may hold its own ad-hoc state or poll on a timer.
([EXTACT-REACTIVE-STATE], #58.)
The violation
The Python Processes panel breaks this. It is the only sidebar tree panel
that does not subscribe to the store's Signals — it refreshes itself on a
2-second
setIntervalpoll:—
wireVisibilityRefresh()→setInterval(() => provider.refresh(), 2000)(
DEFAULT_REFRESH_MS = 2000). Noeffect(), no store signal.Contrast with the two compliant panels:
effect()tostore.analysisRevision(module-explorer.ts:458-470).
effect()tostore.lspState+store.client(info-panel.ts:154-161).
The process panel is the odd one out, and the timer is exactly the "stale state /
poll" pattern the architecture forbids.
Secondary: panel-local state is not centralised
Even the compliant panels keep their data in local instance fields rather than
the single store file:
process-explorer.ts—this.processes,this.fetched,this.sortMode,this.groupMode,this.filterText(process-explorer.ts:180-185).
module-explorer.ts—this.modules,this.workspace,this.viewMode,this.sortMode,this.filterPattern(module-explorer.ts:223-229).
CLAUDE.md: "Each app has a single file for global state. No state should live
outside this file." This mutable view/data state belongs in the store as Signals,
with panels rendering from them — not held privately per provider.
(On-demand webviews —
memory-dashboard.ts,memory-ref-graph.ts,reference-graph.ts— render one-shot snapshots and likewise don't subscribe tostate. Lower priority, but same principle; track here.)
Required fix
a centralised process-list signal to the store, fed by whatever source drives
it (the LSP
basilisk.profiler.processesround-trip), and subscribe the panelwith an
effect()exactly like Modules/Info. Delete thesetIntervalpoll. Ifthe only available source is genuinely a poll (OS processes have no push event),
the poll belongs in the store updating a signal — not in the panel — so the
view stays a pure projection of centralised state.
from store signals and own no mutable data of their own.
Cross-references
Refresh-button placement and the false "No Python processes running" message).
[EXTACT-REACTIVE-STATE](Type Health / Module Explorer panels are not reactive — require manual refresh (centralize state in store via Preact signals) #58),[PROFILE-PROCESSES-PANEL],[PROFILE-UI-GATE]—docs/specs/.architecture conformance must hold before the gate opens.
Acceptance criteria
setInterval/polling refresh; every panel re-renders from acentralised store Signal via
effect().mutable data of its own and the
wireVisibilityRefreshtimer is gone.provider instance fields.
(no timer), cross-referencing the spec ID.