Skip to content

Let a custom transport work without socket paths, and document it - #124

Open
bensheldon wants to merge 2 commits into
basecamp:masterfrom
bensheldon:transport-without-directory
Open

bensheldon wants to merge 2 commits into
basecamp:masterfrom
bensheldon:transport-without-directory

Conversation

@bensheldon

Copy link
Copy Markdown

This makes the transport: option of HotCell.register usable without a socket directory, and documents its contract as public API.

1. A cell with its own transport is enabled without a directory

Cell#enabled? now returns true when the cell has a transport: other than HotCell::Transport::Socket, even without HotCell.root or dir:.

# Before: a placeholder dir: was needed, or every call raised HotCell::CellNotConfigured
HotCell.register "media", dir: "/unused/media", transport: RelayTransport.new

# After
HotCell.register "media", transport: RelayTransport.new

2. Transports can receive a kind: and make socket optional

# Before
def call(cell, line, descriptors, socket: cell.work_socket, timeout: cell.timeout)

# After
def call(cell, line, descriptors, kind:, timeout:)   # kind is :work or :control
  • kind: :work is an operation; kind: :control is describe or metrics.
  • HotCell::Transport::Socket turns the kind into the socket path, and still accepts socket: to name a path directly.
  • The client now passes timeout: on every call, for work as well as control, so the contract is the same for both.

3. Documentation

docs/client-api.md has a new Use your own transport section, with:

  • the arguments that call receives;
  • what it returns;
  • how to report a failure to reach the cell.

The register options table also lists transport:.

Why

  • Discussion #107 describes transport: as the way to reach a cell without passing descriptors over its UNIX socket, and offers to document its contract.
  • hotcell-remote uses transport: to run Hot Cell as a network service. Its transport sends Hot Cell's request line and the inputs over HTTP, and a gateway next to the cell calls it with HotCell::Transport::Socket. Both problems above came up there:
    • it passes a placeholder dir: that's never opened;
    • it compares the socket: argument against that placeholder's paths to tell work from control.

Compatibility

Warning

The socket: → kind: change breaks custom transports. The changelog lists it under Breaking and adds an Upgrading step. transport: wasn't documented before, and the transports in this repository's own tests are updated here.

I dunno if I should worry about this given the current early state of the gem.

A transport's call now takes kind: (:work or :control) instead of
socket:, so a transport that doesn't use the cell's UNIX sockets doesn't
need their paths. Transport::Socket turns the kind into the path, and
still accepts socket: directly. The client passes timeout: on every
call, so the contract is the same for work and control.

A cell with its own transport is enabled without HotCell.root or dir:,
because the transport decides where its requests go.

docs/client-api.md documents transport: under "Use your own transport".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UxJkbuJebUB5t8dzBy1Dy9
Copilot AI balanced review requested due to automatic review settings October 22, 2026 22:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

The implementation has no identified blocking defects; remaining feedback is limited to documentation clarification and regression-test hardening.

2 open issues
What changed in this PR

This PR lets custom client transports reach cells without socket directories and documents the transport interface as public API.

Changes:

  • Enables cells with custom transports without HotCell.root or dir:.
  • Passes explicit kind: and timeout: keywords, while preserving direct socket: support in the socket transport.
  • Updates documentation, migration guidance, and test transports.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

File Description
yabeda-hotcell/​test/​test_helper.rb Updates test transports to accept kind:.
hotcell-client/​test/​registration_test.rb Covers custom transports without directories.
hotcell-client/​test/​diagnosis_test.rb Records request kinds instead of socket paths.
hotcell-client/​test/​control_timeout_test.rb Distinguishes work and control calls by kind.
hotcell-client/​test/​classification_test.rb Updates transport argument recording.
hotcell-client/​lib/​hot_cell/​transport.rb Maps request kinds to sockets and describes the interface.
hotcell-client/​lib/​hot_cell/​client.rb Explicitly forwards work kind and timeout.
hotcell-client/​lib/​hot_cell/​cell.rb Enables custom transports and forwards control kind.
docs/​client-api.md Documents registration and the custom transport contract.
CHANGELOG.md Records the breaking change and upgrade steps.
activestorage-hotcell-client/​test/​test_helper.rb Updates the test transport signature.

Review effort: Balanced

Comment thread docs/client-api.md Outdated
Comment on lines +90 to +91
# Deliver line and the inputs' bytes, write each output's bytes into its descriptor's `io`, and return
# HotCell::Response.parse(response_line).
Comment on lines +15 to +17
# The timeout's default is Transport::Socket's own, so this records what a caller overrode rather than what
# it passed. The work path doesn't override it.
def call(cell, line, descriptors, kind:, timeout: cell.timeout)
…eive a timeout

The client measures each output's size on disk after the transport
returns, so a transport that writes through a buffered IO without
flushing reports a successful request as unavailable. The docs now say
to flush each output before returning success.

The recording transport in control_timeout_test.rb takes timeout:
without a default, so the test fails if the client stops forwarding it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UxJkbuJebUB5t8dzBy1Dy9

This branch has not been deployed

No deployments
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.

2 participants