proto: give the generated C++ Dispatcher a real error channel (P1, 1.4.0)

DAEMON's daemon/docs/proto-requests-m1.md P1: velox::proto::Dispatcher's
on_* methods returned Result<T> = expected<T, ParseError>, and dispatch()
mapped every handler error to -32603 InternalError. A handler had no way to
return -32010 (download.get not-found), -32011 (download.add invalid-path)
or -32013 (probe-failed) with their data payloads -- three error fixtures a
conformant server must satisfy were unreachable, blocking DAEMON's
"conformance as a server" M1 DoD.

Two error channels now, kept separate on purpose:
  - parse: Result<T> / ParseError -- dispatch() failing to turn the wire into
    typed params. Always -32602, always structural.
  - handler: HandlerResult<T> / HandlerError -- a handler deciding the request
    can't be fulfilled. Carries any ErrorCode + message + free-form data.

    struct HandlerError {
        ErrorCode code{ErrorCode::InternalError};  // bare {} is a valid -32603
        std::string message;
        nlohmann::json data = nullptr;             // straight into the error's data
    };
    template <class T> using HandlerResult = std::expected<T, HandlerError>;

dispatch()'s handler branch is now
  make_error(id, r.error().code, r.error().message, r.error().data)
instead of a hard-coded InternalError. -32001/-32002/-32003 stay the server
layer's to raise around dispatch(), as DAEMON already does.

Verified end to end against the real dispatch() path: a handler returning
TaskNotFound/InvalidPath/ProbeFailed produces -32010/-32011/-32013 with the
data object intact, and a bare HandlerError{} still yields a clean -32603
with no data field. The `= nullptr` on the member (not `{nullptr}`) matters:
brace-init of nlohmann::json from nullptr is the array [null], not JSON null.

FixtureDispatcher regenerated to HandlerResult; conformance_main.cpp only
inspects dispatch()'s JSON and needed no change. TS side is untouched beyond
the version string -- no server Dispatcher is generated there.

P2 also handled: session.hello.version-mismatch's data.expected was a stale
"1.0.0"; now $any, with a note that the error-fixture compare is on `code`
only so a server echoing kProtocolVersion there is fine.

Version: minor, 1.3.0 -> 1.4.0. Wire is byte-identical (no schema, fixture,
or OpenRPC change) but every Dispatcher implementer must swap Result ->
HandlerResult on regen, and the bump is how lanes are told to. Not an ADR:
one lane consumes this binding, it's the one that asked, and the shape is
the one they proposed. Answered in contracts/proto-answers-daemon-m1.md.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_012fgjnqFCS5h5L7gZTZo3rV
This commit is contained in:
2026-09-10 15:10:13 +04:00
co-authored by Claude Sonnet 5
parent 9dce588456
commit 5e3e21543a
15 changed files with 298 additions and 190 deletions
+40 -79
View File
@@ -3,7 +3,7 @@
//
// Source: contracts/schema/**
// Generator: contracts/codegen/gen_cpp.py
// Contract: v1.3.0
// Contract: v1.4.0
//
// Hand-editing this file is a merge blocker. Fix the schema and regenerate:
// python3 contracts/codegen/gen_cpp.py
@@ -7245,8 +7245,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_capture_getRules(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7257,8 +7256,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_capture_offer(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7269,8 +7267,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_category_list(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7281,8 +7278,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_category_remove(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7293,8 +7289,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_category_upsert(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7305,8 +7300,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_add(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7317,8 +7311,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_addBatch(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7329,8 +7322,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_cancel(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7341,8 +7333,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_get(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7353,8 +7344,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_list(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7365,8 +7355,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_pause(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7377,8 +7366,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_probe(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7389,8 +7377,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_provideAuth(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7401,8 +7388,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_refreshUrl(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7413,8 +7399,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_remove(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7425,8 +7410,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_resume(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7437,8 +7421,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_start(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7449,8 +7432,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_download_update(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7461,8 +7443,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_grabber_harvest(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7473,8 +7454,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_grabber_start(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7485,8 +7465,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_grabber_status(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7497,8 +7476,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_limiter_get(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7509,8 +7487,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_limiter_set(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7521,8 +7498,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_media_addVariant(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7533,8 +7509,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_media_listVariants(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7545,8 +7520,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_queue_list(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7557,8 +7531,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_queue_reorder(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7569,8 +7542,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_queue_start(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7581,8 +7553,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_queue_stop(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7593,8 +7564,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_queue_upsert(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7605,8 +7575,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_rules_list(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7617,8 +7586,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_rules_upsert(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7629,8 +7597,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_schedule_get(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7641,8 +7608,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_schedule_set(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7653,8 +7619,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_session_hello(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7665,8 +7630,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_session_pair(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7677,8 +7641,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_session_subscribe(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7689,8 +7652,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_settings_get(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}
@@ -7701,8 +7663,7 @@ nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann
nlohmann::json{{"path", p.error().path}});
auto r = handler.on_settings_set(*p);
if (!r)
return make_error(id, ErrorCode::InternalError, r.error().message,
nlohmann::json{{"path", r.error().path}});
return make_error(id, r.error().code, r.error().message, r.error().data);
nlohmann::json out = *r;
return make_result(id, std::move(out));
}