Skip to content

Indeterminate Role (Phase 13b)#43

Merged
maxholman merged 1 commit intoblock65:mainfrom
maxholman:feat/indeterminate-role
Feb 28, 2026
Merged

Indeterminate Role (Phase 13b)#43
maxholman merged 1 commit intoblock65:mainfrom
maxholman:feat/indeterminate-role

Conversation

@maxholman
Copy link
Copy Markdown
Contributor

Indeterminate Role (Phase 13b)

Scope

Wire protocol foundation: add Indeterminate as a fourth NodeRole variant,
wire it through the proto conversions and management API, enforce that transport
connections survive role events, and pause the data plane while indeterminate.

Touches: crates/core/src/types.rs,
crates/wire/proto/management.proto,
crates/core/src/node_api.rs,
crates/core/src/control/handler.rs,
crates/core/src/control/peers.rs,
crates/daemon/src/daemon_config.rs,
crates/daemon/src/mode/mod.rs,
crates/cli/src/daemon_cli.rs

Out of scope

  • Auto-negotiation / role derivation from handshake (Phase 13c)
  • Hints (--prefer, --exclude-role, --fixed-role) (Phase 13d)
  • Subcommand deprecation — entry, exit, relay subcommands continue
    to work unchanged. Deprecation deferred to Phase 13d when --fixed-role
    is available.
  • Mode transitions / RoleTransition messages (Phase 13g)

Why

NodeRole has three variants. ROLE_INDETERMINATE already exists in the
data proto (added in 13a) but maps to Err(NodeRoleError::Unset) in the
domain type — the codebase has no concept of a node waiting for its role to
be resolved. Every subsequent phase (13c onward) depends on indeterminate
being a first-class runtime state.

Notes

  • ROLE_INDETERMINATE already in protodata.proto has it from 13a.
    control.proto uses wallhack.data.NodeRole, so no proto change needed
    there. Only management.proto needs updating: add NODE_ROLE_RELAY (was
    missing — relay collapsed to exit) and NODE_ROLE_INDETERMINATE.
  • NodeRole::Indeterminate in types.rs — add the variant. Change
    TryFrom<ProtoNodeRole> to From<ProtoNodeRole> (no longer fallible —
    ROLE_INDETERMINATEIndeterminate instead of error). Remove
    NodeRoleError. Update Display to print "indeterminate".
  • Management protoipc.rs currently collapses relay → exit in
    From<NodeRole> for management::NodeRole. Fix to report all four roles
    accurately. CLI output and REPL info should show indeterminate when
    applicable.
  • Transport survives role events — audit all paths where a role conflict
    or unexpected handshake result causes disconnection. Each must transition to
    indeterminate instead. Known candidates:
    • server/quic/ and server/ws/ accept paths that reject unexpected roles
    • Any ControlLoopExit::Disconnect path triggered by role mismatch
    • daemon_config.rs / mode/mod.rs — startup role resolution
  • Data plane paused in indeterminate — a node in indeterminate must not
    forward tunnel traffic. Control plane (ping/pong, handshake) continues
    normally. Log at INFO when entering indeterminate, including the reason.

Tests

  • NodeRole::Indeterminate round-trips correctly through data.proto and
    management.proto wire formats.
  • Transport connection survives a role becoming invalid — node transitions to
    indeterminate, connection stays open.
  • Data plane is paused in indeterminate — packets are not forwarded.
  • Control plane continues in indeterminate — ping/pong still works.
  • info output shows indeterminate correctly.
  • just check must pass.

NodeRole gains an Indeterminate variant representing a node whose role
has not yet been resolved. This is the wire-protocol foundation that
every subsequent auto-negotiation phase (13c onward) depends on.

- Add NodeRole::Indeterminate, convert TryFrom<ProtoNodeRole> to
  infallible From, remove NodeRoleError
- Add NODE_ROLE_RELAY and NODE_ROLE_INDETERMINATE to management.proto;
  fix IPC conversion to report all four roles (no longer collapses
  relay to exit)
- Pause data plane for indeterminate nodes (no-op outgoing task in
  both QUIC and WebSocket client connect paths)
- Control plane continues normally in indeterminate state
- Tests: proto round-trips, handler ping/status with indeterminate
  role, control plane responsiveness, data plane pausing, transport
  connection survival

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@maxholman maxholman merged commit 22bcc63 into block65:main Feb 28, 2026
4 checks passed
maxholman added a commit that referenced this pull request May 6, 2026
Closes 8 open dependabot alerts via transitive lockfile bumps:

- rustls-webpki 0.103.9 -> 0.103.13 — CRL/URI/wildcard name-constraint
  handling and panic-on-malformed-CRL DoS (alerts #27 #42 #43 #47)
- rand 0.8.5 -> 0.8.6 and 0.9.2 -> 0.9.4 — soundness fix for callers
  using a custom logger with rand::rng() (#45 #46)
- h3 1.15.8 -> 1.15.11 (website) — path traversal via double-decoded
  %252e%252e in serveStatic and SSE event injection via unsanitized
  carriage return (#24 #25)

No direct dependency edits; all bumps are transitive.
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