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
akroasis-server describes itself as a typed, durable HTTP interface whose endpoints mirror the CLI without forking. Its handlers currently implement that contract by invoking text/JSON-oriented CLI dispatch into a Vec<u8>, parsing those bytes back into serde_json::Value, and returning Json<Value>.
The actual report structs remain private inside CLI modules, so the server has no compile-time relationship to the schema it claims to expose. A same-process typed result is serialized and reparsed merely to cross an internal module boundary.
Verified against mainc8e671845adca3e5b57a205d08aca31eadbc6000.
Evidence
crates/akroasis-server/src/lib.rs:1-15 calls the crate a “Typed axum HTTP backend” and durable service interface, says every response matches a CLI --json report, and says frontends/agents drive the same logic “without forking.”
crates/akroasis-server/src/mesh.rs:24-66 implements all three mesh endpoints by:
constructing a CLI MeshCommand { json: true };
dispatching into Vec<u8>;
calling serde_json::from_slice;
returning Json<serde_json::Value>.
crates/akroasis-server/src/radio.rs:103-120 uses the same rendered-bytes/reparse path for radio detection.
The schema-owning CLI types are private. Examples include StatusReport, NodesReport, and TopologyReport in crates/akroasis/src/mesh/mod.rs:41-92, and DetectReport / DetectedRadioReport in crates/akroasis/src/radio/detect.rs:13-27. Import, export, and vault JSON reports follow the same local pattern.
Closed audit: no MCP / --json / programmatic interface for any CLI surface #126 explicitly recommended a shared typed command-report layer and repeatedly recorded that its incremental JSON slices did not close the eventual shared CLI/MCP/API boundary. The issue was nevertheless closed before that boundary existed, and no open successor owns it.
Why this matters
The HTTP API is coupled to presentation bytes rather than to a type contract:
a harmless CLI formatting or framing change can break an HTTP endpoint at runtime;
every endpoint gains an internal JSON parse failure that cannot exist when returning the typed value directly;
Json<Value> hides schema changes from Rust, API documentation, and downstream compile-time checks;
error classification is layered around CLI dispatch rather than around command-domain results; and
adding a second programmatic client encourages another consumer of rendered JSON instead of one reusable command surface.
This is not a legitimate process boundary. Both layers run in the same workspace and intend to expose the same report.
Desired correction
Extract report types and non-presentational command execution into a shared public/internal library surface. Command functions should return typed reports (or a typed report enum) plus typed errors. The human CLI may render those values as tables/text or serialize them to JSON; the HTTP API should return Json<Report> directly.
Keep interactive-only commands explicitly outside the programmatic surface until they have a non-interactive request contract. Do not replace the current loop with a generic Value-returning dispatcher—the schema types are the point.
Done when:
mesh and radio HTTP handlers do not call CLI dispatch or parse rendered bytes;
CLI JSON and HTTP JSON serialize the same report types;
changing a report field produces compile-time changes in both consumers;
API responses use concrete Json<T> types rather than Json<Value> where the schema is known;
shared error/domain execution is independent of terminal rendering; and
Finding
akroasis-serverdescribes itself as a typed, durable HTTP interface whose endpoints mirror the CLI without forking. Its handlers currently implement that contract by invoking text/JSON-oriented CLI dispatch into aVec<u8>, parsing those bytes back intoserde_json::Value, and returningJson<Value>.The actual report structs remain private inside CLI modules, so the server has no compile-time relationship to the schema it claims to expose. A same-process typed result is serialized and reparsed merely to cross an internal module boundary.
Verified against
mainc8e671845adca3e5b57a205d08aca31eadbc6000.Evidence
crates/akroasis-server/src/lib.rs:1-15calls the crate a “Typed axum HTTP backend” and durable service interface, says every response matches a CLI--jsonreport, and says frontends/agents drive the same logic “without forking.”crates/akroasis-server/src/mesh.rs:24-66implements all three mesh endpoints by:MeshCommand { json: true };Vec<u8>;serde_json::from_slice;Json<serde_json::Value>.crates/akroasis-server/src/radio.rs:103-120uses the same rendered-bytes/reparse path for radio detection.StatusReport,NodesReport, andTopologyReportincrates/akroasis/src/mesh/mod.rs:41-92, andDetectReport/DetectedRadioReportincrates/akroasis/src/radio/detect.rs:13-27. Import, export, and vault JSON reports follow the same local pattern.Why this matters
The HTTP API is coupled to presentation bytes rather than to a type contract:
Json<Value>hides schema changes from Rust, API documentation, and downstream compile-time checks;This is not a legitimate process boundary. Both layers run in the same workspace and intend to expose the same report.
Desired correction
Extract report types and non-presentational command execution into a shared public/internal library surface. Command functions should return typed reports (or a typed report enum) plus typed errors. The human CLI may render those values as tables/text or serialize them to JSON; the HTTP API should return
Json<Report>directly.Keep interactive-only commands explicitly outside the programmatic surface until they have a non-interactive request contract. Do not replace the current loop with a generic
Value-returning dispatcher—the schema types are the point.Done when:
Json<T>types rather thanJson<Value>where the schema is known;