Skip to content

Architecture: all panels must be reactive via centralised Signals — Python Processes timer-polls instead #148

Description

@MelbourneDeveloper

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:

  • process-explorer.tsthis.processes, this.fetched, this.sortMode,
    this.groupMode, this.filterText
    (process-explorer.ts:180-185).
  • module-explorer.tsthis.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 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

  • No panel uses a setInterval/polling refresh; every panel re-renders from a
    centralised store Signal via effect().
  • The Python Processes list is driven by a store signal; the panel holds no
    mutable data of its own and the wireVisibilityRefresh timer is gone.
  • Mutable panel/view state (sort/group/filter/data) lives in the store, not in
    provider instance fields.
  • An e2e test asserts the process panel updates reactively from store state
    (no timer), cross-referencing the spec ID.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghigh-priorityHigh priority — schedule ahead of other feature work

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions