packages feed

plexus-protocol 0.6.0.0 → 0.7.0.0

raw patch · 8 files changed

+72/−197 lines, 8 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Plexus: SelectOption :: t -> Text -> Maybe Text -> SelectOption t
- Plexus: StreamRequest :: Text -> Provenance -> Text -> StandardRequest -> Maybe Int -> PlexusStreamItem
- Plexus: [itemRequestData] :: PlexusStreamItem -> StandardRequest
- Plexus: [itemRequestId] :: PlexusStreamItem -> Text
- Plexus: [itemTimeout] :: PlexusStreamItem -> Maybe Int
- Plexus: [methodBidirectional] :: MethodSchema -> Bool
- Plexus: [methodRequestType] :: MethodSchema -> Maybe Value
- Plexus: [methodResponseType] :: MethodSchema -> Maybe Value
- Plexus: [optionDescription] :: SelectOption t -> Maybe Text
- Plexus: [optionLabel] :: SelectOption t -> Text
- Plexus: [optionValue] :: SelectOption t -> t
- Plexus: data SelectOption t
- Plexus: sendBidirectionalResponse :: SubstrateConfig -> Text -> Response Value -> IO (Either TransportError ())
- Plexus: type StandardRequest = Request Value
- Plexus: type StandardResponse = Response Value
- Plexus.Schema.Recursive: [methodBidirectional] :: MethodSchema -> Bool
- Plexus.Schema.Recursive: [methodRequestType] :: MethodSchema -> Maybe Value
- Plexus.Schema.Recursive: [methodResponseType] :: MethodSchema -> Maybe Value
- Plexus.Transport: sendBidirectionalResponse :: SubstrateConfig -> Text -> Response Value -> IO (Either TransportError ())
- Plexus.Types: Cancelled :: Response t
- Plexus.Types: Confirm :: Text -> Maybe Bool -> Request t
- Plexus.Types: Confirmed :: Bool -> Response t
- Plexus.Types: Prompt :: Text -> Maybe t -> Maybe Text -> Request t
- Plexus.Types: Select :: Text -> [SelectOption t] -> Bool -> Request t
- Plexus.Types: SelectOption :: t -> Text -> Maybe Text -> SelectOption t
- Plexus.Types: Selected :: [t] -> Response t
- Plexus.Types: StreamRequest :: Text -> Provenance -> Text -> StandardRequest -> Maybe Int -> PlexusStreamItem
- Plexus.Types: Value :: t -> Response t
- Plexus.Types: [confirmDefault] :: Request t -> Maybe Bool
- Plexus.Types: [confirmMessage] :: Request t -> Text
- Plexus.Types: [confirmedValue] :: Response t -> Bool
- Plexus.Types: [itemRequestData] :: PlexusStreamItem -> StandardRequest
- Plexus.Types: [itemRequestId] :: PlexusStreamItem -> Text
- Plexus.Types: [itemTimeout] :: PlexusStreamItem -> Maybe Int
- Plexus.Types: [optionDescription] :: SelectOption t -> Maybe Text
- Plexus.Types: [optionLabel] :: SelectOption t -> Text
- Plexus.Types: [optionValue] :: SelectOption t -> t
- Plexus.Types: [promptDefault] :: Request t -> Maybe t
- Plexus.Types: [promptMessage] :: Request t -> Text
- Plexus.Types: [promptPlaceholder] :: Request t -> Maybe Text
- Plexus.Types: [responseValue] :: Response t -> t
- Plexus.Types: [selectMessage] :: Request t -> Text
- Plexus.Types: [selectMulti] :: Request t -> Bool
- Plexus.Types: [selectOptions] :: Request t -> [SelectOption t]
- Plexus.Types: [selectedValues] :: Response t -> [t]
- Plexus.Types: data Request t
- Plexus.Types: data Response t
- Plexus.Types: data SelectOption t
- Plexus.Types: instance Data.Aeson.Types.FromJSON.FromJSON t => Data.Aeson.Types.FromJSON.FromJSON (Plexus.Types.Request t)
- Plexus.Types: instance Data.Aeson.Types.FromJSON.FromJSON t => Data.Aeson.Types.FromJSON.FromJSON (Plexus.Types.Response t)
- Plexus.Types: instance Data.Aeson.Types.FromJSON.FromJSON t => Data.Aeson.Types.FromJSON.FromJSON (Plexus.Types.SelectOption t)
- Plexus.Types: instance Data.Aeson.Types.ToJSON.ToJSON t => Data.Aeson.Types.ToJSON.ToJSON (Plexus.Types.Request t)
- Plexus.Types: instance Data.Aeson.Types.ToJSON.ToJSON t => Data.Aeson.Types.ToJSON.ToJSON (Plexus.Types.Response t)
- Plexus.Types: instance Data.Aeson.Types.ToJSON.ToJSON t => Data.Aeson.Types.ToJSON.ToJSON (Plexus.Types.SelectOption t)
- Plexus.Types: instance GHC.Classes.Eq t => GHC.Classes.Eq (Plexus.Types.Request t)
- Plexus.Types: instance GHC.Classes.Eq t => GHC.Classes.Eq (Plexus.Types.Response t)
- Plexus.Types: instance GHC.Classes.Eq t => GHC.Classes.Eq (Plexus.Types.SelectOption t)
- Plexus.Types: instance GHC.Generics.Generic (Plexus.Types.Request t)
- Plexus.Types: instance GHC.Generics.Generic (Plexus.Types.Response t)
- Plexus.Types: instance GHC.Generics.Generic (Plexus.Types.SelectOption t)
- Plexus.Types: instance GHC.Show.Show t => GHC.Show.Show (Plexus.Types.Request t)
- Plexus.Types: instance GHC.Show.Show t => GHC.Show.Show (Plexus.Types.Response t)
- Plexus.Types: instance GHC.Show.Show t => GHC.Show.Show (Plexus.Types.SelectOption t)
- Plexus.Types: type StandardRequest = Request Value
- Plexus.Types: type StandardResponse = Response Value
- Plexus.Types: type WellKnownRequest = Request Value
- Plexus.Types: type WellKnownResponse = Response Value
- Plexus: MethodSchema :: Text -> Text -> PluginHash -> Maybe Value -> Value -> Maybe Value -> Maybe Value -> Cardinality -> Bool -> Text -> Maybe Value -> Maybe Value -> Maybe DeprecationInfo -> Maybe [ParamSchema] -> MethodRole -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe [Text] -> Bool -> Maybe Text -> [MethodExample] -> Maybe Value -> MethodSchema
+ Plexus: MethodSchema :: Text -> Text -> PluginHash -> Maybe Value -> Value -> Maybe Value -> Maybe Value -> Cardinality -> Text -> Maybe DeprecationInfo -> Maybe [ParamSchema] -> MethodRole -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe [Text] -> Bool -> Maybe Text -> [MethodExample] -> Maybe Value -> MethodSchema
- Plexus.Schema.Recursive: MethodSchema :: Text -> Text -> PluginHash -> Maybe Value -> Value -> Maybe Value -> Maybe Value -> Cardinality -> Bool -> Text -> Maybe Value -> Maybe Value -> Maybe DeprecationInfo -> Maybe [ParamSchema] -> MethodRole -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe [Text] -> Bool -> Maybe Text -> [MethodExample] -> Maybe Value -> MethodSchema
+ Plexus.Schema.Recursive: MethodSchema :: Text -> Text -> PluginHash -> Maybe Value -> Value -> Maybe Value -> Maybe Value -> Cardinality -> Text -> Maybe DeprecationInfo -> Maybe [ParamSchema] -> MethodRole -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe [Text] -> Bool -> Maybe Text -> [MethodExample] -> Maybe Value -> MethodSchema

Files

CHANGELOG.md view
@@ -1,5 +1,24 @@ # Changelog for plexus-protocol +## 0.7.0.0++bidir removed (ASK-1, ASK-3). Breaking.++### Breaking++- **bidir is gone.** The server no longer asks its caller mid-call: the+  `request` stream item (`StreamRequest`), `Request` / `Response`+  (`Confirm`, `Prompt`, `Select`; `Confirmed`, `Value`, `Selected`,+  `Cancelled`), `SelectOption`, `WellKnownRequest` / `WellKnownResponse`,+  `StandardRequest` / `StandardResponse` and `sendBidirectionalResponse`+  (`{ns}.respond`) are removed. A `request` item is no stream item.+- **`MethodSchema`**: `methodBidirectional`, `methodRequestType` and+  `methodResponseType` are removed, with nothing in their place. An older+  schema's `bidirectional` (and its request / response types) is read past.+- Plexus has no in-call or protocol-wide confirmation: a service that wants+  one builds it as its own methods. The input half (BIDIR-18,+  `Plexus.Input`) stays.+ ## 0.6.0.0  The Haskell side of plexus 0.7's schema and envelope. Breaking.
README.md view
@@ -188,7 +188,7 @@   , methodError       :: Maybe Value  -- JSON Schema of the error type E (fallible methods)   , methodProgress    :: Maybe Value  -- JSON Schema of the progress type P   , methodCardinality :: Cardinality  -- CardinalityOne | CardinalityMany (required)-  , …                                 -- bidirectional, http_method, request/response types, deprecation, role+  , …                                 -- http_method, deprecation, role, …   }  data SchemaResult
plexus-protocol.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               plexus-protocol-version:            0.6.0.0+version:            0.7.0.0 synopsis:           Plexus RPC protocol types and client description:        Haskell types and a client for Plexus RPC, a streaming JSON-RPC 2.0                     protocol: stream items and provenance, recursive plugin and method
src/Plexus.hs view
@@ -54,14 +54,6 @@   , rpcCallStreaming   , invokeMethodStreaming -    -- * Bidirectional Response-  , sendBidirectionalResponse--    -- * Bidirectional Types-  , StandardRequest(..)-  , StandardResponse(..)-  , SelectOption(..)-     -- * Stream Types   , PlexusStreamItem(..)   , Provenance(..)
src/Plexus/Schema/Recursive.hs view
@@ -246,10 +246,7 @@   , methodError           :: Maybe Value  -- ^ JSON Schema for the error type @E@ (@-> Result<T, E>@); 'Nothing' when the method is infallible   , methodProgress        :: Maybe Value  -- ^ JSON Schema for the progress type @P@ carried by progress frames; 'Nothing' when the method reports no progress   , methodCardinality     :: Cardinality  -- ^ One item or many-  , methodBidirectional   :: Bool         -- ^ True if method uses a bidirectional channel   , methodHttpMethod      :: Text         -- ^ HTTP method of the method's REST endpoint (@"GET"@, @"POST"@, …); @"POST"@ when absent-  , methodRequestType     :: Maybe Value  -- ^ JSON Schema for the server→client request type (when bidirectional)-  , methodResponseType    :: Maybe Value  -- ^ JSON Schema for the client→server response type (when bidirectional)   , methodDeprecation     :: Maybe DeprecationInfo  -- ^ Deprecation info, if any (IR-5)   , methodParamSchemas    :: Maybe [ParamSchema]    -- ^ Optional structured param info with per-field deprecations (IR-5)   , methodRole            :: MethodRole             -- ^ Structural role in the activation graph (IR-2 / IR-3); defaults to 'MethodRoleRpc'@@ -275,10 +272,9 @@     <*> o .:? "error"     <*> o .:? "progress"     <*> cardinalityOf o-    <*> o .:? "bidirectional"  .!= False+    -- ASK-1: bidir is gone; an older schema's @bidirectional@,+    -- @request_type@ and @response_type@ are read past     <*> o .:? "http_method"    .!= "POST"-    <*> o .:? "request_type"-    <*> o .:? "response_type"     <*> o .:? "deprecation"     <*> o .:? "param_schemas"     <*> o .:? "role" .!= MethodRoleRpc@@ -321,15 +317,12 @@     , "hash"           .= methodHash     , "returns"        .= methodReturns     , "cardinality"    .= methodCardinality-    , "bidirectional"  .= methodBidirectional     , "http_method"    .= methodHttpMethod     , "role"           .= methodRole     ] <> catMaybes     [ "params"         .=? methodParams     , "error"          .=? methodError     , "progress"       .=? methodProgress-    , "request_type"   .=? methodRequestType-    , "response_type"  .=? methodResponseType     , "deprecation"    .=? methodDeprecation     , "param_schemas"  .=? methodParamSchemas     , "long_description" .=? methodLongDescription
src/Plexus/Transport.hs view
@@ -13,8 +13,6 @@   , invokeMethodStreamingWith   , invokeMethodDuplex -    -- * Bidirectional Response-  , sendBidirectionalResponse      -- * Schema Fetching   , fetchSchemaAt@@ -50,7 +48,7 @@ import Plexus.Input (InputHalf) import Plexus.Client.Pool (ConnectionPool, createConnectionPool, withPooledConnection, defaultPlexusPoolConfig) import Plexus.RemoteError (renderRemoteError)-import Plexus.Types (PlexusStreamItem(..), TransportError(..), Response(..), StandardResponse)+import Plexus.Types (PlexusStreamItem(..), TransportError(..)) import Plexus.Schema.Recursive (PluginSchema, MethodSchema, SchemaResult(..), parsePluginSchema, parseSchemaResult)  -- | Global connection pool cache@@ -291,19 +289,3 @@   let backend = substrateBackend cfg   let callParams = object ["method" .= method, "params" .= params]   rpcCallWith cfg (backend <> ".call") callParams---- | Send a response back to the server for a bidirectional request--- Uses {backend}.respond RPC method-sendBidirectionalResponse :: SubstrateConfig -> Text -> Response Value -> IO (Either TransportError ())-sendBidirectionalResponse cfg requestId response = do-  let backend = substrateBackend cfg-  let respondParams = object-        [ "request_id" .= requestId-        , "response_data" .= response-        ]-  result <- rpcCallWith cfg (backend <> ".respond") respondParams-  case result of-    Left transportErr -> pure $ Left transportErr-    Right items -> case [renderRemoteError err | StreamError _ _ err _ <- items] of-      (err:_) -> pure $ Left $ ProtocolError err-      [] -> pure $ Right ()
src/Plexus/Types.hs view
@@ -22,15 +22,6 @@   , GuidanceSuggestion(..)   , TransportError(..) -    -- * Bidirectional Types-  , SelectOption(..)-  , Request(..)-  , Response(..)-  , WellKnownRequest-  , WellKnownResponse-  , StandardRequest  -- Deprecated, kept for backwards compatibility-  , StandardResponse -- Deprecated, kept for backwards compatibility-     -- * Helpers   , mkSubscribeRequest   , mkUnsubscribeRequest@@ -369,125 +360,6 @@       _ -> fail $ "Unknown transport error_kind: " <> T.unpack kind  -- ============================================================================--- Bidirectional Types (Request/Response)--- ============================================================================---- | Option for select requests, parameterized over value type-data SelectOption t = SelectOption-  { optionValue       :: t-  , optionLabel       :: Text-  , optionDescription :: Maybe Text-  }-  deriving (Show, Eq, Generic)--instance (FromJSON t) => FromJSON (SelectOption t) where-  parseJSON = withObject "SelectOption" $ \o -> SelectOption-    <$> o .: "value"-    <*> o .: "label"-    <*> o .:? "description"--instance (ToJSON t) => ToJSON (SelectOption t) where-  toJSON SelectOption{..} = object $-    [ "value" .= optionValue, "label" .= optionLabel ]-    <> catMaybes [("description" .=) <$> optionDescription]---- | Parameterized request type for bidirectional communication------ This type represents the well-known request types in the Plexus bidirectional protocol.--- Unlike Rust which uses traits, Haskell uses a parameterized ADT which provides--- similar flexibility with better type safety.------ The type parameter @t@ is used for values in Prompt defaults and Select options.--- For most cases, use 'WellKnownRequest' which sets @t = Value@.-data Request t-  = Confirm  { confirmMessage :: Text, confirmDefault :: Maybe Bool }-  | Prompt   { promptMessage :: Text, promptDefault :: Maybe t, promptPlaceholder :: Maybe Text }-  | Select   { selectMessage :: Text, selectOptions :: [SelectOption t], selectMulti :: Bool }-  deriving (Show, Eq, Generic)---- | Well-known request types with JSON values------ This is the recommended type for most bidirectional requests.--- It matches the Rust @WellKnownRequest@ and TypeScript union types.-type WellKnownRequest = Request Value---- | Type alias for backwards compatibility: requests with JSON values------ Deprecated: Use 'WellKnownRequest' instead for consistency with Rust/TypeScript.-type StandardRequest = Request Value--instance (FromJSON t) => FromJSON (Request t) where-  parseJSON = withObject "Request" $ \o -> do-    typ <- o .: "type" :: Parser Text-    case typ of-      "confirm" -> Confirm-        <$> o .: "message"-        <*> o .:? "default"-      "prompt" -> Prompt-        <$> o .: "message"-        <*> o .:? "default"-        <*> o .:? "placeholder"-      "select" -> Select-        <$> o .: "message"-        <*> o .: "options"-        <*> o .:? "multi_select" .!= False-      _ -> fail $ "Unknown request type: " <> T.unpack typ--instance (ToJSON t) => ToJSON (Request t) where-  toJSON (Confirm msg def) = object $-    [ "type" .= ("confirm" :: Text), "message" .= msg ]-    <> catMaybes [("default" .=) <$> def]-  toJSON (Prompt msg def placeholder) = object $-    [ "type" .= ("prompt" :: Text), "message" .= msg ]-    <> catMaybes [("default" .=) <$> def, ("placeholder" .=) <$> placeholder]-  toJSON (Select msg opts multi) = object-    [ "type" .= ("select" :: Text), "message" .= msg-    , "options" .= opts, "multi_select" .= multi ]---- | Parameterized response type for bidirectional communication------ This type represents the well-known response types in the Plexus bidirectional protocol.------ Note: The 'Value' constructor corresponds to JSON @"type":"text"@ for--- wire compatibility with the Rust implementation.------ The type parameter @t@ is used for values in Prompt responses and Select responses.--- For most cases, use 'WellKnownResponse' which sets @t = Value@.-data Response t-  = Confirmed { confirmedValue :: Bool }-  | Value     { responseValue :: t }    -- ^ wire tag: "text"-  | Selected  { selectedValues :: [t] }-  | Cancelled-  deriving (Show, Eq, Generic)---- | Well-known response types with JSON values------ This is the recommended type for most bidirectional responses.--- It matches the Rust @WellKnownResponse@ and TypeScript union types.-type WellKnownResponse = Response Value---- | Type alias for backwards compatibility: responses with JSON values------ Deprecated: Use 'WellKnownResponse' instead for consistency with Rust/TypeScript.-type StandardResponse = Response Value--instance (FromJSON t) => FromJSON (Response t) where-  parseJSON = withObject "Response" $ \o -> do-    typ <- o .: "type" :: Parser Text-    case typ of-      "confirmed" -> Confirmed <$> o .: "value"-      "text"      -> Value <$> o .: "value"-      "selected"  -> Selected <$> o .: "values"-      "cancelled" -> pure Cancelled-      _ -> fail $ "Unknown response type: " <> T.unpack typ--instance (ToJSON t) => ToJSON (Response t) where-  toJSON (Confirmed v)  = object ["type" .= ("confirmed" :: Text), "value" .= v]-  toJSON (Value v)      = object ["type" .= ("text" :: Text), "value" .= v]-  toJSON (Selected vs)  = object ["type" .= ("selected" :: Text), "values" .= vs]-  toJSON Cancelled      = object ["type" .= ("cancelled" :: Text)]---- ============================================================================ -- Plexus Stream Items -- ============================================================================ @@ -545,13 +417,6 @@         -- the refusal's fields), kept as sent and written back so; empty         -- for a frame built here.       }-  | StreamRequest-      { itemPlexusHash  :: Text-      , itemProvenance  :: Provenance-      , itemRequestId   :: Text-      , itemRequestData :: StandardRequest-      , itemTimeout     :: Maybe Int-      }   | StreamDone       { itemPlexusHash :: Text       , itemProvenance :: Provenance@@ -565,7 +430,7 @@ pattern StreamError hash prov err rec <- StreamErrorWith hash prov err rec _ _   where StreamError hash prov err rec = StreamErrorWith hash prov err rec Nothing KM.empty -{-# COMPLETE StreamProgress, StreamData, StreamGuidance, StreamError, StreamRequest, StreamDone #-}+{-# COMPLETE StreamProgress, StreamData, StreamGuidance, StreamError, StreamDone #-}  -- | AUTH-2: the refusal an item carries — an error item with -- @error_kind: "forbidden"@ (or whose typed error is a@@ -610,10 +475,6 @@             <*> o .: "recoverable"             <*> pure (refusalFromObject o)             <*> pure (besideError o)-          "request" -> StreamRequest hash prov-            <$> o .: "request_id"-            <*> o .: "request"-            <*> o .:? "timeout"           "done" -> pure $ StreamDone hash prov           _ -> fail $ "Unknown event type: " <> T.unpack typ @@ -644,11 +505,6 @@             <*> o .:? "recoverable" .!= False             <*> pure (refusalFromObject o)             <*> pure (besideError o)-          "request" -> StreamRequest hash-            <$> o .: "provenance"-            <*> o .: "request_id"-            <*> o .: "request"-            <*> o .:? "timeout"           "done" -> StreamDone hash             <$> o .: "provenance"           _ -> fail $ "Unknown event type: " <> T.unpack typ@@ -687,14 +543,6 @@       refusalFields = case toJSON <$> refusal of         Just (Object ro) -> [ (k, v) | (k, v) <- KM.toList ro, k /= "message" ]         _ -> []-  toJSON (StreamRequest hash prov reqId reqData timeout) = object $-    [ "type" .= ("request" :: Text)-    , "metadata" .= StreamMetadata prov hash 0-    , "request_id" .= reqId-    , "request" .= reqData-    ] <> catMaybes-    [ ("timeout" .=) <$> timeout-    ]   toJSON (StreamDone hash prov) = object     [ "type" .= ("done" :: Text)     , "metadata" .= StreamMetadata prov hash 0
test/Main.hs view
@@ -1,4 +1,4 @@--- | plexus-protocol 0.6 against plexus 0.7.+-- | plexus-protocol 0.7 against plexus 0.7 and 0.8. -- -- The golden half reads RETURNS-7's conformance fixture by sibling path -- (@../plexus-macros/fixtures/conformance/expected/@) and checks that every@@ -101,6 +101,15 @@ matches (Array e) (Array a) = length e == length a && and (zipWith matches (toList e) (toList a)) matches e a = e == a +-- | ASK-1: a schema written before bidir's removal says+-- @"bidirectional": false@ on every method; it is read past and written as+-- nothing.+dropBidirectional :: Value -> Value+dropBidirectional = \case+  Object o -> Object (KM.map dropBidirectional (KM.filterWithKey (\k v -> not (k == "bidirectional" && v == Bool False)) o))+  Array a -> Array (fmap dropBidirectional a)+  v -> v+ -- | Parse @v@ as an @a@, re-encode it, and require the result to match @v@. roundTrips :: forall a. (FromJSON a, ToJSON a) => (Value -> Value) -> Value -> IO a roundTrips norm v = case parseEither parseJSON v of@@ -155,10 +164,12 @@   rejectionSpec   strictnessSpec   mergedSpec+  noBidirSpec  schemaSpec :: Spec schemaSpec = describe "expected/schema.json" $ do-  let load = readJson (fixtureDir </> "schema.json")+  -- ASK-1: a fixture written before bidir's removal says bidirectional: false+  let load = dropBidirectional <$> readJson (fixtureDir </> "schema.json")    it "parses as a PluginSchema and re-encodes to the same JSON" $ do     v <- load@@ -228,7 +239,6 @@     forM_ (psMethods schema) $ \m -> do       methodHttpMethod m `shouldBe` "POST"       methodRole m `shouldBe` MethodRoleRpc-      methodBidirectional m `shouldBe` False  wireSpec :: Spec wireSpec = describe "expected/wire/*.jsonl" $ do@@ -499,7 +509,7 @@     methodHttpMethod m `shouldBe` "POST"     methodRole m `shouldBe` MethodRoleRpc     toJSON m `shouldBe` method-      [ returns, "cardinality" .= s "many", "bidirectional" .= False+      [ returns, "cardinality" .= s "many"       , "http_method" .= s "POST", "role" .= object ["kind" .= s "rpc"] ]    let meta = "metadata" .= object@@ -518,7 +528,7 @@     methodReturns one `shouldBe` object ["type" .= s "string"]     -- written back in 0.8's shape     toJSON many `shouldBe` method-      [ returns, "cardinality" .= s "many", "bidirectional" .= False+      [ returns, "cardinality" .= s "many"       , "http_method" .= s "POST", "role" .= object ["kind" .= s "rpc"] ]    it "a 0.8 method's cardinality wins over a streaming flag beside it" $ do@@ -695,7 +705,7 @@     let wire = object           [ "name" .= s "set_status", "description" .= s "d", "hash" .= s "h"           , "returns" .= object [], "error" .= object ["title" .= s "SetStatusError"]-          , "cardinality" .= s "one", "bidirectional" .= False, "http_method" .= s "POST"+          , "cardinality" .= s "one", "http_method" .= s "POST"           , "role" .= object ["kind" .= s "rpc"]           , "long_description" .= s "long", "grant" .= s "tickets.set_status", "target" .= s "id"           , "held_on" .= [s "*"], "public" .= True, "group" .= s "write"@@ -721,3 +731,34 @@       (object ["namespace" .= s "menger", "methods" .= ([] :: [Value]), "view" .= s "anonymous"])     psHash p `shouldBe` ""     psView p `shouldBe` Just Anonymous++-- | ASK-1: bidir is gone from the wire, and nothing replaced it: an older+-- schema's bidirectional keys are read past, and a request item is no stream+-- item.+noBidirSpec :: Spec+noBidirSpec = describe "no bidir (ASK-1)" $ do+  let method extra = object $+        [ "name" .= s "archive", "description" .= s "d", "hash" .= s "h"+        , "returns" .= object [], "cardinality" .= s "one" ] ++ extra+      meta = "metadata" .= object+        ["provenance" .= [s "tickets"], "plexus_hash" .= s "h", "timestamp" .= (0 :: Int)]++  it "an older schema's bidirectional (and its request/response types) is read past" $ do+    m <- either fail pure $ decodes @MethodSchema (method+      [ "bidirectional" .= True, "request_type" .= object ["title" .= s "StandardRequest"]+      , "response_type" .= object ["title" .= s "StandardResponse"] ])+    toJSON m `shouldBe` method ["http_method" .= s "POST", "role" .= object ["kind" .= s "rpc"]]++  it "a request item (spec/08's, gone) is no stream item" $+    (decodes @PlexusStreamItem (object+      [ "type" .= s "request", meta, "request_id" .= s "r1"+      , "request" .= object ["type" .= s "confirm", "message" .= s "ok?"] ]))+      `shouldSatisfy` either (const True) (const False)++  it "a data item whose content says needs_input is an ordinary data item" $ do+    let content = object ["type" .= s "needs_input", "summary" .= s "go", "token" .= s "t"]+    item <- roundTrips @PlexusStreamItem normalizeFrame (object+      [ "type" .= s "data", meta, "content_type" .= s "tickets.archive", "content" .= content ])+    case item of+      StreamData _ _ _ c -> c `shouldBe` content+      other -> expectationFailure ("not a data item: " <> show other)