Skip to content

Chat action-dispatch: governor pause/resume #6521

Description

@JSONbored

Context

apps/loopover-miner-ui/src/routes/ledgers.tsx's GovernorControlSection (lines 60-114) is the only existing UI for governor pause/resume today — a "Pause governor" / "Resume governor" button pair, wired up by LedgersPage (lines 202-266). LedgersPage calls pauseGovernorAction/resumeGovernorAction (defaulted to pauseGovernor/resumeGovernor from apps/loopover-miner-ui/src/lib/governor.ts) inside runGovernorAction (lines 237-243), which flips an actionPending boolean (line 215) around the call so the buttons disable during the round-trip, then stores the returned GovernorPauseStateResult back into pauseState for GovernorControlSection to render.

lib/governor.ts exports GOVERNOR_PAUSE_API_PATH = "/api/governor/pause" and GOVERNOR_RESUME_API_PATH = "/api/governor/resume" (lines 7-8), and pauseGovernor(reason?) / resumeGovernor() (lines 71-78), which POST to those two routes and always resolve to a typed GovernorPauseStateResult ({ ok: true; pauseState } | { ok: false; error }) — network failures are caught and turned into the ok: false shape rather than thrown. Those two HTTP routes are served by apps/loopover-miner-ui/vite-governor-api.ts, whose own header comment is explicit that it is "a thin bridge to the EXISTING governor-state.js exports (loadPauseState/savePauseState)" — the same functions the CLI's governor pause/governor resume subcommands already use via packages/loopover-miner/lib/governor-pause-cli.js — and that it "never touches governor-chokepoint.js/governor-chokepoint-persisted.js." Pause/resume is administrative control over the governor, not a chokepoint-gated content-producing write like open_pr/file_issue, so it is intentionally a simpler, separate code path from those — there is nothing to route through the chokepoint here, only the existing HTTP API to reuse.

The miner dashboard redesign is adding a persistent chat rail to apps/loopover-miner-ui (mounted once in __root.tsx, surviving route navigation) that is action-capable in v1 for three narrowly-scoped action families: discover/attempt, portfolio release/requeue, and governor pause/resume — this issue is the governor pause/resume family. The safety case for chat being action-capable at all rests entirely on chat calling the exact same endpoints the existing buttons already call, through one shared dispatch layer, never a second path — the miner already has full local write autonomy over its own machine, so a chat input in front of controls that already exist as buttons creates no new privilege, provided it is genuinely the same controls and not a reimplementation.

This issue depends on, but does not itself build, two sibling pieces of this same redesign: the chat action-dispatch scaffolding issue (the shared action registry/execution layer plus its config flag, off by default) and the chat message-list issue (the inline chat surface this issue's result renders into). If either has not landed when this is picked up, this issue is blocked — do not build a local or parallel dispatch/render mechanism to route around a missing dependency. Beyond those two prerequisites, this issue calls an already-shipped endpoint through an already-designed dispatch contract: there is no open design question left to resolve here, only wiring two actions into it.

Requirements

⚠️ Read this before starting. This issue must not add, wrap, or duplicate any governor write logic. The only two calls this issue is allowed to make are pauseGovernor() and resumeGovernor(), exported from apps/loopover-miner-ui/src/lib/governor.ts, which already POST to /api/governor/pause//api/governor/resume. A PR that calls packages/loopover-miner/lib/governor-state.js (savePauseState/loadPauseState) directly, that adds a new /api/governor/* route (in vite-governor-api.ts or a new plugin), or that reimplements the POST body/fetch logic instead of importing the existing functions, does NOT satisfy this issue and will be closed.

  • Register two chat-dispatchable actions — governor_pause (accepting an optional reason: string) and governor_resume (no arguments) — with the chat action-dispatch layer, using whatever registration contract the scaffolding issue defines.
  • Each action's handler must call pauseGovernor(reason) / resumeGovernor() from apps/loopover-miner-ui/src/lib/governor.ts and return the same GovernorPauseStateResult union those functions already produce — do not narrow, rename, or re-shape that result before handing it to the dispatch layer's result plumbing.
  • Both actions must be gated behind the shared action-dispatch config flag introduced by the scaffolding issue — this issue must not read, define, or check a second, governor-specific flag.
  • Add the inline chat rendering for the result, reusing the exact copy already established in GovernorControlSection (ledgers.tsx:85-89): "Paused since <pausedAt> (<reason>)" when paused with a reason, "Paused since <pausedAt>" when paused without one, "Not paused" otherwise, and the existing error text "Could not read the local governor state: <error>" (ledgers.tsx:79-82) for the ok: false case — do not invent new wording for states this codebase already has copy for.
  • A pending/in-flight state must be surfaced in chat while the request is outstanding, mirroring LedgersPage's actionPending/runGovernorAction pattern (ledgers.tsx:215,237-243), so the chat surface never looks unresponsive during the POST round-trip.
  • The existing button-driven GovernorControlSection on the Ledgers route must be left functionally unchanged — this issue adds a second entry point to the same two functions, not a replacement for the first.

Deliverables

  • governor_pause/governor_resume action registrations, wired to pauseGovernor/resumeGovernor from apps/loopover-miner-ui/src/lib/governor.ts, gated behind the shared action-dispatch flag.
  • Inline chat result rendering for both actions (paused-with-reason, paused-without-reason, not-paused, and error states), reusing GovernorControlSection's existing copy verbatim.
  • A pending/in-flight indicator in chat for the duration of the POST round-trip.
  • Unit tests covering both action handlers' ok: true/ok: false branches and the pending state, at the same rigor as the existing apps/loopover-miner-ui/src/governor.test.tsx.

Test Coverage Requirements

apps/** is excluded from Codecov entirely (codecov.yml's coverage.ignore includes "apps/**"), so codecov/patch will not numerically gate this PR. That does not relax the bar: npm run test:coverage's local vitest backstop still runs over this code, and every new branch needs an explicit test — ok: true vs ok: false for both governor_pause and governor_resume, the pending-state render, and the paused-with-reason vs paused-without-reason vs not-paused render — mirroring the pattern already in apps/loopover-miner-ui/src/governor.test.tsx (e.g. its existing "renders an error message when the local API is unreachable" and paused/not-paused cases for GovernorControlSection). Add a regression test asserting the two action handlers call pauseGovernor/resumeGovernor (not governor-state.js directly, and not a hand-rolled fetch) so a future refactor can't silently reintroduce a parallel write path.

Expected Outcome

A miner operator can trigger a pause or resume from the chat rail and have it actually pause/resume the governor — through the identical /api/governor/pause//api/governor/resume calls the existing Ledgers-page buttons already make — with the result (paused state, reason, timestamp, or an error) shown inline in chat while it's pending and once it resolves. No new governor write path exists anywhere in the codebase; the action stays inert until the shared action-dispatch config flag is explicitly enabled per-install.

Links & Resources

  • apps/loopover-miner-ui/src/lib/governor.tspauseGovernor/resumeGovernor and the API path constants this issue must call, unchanged.
  • apps/loopover-miner-ui/vite-governor-api.ts — the server-side bridge those functions call into; not to be modified by this issue.
  • apps/loopover-miner-ui/src/routes/ledgers.tsxGovernorControlSection (lines 60-114) and LedgersPage (lines 202-266) for the existing button-driven precedent: copy, pending-state handling, and result shape.
  • apps/loopover-miner-ui/src/governor.test.tsx — the existing test file to mirror for coverage rigor.
  • packages/loopover-miner/lib/governor-state.js / governor-pause-cli.js — the underlying store and CLI equivalent (governor pause/governor resume); referenced for context only, not to be called directly from this issue's code.
  • The chat action-dispatch scaffolding issue (shared registry + config flag) — hard prerequisite; this issue registers into it rather than building its own dispatch mechanism.
  • The chat message-list issue — renders this issue's inline result; confirm its message shape before finalizing this issue's render output.
  • Sibling action-family issues in the same redesign: the portfolio release/requeue chat-action issue and the discover/attempt chat-action issue — same dispatch layer, same "call the existing endpoint, never a new one" constraint, different underlying calls.

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:featureGittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.help wantedExtra attention is needed

    Projects

    Status
    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions