You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
roxyd already routes NodePowerRequest into handlers::power::handle, but src/bin/roxyd/handlers/power.rs is still scaffolding only
The legacy roxy path already implements immediate reboot and immediate power-off plus graceful reboot and graceful power-off in src/root/task.rs
This issue intentionally covers the full power family rather than only a restart-shaped subset, and the current roxyd control path already routes legacy flat reboot and shutdown requests through node_power
In review-protocol, NodePowerResponse::Initiated means the node accepted the power command and may become unreachable shortly after the response is received
Because roxyd sends the response only after the power handler returns in the upstream review_protocol::request::handle() flow, an inline Linux reboot(2) or poweroff(2) path cannot satisfy the Initiated reply contract
The current dispatch path writes the power response after handlers::power::handle returns, so the immediate reboot and shutdown path requires a small roxyd-local dispatch-side change in addition to the handler work
The repository CI currently runs on GitHub-hosted ubuntu-latest and macos-latest, so normal CI coverage must not reboot or shut down the runner
This issue is for migration, not behavior redesign
Goal
Implement the full power family directly in the roxyd power path
Preserve current legacy behavior and platform boundaries while adapting to NodePowerRequest, NodePowerResponse, and the reply timing contract
Close the first-pass execution path enough that implementation can start without reopening the design during this issue
Scope
Immediate Reboot And Shutdown
Implement NodePowerRequest::Reboot and NodePowerRequest::Shutdown handling in the roxyd power path
NodePowerRequest::Shutdown maps to the legacy immediate PowerOff intent
Immediate Reboot and Shutdown remain Linux-only as in the legacy path
The immediate path must use an implementation that lets roxyd write NodePowerResponse::Initiated successfully before reboot or power-off begins
For the first pass, use an in-process pending-operation approach for immediate reboot and power-off
The immediate power path must prepare a pending reboot or shutdown operation without executing it immediately
The pending operation must wait for an explicit release signal before calling nix::sys::reboot::reboot(...)
roxyd must write NodePowerResponse::Initiated on the current request stream before releasing the pending operation
roxyd must release the pending operation only after the success response write completes successfully
If writing the success response fails, the pending operation must be dropped or cancelled without rebooting or powering off
Add a small roxyd-local power-aware dispatch path for immediate NodePowerRequest::Reboot and NodePowerRequest::Shutdown so roxyd owns the response-write ordering
Preserve the existing flat reboot and shutdown compatibility requests through the same ordering-safe path
This issue does not require a hidden roxyd one-shot mode, hidden internal CLI surface, parent/child readiness protocol, or child-process release protocol
Do not call nix::sys::reboot::reboot(...) inline from the normal request handler before the success response is written
Do not replace the immediate path with shelling out to reboot or poweroff
Unsupported non-Linux immediate requests and preparation failures detected before the success response return Err("invalid command".to_string())
Graceful Reboot And Shutdown
Implement NodePowerRequest::GracefulReboot and NodePowerRequest::GracefulShutdown in src/bin/roxyd/handlers/power.rs
NodePowerRequest::GracefulShutdown maps to the legacy GracefulPowerOff intent
GracefulReboot and GracefulShutdown remain aligned with the current legacy platform behavior
Return NodePowerResponse::Initiated when the power request has been accepted and the execution path is ready to proceed
Handle power operations directly in roxyd without using run_roxy() or the legacy subprocess path
Keep the existing flat reboot and shutdown requests working through the same ordering-safe power path
Preserve response-write ordering for immediate reboot and shutdown within roxyd without requiring a review-protocol change
Do not introduce a new client-visible failure contract for errors that happen after NodePowerResponse::Initiated has already been returned
Keep any additional intentional behavior change out of this issue
Testing
If needed for safe testing, allow a minimal helper extraction or other small indirection at the reboot and shutdown operation boundary
Add or update tests for power handler/helper behavior and dispatch behavior
Normal test and CI runs must not reboot or shut down the real test host or a GitHub Actions runner
Acceptance Criteria
Immediate: On Linux, NodePowerRequest::Reboot preserves the current legacy immediate reboot intent and writes NodePowerResponse::Initiated successfully before reboot begins
Immediate: On Linux, NodePowerRequest::Shutdown preserves the current legacy immediate power-off intent and writes NodePowerResponse::Initiated successfully before power-off begins
Immediate: On non-Linux platforms, immediate Reboot and Shutdown remain unsupported and return the error string invalid command
Immediate: reboot and shutdown do not execute the legacy inline nix::sys::reboot::reboot(...) call inside the normal request handler before the success response is written and do not replace the immediate path with shelling out to reboot or poweroff
Immediate: preparation failures detected before the success response return invalid command
Immediate: the pending operation does not begin reboot or power-off before the current request stream has written NodePowerResponse::Initiated successfully
Immediate: if writing the success response fails, the pending operation is dropped or cancelled without rebooting or powering off
Graceful: NodePowerRequest::GracefulReboot initiates a graceful reboot and returns NodePowerResponse::Initiated
Graceful: NodePowerRequest::GracefulShutdown initiates the legacy graceful power-off behavior and returns NodePowerResponse::Initiated
Graceful: start failures return fail rather than unimplemented!() or panic
Compatibility: the canonical grouped node_power path and the existing flat reboot and shutdown compatibility paths preserve the expected success and failure behavior
Compatibility: response-write ordering for immediate reboot and shutdown is preserved within roxyd without requiring a review-protocol change
Compatibility: the roxyd power path does not invoke run_roxy() or the legacy roxy binary
Compatibility: this issue does not add a new client-visible failure response for errors that happen after NodePowerResponse::Initiated has already been returned
Testing: tests cover direct power handler behavior, grouped node dispatch, and the flat reboot and shutdown compatibility paths without rebooting or shutting down the real test host during normal runs
Testing: normal CI test runs do not reboot or shut down a GitHub Actions runner
Tasks
Immediate Reboot And Shutdown
Implement NodePowerRequest::Reboot and NodePowerRequest::Shutdown handling in the roxyd power path
Map NodePowerRequest::Shutdown to the legacy PowerOff intent
Add an in-process pending-operation path for immediate reboot and power-off
Add an explicit release step that runs the pending operation only after NodePowerResponse::Initiated is written successfully
Add the roxyd-local power-aware dispatch path for immediate NodePowerRequest::Reboot and NodePowerRequest::Shutdown
Preserve the flat reboot and shutdown compatibility paths through the same ordering-safe path
Implement the immediate reboot and power-off path so roxyd writes NodePowerResponse::Initiated successfully before reboot or power-off begins, without calling nix::sys::reboot::reboot(...) inline from the normal request handler
Map unsupported non-Linux immediate requests and preparation failures detected before the success response to Err("invalid command".to_string())
Graceful Reboot And Shutdown
Implement NodePowerRequest::GracefulReboot and NodePowerRequest::GracefulShutdown in src/bin/roxyd/handlers/power.rs
Map NodePowerRequest::GracefulShutdown to the legacy GracefulPowerOff intent
Map GracefulReboot and GracefulShutdown start failures to Err("fail".to_string())
Testing And Compatibility
If needed for safe testing, extract a minimal power-operation boundary that allows success and failure paths to be tested without rebooting or shutting down the real host during normal test runs
Add focused power handler/helper tests for immediate and graceful power success and failure paths
Add a test that verifies a success-response write failure does not allow reboot or power-off to begin
Update the roxyd live dispatch tests for the canonical grouped power path and the existing flat reboot and shutdown compatibility requests so they verify the expected success or failure behavior instead of the current unimplemented panic path
Verify that the implementation preserves the current platform boundaries and does not depend on the legacy subprocess wrapper path
Non Goals
Removing the legacy roxy binary or legacy power code
Background
roxydalready routesNodePowerRequestintohandlers::power::handle, butsrc/bin/roxyd/handlers/power.rsis still scaffolding onlyroxypath already implements immediate reboot and immediate power-off plus graceful reboot and graceful power-off insrc/root/task.rspowerfamily rather than only a restart-shaped subset, and the currentroxydcontrol path already routes legacy flatrebootandshutdownrequests throughnode_powerreview-protocol,NodePowerResponse::Initiatedmeans the node accepted the power command and may become unreachable shortly after the response is receivedroxydsends the response only after the power handler returns in the upstreamreview_protocol::request::handle()flow, an inline Linuxreboot(2)orpoweroff(2)path cannot satisfy theInitiatedreply contracthandlers::power::handlereturns, so the immediate reboot and shutdown path requires a smallroxyd-local dispatch-side change in addition to the handler workubuntu-latestandmacos-latest, so normal CI coverage must not reboot or shut down the runnerGoal
roxydpower pathNodePowerRequest,NodePowerResponse, and the reply timing contractScope
Immediate Reboot And Shutdown
NodePowerRequest::RebootandNodePowerRequest::Shutdownhandling in theroxydpower pathNodePowerRequest::Shutdownmaps to the legacy immediatePowerOffintentRebootandShutdownremain Linux-only as in the legacy pathroxydwriteNodePowerResponse::Initiatedsuccessfully before reboot or power-off beginsnix::sys::reboot::reboot(...)roxydmust writeNodePowerResponse::Initiatedon the current request stream before releasing the pending operationroxydmust release the pending operation only after the success response write completes successfullyroxyd-local power-aware dispatch path for immediateNodePowerRequest::RebootandNodePowerRequest::Shutdownsoroxydowns the response-write orderingrebootandshutdowncompatibility requests through the same ordering-safe pathroxydone-shot mode, hidden internal CLI surface, parent/child readiness protocol, or child-process release protocolnix::sys::reboot::reboot(...)inline from the normal request handler before the success response is writtenrebootorpoweroffErr("invalid command".to_string())Graceful Reboot And Shutdown
NodePowerRequest::GracefulRebootandNodePowerRequest::GracefulShutdowninsrc/bin/roxyd/handlers/power.rsNodePowerRequest::GracefulShutdownmaps to the legacyGracefulPowerOffintentGracefulRebootandGracefulShutdownremain aligned with the current legacy platform behaviorErr("fail".to_string())Response And Compatibility
NodePowerResponse::Initiatedwhen the power request has been accepted and the execution path is ready to proceedroxydwithout usingrun_roxy()or the legacy subprocess pathrebootandshutdownrequests working through the same ordering-safe power pathroxydwithout requiring areview-protocolchangeNodePowerResponse::Initiatedhas already been returnedTesting
Acceptance Criteria
NodePowerRequest::Rebootpreserves the current legacy immediate reboot intent and writesNodePowerResponse::Initiatedsuccessfully before reboot beginsNodePowerRequest::Shutdownpreserves the current legacy immediate power-off intent and writesNodePowerResponse::Initiatedsuccessfully before power-off beginsRebootandShutdownremain unsupported and return the error stringinvalid commandnix::sys::reboot::reboot(...)call inside the normal request handler before the success response is written and do not replace the immediate path with shelling out torebootorpoweroffinvalid commandNodePowerResponse::InitiatedsuccessfullyNodePowerRequest::GracefulRebootinitiates a graceful reboot and returnsNodePowerResponse::InitiatedNodePowerRequest::GracefulShutdowninitiates the legacy graceful power-off behavior and returnsNodePowerResponse::Initiatedfailrather thanunimplemented!()or panicnode_powerpath and the existing flatrebootandshutdowncompatibility paths preserve the expected success and failure behaviorroxydwithout requiring areview-protocolchangeroxydpower path does not invokerun_roxy()or the legacyroxybinaryNodePowerResponse::Initiatedhas already been returnedTasks
Immediate Reboot And Shutdown
NodePowerRequest::RebootandNodePowerRequest::Shutdownhandling in theroxydpower pathNodePowerRequest::Shutdownto the legacyPowerOffintentNodePowerResponse::Initiatedis written successfullyroxyd-local power-aware dispatch path for immediateNodePowerRequest::RebootandNodePowerRequest::Shutdownrebootandshutdowncompatibility paths through the same ordering-safe pathroxydwritesNodePowerResponse::Initiatedsuccessfully before reboot or power-off begins, without callingnix::sys::reboot::reboot(...)inline from the normal request handlerErr("invalid command".to_string())Graceful Reboot And Shutdown
NodePowerRequest::GracefulRebootandNodePowerRequest::GracefulShutdowninsrc/bin/roxyd/handlers/power.rsNodePowerRequest::GracefulShutdownto the legacyGracefulPowerOffintentGracefulRebootandGracefulShutdownstart failures toErr("fail".to_string())Testing And Compatibility
roxydlive dispatch tests for the canonical grouped power path and the existing flatrebootandshutdowncompatibility requests so they verify the expected success or failure behavior instead of the current unimplemented panic pathNon Goals
roxybinary or legacy power codeNodePowerResponse::Initiatedroxydone-shot CLI or subprocess protocol for the first-pass migration