Skip to content

Surface the real Halibut connection log per machine

Placeholder ppxd requested to merge feat/connection-log-truth into main

Summary

  • An agent's operator-facing connection status was only MachineHealthStatus, derived from whether the last Capabilities probe succeeded — there was no way to see the actual transport-level story (connection opened, TLS/security negotiation, message exchange, listener accept, errors). A disconnected/flaky agent showed Unhealthy with no why.
  • The server's Halibut runtime was built with no log factory, so Halibut's per-endpoint connection events were unreachable. This wires Halibut's own bounded in-memory LogFactory via WithLogFactory, holds the singleton reference, and exposes the events per machine via GET /api/machine/{id}/connection-log (mirrors the upgrade-log endpoint).
  • The reader resolves the machine's Halibut endpoint URI the same way the health-check + dispatch paths do (poll://{subscriptionId}/ or https://host:port/, via EndpointJsonHelper) so it reads the right log, and projects Halibut's LogEvent into a transport-agnostic DTO (no Halibut type leaks past the service). Works for both polling and listening tentacles.

Design notes

  • Additive / non-breaking: a new read-only endpoint, a new reader service (IMachineConnectionLogReader, IScopedDependency), a thin handler (Rule 16), and a one-line runtime wiring that passes Halibut the same LogFactory type it already uses internally. No schema change (the log is an in-memory recent-events buffer, not persisted), no changed response shapes, no frontend impact.
  • The handler clamps the maxEntries query param to [1, 1000] (default 200). MachineView permission, same as the upgrade endpoints.

Test plan

  • Unit — EndpointJsonHelperConnectionUriTests: URI resolution for polling / listening / unknown-style / malformed / null
  • Unit — MachineConnectionLogReaderTests: projects type/message/error/time, returns most-recent-N in chronological order, resolves listening vs polling, empty for no-events / unknown machine / unresolvable endpoint
  • Unit — GetMachineConnectionLogRequestHandlerTests: entry-cap clamping (null→default, ≤0→1, >max→cap, in-range passthrough) + delegation + response wrapping
  • E2E — Agent_ConnectionLog_RecordsRealHalibutEvents_ForPollingEndpoint: a real Halibut RPC to a polling agent, then reads back non-empty, well-formed connection events — proves the WithLogFactory wiring AND that the polling endpoint is populated (ran green locally, 1/1)
  • Full unit suite: 5833/5833 green
  • Full solution build: 0 errors

Merge request reports

Loading