Skip to content

fix(dcs): one relay endpoint label, record only while relaying, waiting wording matches the mode - #156

Merged
mottihoresh merged 1 commit into
fix/chunk-5from
fix/c5a-relay
Oct 17, 2026
Merged

mottihoresh merged 1 commit into
fix/chunk-5from
fix/c5a-relay

Conversation

@mottihoresh

Copy link
Copy Markdown
Contributor

Part of #134 (chunk 5): X9, X12, N2 and N3. All four live in dcs/relay-rules.ts and are pushed on relay:facts. The renderer only reads them.

X9: one endpoint label

  • Today: the Relay pill and the Overview DCS Link tile each build their own endpoint, and the two disagree. TCP showed host:port on the pill and host:port · remote on the tile. Unicast showed unicast listen on the pill and 239.255.50.10:5010 · local (the multicast group) on the tile. Both used the host and port as typed in the renderer's form.

  • After: there is one relayEndpoint() in relay-rules.ts, built from the settings main holds and pushed as RelayFacts.endpoint (a string). The pill tooltip, the DCS Link tile and the event log's relay rows all show it. The label per transport:

    • TCP: host:commandPort
    • Multicast: 239.255.50.10:5010
    • Unicast: 0.0.0.0:listenPort (the transport binds listenPort on every address)

    relay-events.ts used to build its own copy of this label; it now calls relayEndpoint(). EndpointLabel, pillEndpoint, overviewEndpoint and the renderer's endpointText were removed. The title bar no longer passes host and port to the pill.

X12: Record only while relaying

  • Today: Settings › Connection's Record is enabled even while the relay is stopped. The Connection tab's Record card is enabled only while relaying.
  • After: both read the same RelaySurfaces.canRecord boolean, from canRecord(relaying, recording). A recording can start only while relaying. A recording that is already running can always be stopped, so stopping the relay mid-recording never leaves a recording you can't stop. Main also enforces the rule: DcsRelay.mayRecord() is checked first in capture:toggle, so a refused Start never opens the save dialog. The save dialog still opens when a recording starts.

N2: no device-waiting wording in Monitor

  • Today: the Overview Link tile says "relay waiting — resumes when it connects" whenever a relay runs with the link down, Monitor included.
  • After: "waiting" follows the same rule as the pill and the note under Start: it shows only while the relay waits for the board. Monitor and an undriven Replay show a new running value, worded "stream running".

N3: a driven Replay shows the waiting reason

  • Today: "waiting for the Gateway" shows in Bridge only.
  • After: waitingForDevice uses exportToDevice (Bridge, or Replay with Drive Gateway on). So a driven Replay that loses the board now shows the waiting reason: the pill tooltip says it waits for the Gateway and turns gold, the note under Start says the same, and the Overview says "relay waiting". startBlocked uses the same exportToDevice rule.

Tests changed on purpose

  • relay-rules.test.ts: the X9, X12, N2 and N3 blocks that pinned the old behaviour were rewritten: the per-surface endpoints, the per-surface canRecord, "waiting in every mode", and "a driven Replay is never waiting". The facts test now expects a driven Replay running with no board to show waiting-device.
  • pushed-rules.seam.test.ts: the config:edit facts test now expects the Unicast endpoint 0.0.0.0:5010. New seam tests cover X9 (all three transports from the settings main holds), X12 (refused while stopped with no dialog, allowed while relaying, stoppable after Stop), N2 (Monitor with no Gateway is running) and N3 (a driven Replay that loses the board waits for it).
  • link-view.test.ts: the relay inputs carry replayDriveSerial, and relayWaiting gains a driven-Replay case.
  • t27: the DCS Link tile expectations are now the shared label, without the · remote / · local suffix, and Unicast shows its listen port. The old "reconnecting while relaying" Link case is now Bridge, since Monitor no longer waits. New cases: Monitor with no board reads "stream running"; a driven Replay reads "relay waiting"; the pill and the DCS Link tile show the same endpoint in <App /> for TCP, Multicast and Unicast.
  • t31: Settings › Connection's Record is disabled while stopped and enabled once relaying. This was contract B62; the comment noting the old behaviour was removed.
  • t15 / t28: new tests. A driven Replay with no board shows the waiting reason on the pill and in the note under Start. An undriven Replay just plays. Monitor with no board has no waiting wording.

With the production files reverted to the base branch, 25 of these tests fail. Both the main and renderer tests catch every item.

How verified

npm run lint, npm run lint:deps, npm run typecheck and npm test all pass (1414 tests). The API guard header records the type change: no channel, intent or method was renamed. Still to do: the on-device checklist in #134.

…ng wording matches the mode

X9: relay-rules relayEndpoint is the one endpoint label, pushed as relay:facts.endpoint and
read by the Relay pill, the Overview DCS Link tile and the event log: host:port for TCP, the
multicast group for loopback, 0.0.0.0:listenPort for Unicast.

X12: one canRecord rule for the Connection card and Settings > Connection: a recording starts
only while relaying, one already on can always be stopped. Main refuses capture:toggle before
the save dialog when the rule says no.

N2: the Overview Link tile says "relay waiting" only while the relay waits for the board;
Monitor and an undriven Replay read "stream running".

N3: a Replay driving the Gateway waits for the board as Bridge does: the pill, the note under
Start and the Overview show the waiting reason.

Part of #134.
@mottihoresh
mottihoresh merged commit 8c48345 into fix/chunk-5 Oct 17, 2026
3 checks passed
@mottihoresh
mottihoresh deleted the fix/c5a-relay branch October 17, 2026 18:31
mottihoresh added a commit that referenced this pull request Oct 17, 2026
…saved on commit with validation, psu fields follow imports (#157)

Part of chunk 5 (#134): items X10, N5 and N8. Base: `fix/chunk-5`.

## X10: one telemetry spec
- **Today:** the idle placeholders are their own spec. IAS and Press Alt
read `% FS` until the first telemetry tick, then switch to kt and ft.
Press Alt's idle id was `D_ALT_NEEDLE`, not `ALT_FT`.
- **After:** there is one spec, `TELEMETRY` in
`main/dcs/sim-telemetry-decoder.ts`. `idleTelemetry()` returns the
decoder's live readouts with nothing decoded yet, so the gauges show kt,
ft and % from the start. The contract's `TELEMETRY_IDLE`
(`shared/dcs/ipc.ts`) is the renderer's starting value. A test pins it
to the decoder's output.
- **Side effect:** the idle Press Alt ring now uses the secondary tone,
the same as the live Press Alt ring. Before, the idle ring was primary
and only switched to secondary on the first tick. This follows from
having one spec.

## N5: host and port
- **Today:** the host and port are saved on every keystroke, and a port
that isn't a number silently saves as 7778.
- **After:** typing saves nothing. The field is saved on commit (blur or
Enter). Main checks the port in `settings-form.ts` `commandPortOf`,
which accepts whole digits from 1 to 65535. A bad port saves nothing and
pushes nothing. `config:edit` then answers `{ ok: false, error }` (new
`ConfigEditResult`). Both the Settings › Connection form and the
Connection tab's DCS Link form show main's error using the existing
`input--bad` / `aria-invalid` outline and `set-err` text. No new CSS. A
blur that follows an Enter with nothing new typed sends nothing. An
import resets the typed text and the error.
- **API guard:** `editConfig` now answers `ConfigEditResult` instead of
`AppConfig`. The frozen copy is updated on purpose, with a header note.
No channel was added, removed or renamed.

## N8: PSU limit fields
- **Today:** Settings › Cockpit's custom-limit fields hold their own
typed text, which is never refreshed after an import replaces the
settings.
- **After:** an import (and `config:get`) bumps the config store's
`formsReset`. `PowerSupply` is keyed on it, so the fields restart from
the pushed config. This works the same way as the other form fields,
which restart from the config on an import. A form's own edit still
leaves its typed text alone.

## Tests changed on purpose (they pinned the old behaviour)
- `sim-telemetry-decoder.test.ts`: the "idle readouts are their own
spec" test becomes "one spec": idle equals the live snapshot, with units
`% RPM / kt / % DN / ft / % QTY`. A new test checks that the first frame
keeps the idle ids, labels and units.
- `t27`: the idle gauges read `—kt` / `—ft` instead of `—% FS`.
- `settings-edit.test.ts`: removed the "junk port saves as 7778"
assertions. Added tests for `commandPortOf`, for a junk port being
refused with its error, and for `SettingsService.edit` saving and
pushing nothing on a junk port. Updated the tests for the new
`SavedEdit` / `ConfigEditResult` shapes.
- `pushed-rules.seam.test.ts`: `config:edit { port: '77a' }` is refused
with the error. `config.json` and `config:get` keep the last good port,
and no `config:changed` is pushed.
- `t28` / `t31`: "saved as typed" becomes "saved on commit". These tests
check that typing saves nothing, that blur and Enter each save, and that
a blur after Enter does not send again. New tests check that a junk port
shows the error with `aria-invalid` and saves nothing, and that a good
port then saves and clears the error.
- `t29` (new): renders the Cockpit and Configuration sections together.
A typed (refused) limit is followed by an import with other limits, and
the fields show the imported limits.
- `skyhawk-mock.ts`: `editConfig` answers `ConfigEditResult` the way
main does.

All new and changed tests fail on the old source. I checked this by
stashing the non-test changes: 16 tests failed.

## How verified
`npm run lint`, `npm run lint:deps`, `npm run typecheck` and `npm test`
(1421 tests) all pass locally, after rebasing onto `fix/chunk-5` at
8c48345 (#156). I have not tested on the DCS computer yet; that belongs
in the chunk 5 device session.
mottihoresh added a commit that referenced this pull request Oct 18, 2026
…etry in real units, port validated on commit (#158)

Chunk 5 of the fix track (#135): relay, telemetry and the settings form.
Closes #134.

Item PRs squash-merged into `fix/chunk-5`:
- #156 — one `relayEndpoint` label for the pill, the Overview and the
event log, correct per transport (Unicast reads "this PC:<port>");
Record only while relaying (or to stop a recording in progress), in
Settings and on the Connection card, enforced in main before the save
dialog; no device-waiting wording in Monitor; a Replay that drives the
device shows the same waiting reason as Bridge.
- #157 — one telemetry spec: idle gauges read kt/ft/% from the start;
host and port are saved on commit (blur/Enter), a bad port shows an
error and nothing is saved; the PSU custom-limit fields refresh after an
import.

Tested with a recorded replay before merge (checklist in #134); a live
DCS session goes on the v0.2.0 QA run. Rebased on main after chunk 4.

BEGIN_COMMIT_OVERRIDE
fix(dcs): one relay endpoint label, record only while relaying, waiting
wording matches the mode
fix(settings): telemetry in real units from the start, host and port
saved on commit with validation, psu fields follow imports
END_COMMIT_OVERRIDE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant