Skip to content

fix: start waits for the gateway, connected nodes points to new boards, paused log keeps rows, can state reads ok - #167

Merged
mottihoresh merged 4 commits into
mainfrom
fix/parked
Oct 18, 2026
Merged

mottihoresh merged 4 commits into
mainfrom
fix/parked

Conversation

@mottihoresh

Copy link
Copy Markdown
Contributor

The four parked items kept from the fix track (#135), prioritized 2026-10-18. Item PRs squash-merged into fix/parked:

Closes #159
Closes #160
Closes #161
Closes #162

BEGIN_COMMIT_OVERRIDE
fix(nodes): healthy CAN state reads "OK" instead of error-active
fix(nodes): connected nodes points to new boards on the bus instead of saying none are reported
fix(dcs): start with no gateway starts and waits for the board instead of being refused
fix(log): the stream keeps rows that arrive while paused and shows them on resume
END_COMMIT_OVERRIDE

**Today:** a board panel's CAN state row shows "error-active" for the
healthy CAN state (`panels.ts:241`), which reads like a fault.

**After:** the healthy state reads "OK"; bus-off and error-passive
unchanged. Display text only.

**Tests changed on purpose:** `panels.test.ts` (CAN state row) and
`t18-node-panel-status` (rendered row) expect "OK".

Closes #162
…f saying none are reported (#164)

## What

Connection › Connected nodes said "No nodes reported. Power on a
PanelGroup." while a board not yet added to the cockpit was on the bus
and reporting. With no board of your cockpit to count, the card now says
where the new ones are:

- 1 board: "1 new board on the bus — add it from the Cockpit."
- 2+ boards: "2 new boards on the bus — add them from the Cockpit."
- "No nodes reported. Power on a PanelGroup." only when the bus reports
nothing (none on it, or none identified yet).

When cockpit boards exist the card is unchanged.

## How

- `src/shared/nodes/ipc.ts` — `NodesSummary` gains `newCount` and
`empty` (the card's line when `known` is 0); `NO_NODES` constant used by
`COCKPIT_IDLE` and main.
- `src/main/nodes/cockpit-snapshot/summaries.ts` — `nodesSummary` takes
`newCount` from `newDevices(views, live)` (the Overview notice's count;
the same `isReportableNew` rule as the Cockpit's "New on the bus · N"),
and `emptyLine` builds the sentence in main, like the card's `footer`.
- `src/renderer/src/nodes/NodesCard.tsx` — the existing `hint` shows
`sum.empty` instead of the hard-coded text. No layout or styling change.

## Tests changed on purpose

- `src/main/nodes/cockpit-snapshot/connection-summary.test.ts` — new
`nodesSummary with no board of your cockpit (#160)`: 1 / 2 new boards →
count + wording; empty bus and a board still identifying → "No nodes
reported…".
- `src/renderer/test/t5-connection-nodes-card.test.tsx` — new case via
`emitScenario`: empty bus → old line; 1 and 2 new boards → new lines;
board added → normal card.

All three new tests fail on the old code. `npm run lint`, `lint:deps`,
`typecheck`, `npm test` (1464) pass.

Closes #160
…d of being refused (#165)

## What

In Bridge, and in Replay with Drive Gateway on, Start with no Gateway
was refused (`startBlocked`, enforced in `DcsRelay.start()`): the pill
flipped back to Stopped and main's reason never showed.

Start now always starts. With no board the relay runs and shows the
waiting reason a driven Replay already shows after a drop: gold pill +
"waiting for the Gateway" tooltip, the note under Start, the Overview's
"relay waiting — resumes when it connects". When the Gateway connects,
delivery begins with no further click.

## Changes

- `src/main/dcs/dcs-relay.ts` — `start()` no longer gated on the link;
it just runs.
- `src/main/dcs/relay-rules.ts` — `startBlocked()` and the
`startBlocked` surface fact removed.
- `src/shared/dcs/ipc.ts` — `RelaySurfaces.startBlocked` removed (type
change only; noted in `ipc.compat.test-d.ts` header).
- Renderer, now dead without the fact:
- `RelayPill.tsx` — the "!" mark, `aria-disabled`, and the "Can't start
the relay" callout + Connect button removed.
  - `RelayControls.tsx` — Start is never disabled.
- `relay-view.ts` — `startBlockedReason` / `startBlockedCallout`
removed; `relayNote` returns the text only, since its `info` flag was
only set for the blocked reason.
- `styles.css` — `.pill--blocked`, `.devpop__hint`, `.waitnote--info`
removed (only those used them).
- Still refused: Replay with no capture loaded ("No capture loaded"),
plus a transport that throws on start. The store's take-back of a
refused pending Start stays for those cases (comment updated).

## Tests

New (they fail on the old code):
- `pushed-rules.seam.test.ts` — Bridge with no board: Start → `running`,
`waiting: 'device'`, Overview `waiting`; the board arrives →
`delivering` and export reaches the board. Same for a driven Replay with
a capture.
- `t15-relay-pill.test.tsx` — Bridge / driven Replay with no board: a
click starts, the pill goes gold with the waiting-for-Gateway tooltip;
the board arriving clears it with no further click.

Updated because they pinned the old refusal:
- `src/main/dcs/relay-rules.test.ts` — "each side of the on/off": the
stopped side carries no `startBlocked`.
- `src/main/app/app-services.test.ts` — "refuses Start until the board
is connected…" → "starts with no board … and waits for the board" (now
also checks delivery once the board opens); "does not reconnect a
released link on Start" now expects `ok: true`; the Monitor/Replay test
expects a driven Replay to be refused only for having no capture.
- `src/main/app/pushed-rules.seam.test.ts` — "Bridge with no board:
Start blocked…" replaced (above); "toggle: … a refused Start pushes no
relay state" now refuses with a Replay that has no capture.
- `src/renderer/src/gateway/link-view.test.ts` — `startBlocked` /
`startBlockedReason` describes removed; `relayNote` expectations are
strings.
- `src/renderer/test/t15-relay-pill.test.tsx` — the three
blocked/callout tests ("blocked with '!'…", "the board arriving lifts
the block…", "Esc closes the callout…") replaced by the start-and-wait
test; `aria-disabled` checks removed.
- `src/renderer/test/t28-connection-relay-controls.test.tsx` — "Drive
Gateway … without a board it blocks Start" and "Bridge without a board:
Start is greyed out" now start and show the waiting note.

Closes #159
…em on resume (#166)

## What

Log › Pause held the Events view (rows recorded, shown on Resume), but
the Stream view dropped every `log:batch` that arrived while paused, so
that data was lost.

Now the stream holds those rows while paused and shows them on Resume,
within its existing 1000-row cap (the oldest fall off, as they do live).
The paused list stays frozen in the meantime.

## Changes

- `src/renderer/src/dcs/store.ts`
- `logBatch` no longer returns early while paused. It numbers the rows
as before and puts them in a new `private_held` list (newest first,
capped at `MAX_LOG`) instead of `log`.
- A subscription on the events store's pause adds `private_held` on top
of `log` when the pause turns off (Resume), capped at `MAX_LOG`.
  - `clearLog` empties `private_held` too.
- The pause stays owned by `src/renderer/src/events/store.ts`
(`logPaused` / `togglePause`, unchanged). Only its header comment was
updated to say the stream also reads it on Resume.
- `Log.tsx` is unchanged: no layout or styling change.

## Tests

`src/renderer/test/t23-log-stream.test.tsx`:
- Updated (it pinned the old behaviour): "Pause freezes the list: rows
that arrive while paused are dropped, not held (today)" became "Pause
freezes the list and holds what arrives; Resume shows it".
- New: "rows held while paused keep the list's cap: the oldest fall off
as they do live".
- New: "Clear while paused also drops what was held".

All three fail on the old code.

Closes #161
@mottihoresh
mottihoresh merged commit 9fe78d0 into main Oct 18, 2026
4 checks passed
@mottihoresh
mottihoresh deleted the fix/parked branch October 18, 2026 02:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant