fix: channels parse-failure path writes the negotiation error frame (R4)
Review #002 R4 — a NegotiateRequest parse failure of the open op's schema-validated input died silently (log + return, channel teardown, consumer observed NoExitChunk — indistinguishable from a crashed producer), while the other post-open failure classes (unknown backend, allocate_failed, ownership denial) wrote the 0x00-prefixed error frame. - make_tty_open_handler now accepts the channel's BiStream and writes a malformed_negotiation frame via the shared crate::adapter::send_negotiation_error (now pub(crate)) before returning; the consumer's M1 peek surfaces NegotiationRejected unchanged - the frame type and layout are unchanged (ADR-001 wire-stable contract); no new frame type, no wire change - tests: make_tty_open_handler seam test with a hand-built schema-bypassing input (cwd: 42) + a real-registry end-to-end test via ChannelClient::open_channel (bypasses open_via_channels's local fail-fast parse — R5's path — so it exercises the producer handler) - docs: ADR-009 amended (Parse-failure error frame section); tty-adapter.md malformed_negotiation row covers both paths; session.rs post-open failure lists updated; review #002 R4 resolved Note: the review's "unreachable end-to-end" premise was refined — open_via_channels parses params locally (fail-fast) so a TtySession consumer never hits the producer-side parse failure, but direct ChannelClient callers do; the schema is deliberately partial so a schema-valid value (cwd typed as a number) reaches the handler. Verification: cargo test 95 lib (default) / 138 (--all-features); clippy -D warnings native + wasm clean; fmt clean; doc 0 warnings.
This commit is contained in:
+11
-8
@@ -196,11 +196,13 @@ impl TtySession {
|
||||
///
|
||||
/// Failures before the channel opens (ACL denial, unknown op,
|
||||
/// channel cap, invalid params) surface as
|
||||
/// [`TtySessionError::ChannelsOpen`]. Post-open failures (unknown
|
||||
/// backend, allocate failure, ownership denial) arrive as a
|
||||
/// negotiation error frame on the channel stream — the session
|
||||
/// surfaces those as [`TtySessionError::NegotiationRejected`] via
|
||||
/// the same `0x00` disambiguation read the direct path uses.
|
||||
/// [`TtySessionError::ChannelsOpen`]. Post-open failures (a
|
||||
/// `NegotiateRequest` parse failure of a schema-valid-but-unparseable
|
||||
/// params value, unknown backend, allocate failure, ownership
|
||||
/// denial) arrive as a negotiation error frame on the channel
|
||||
/// stream — the session surfaces those as
|
||||
/// [`TtySessionError::NegotiationRejected`] via the same `0x00`
|
||||
/// disambiguation read the direct path uses.
|
||||
pub async fn open_via_channels(
|
||||
client: &ChannelClient,
|
||||
params: serde_json::Value,
|
||||
@@ -292,9 +294,10 @@ impl TtySession {
|
||||
/// Core inner for the channels path (ADR-009): the negotiation
|
||||
/// already happened in the open op — the stream is already in
|
||||
/// raw-chunk mode. The peek still applies: the producer sends a
|
||||
/// `0x00`-prefixed error frame on post-open failures (unknown
|
||||
/// backend, allocate failure, ownership denial), and a raw chunk
|
||||
/// (`stream_type` in `{1, 2, 4}`) on success.
|
||||
/// `0x00`-prefixed error frame on any post-open failure (a
|
||||
/// `NegotiateRequest` parse failure of the open op's `input`,
|
||||
/// unknown backend, allocate failure, ownership denial), and a raw
|
||||
/// chunk (`stream_type` in `{1, 2, 4}`) on success.
|
||||
async fn from_halves_raw<R, W>(read: R, write: W) -> Result<Self, TtySessionError>
|
||||
where
|
||||
R: AsyncRead + Send + Unpin + 'static,
|
||||
|
||||
Reference in New Issue
Block a user