This is placeholder for documentation to come. These are notes from early discussions.

/\*\*

- Straw Man : How does SelectConnect work?
-
- Every incoming InteropMessage converts to a redux action.
-
- Non-broadcast actions (e.g. getSystemChannels, findIntent, joinChannel etc) are processed by reducers which update state and deliver (thunk) replies to the client
-
- Broadcast actions run the SelectConnect algorithm. The algorithm results in an array of:
- (1) destinations uuids
- (2) the message (context and/or intent) for each destination, possibly transformed
-
-       The algorithm is a loop.
-        On start:
-     	  (1) The list of prospective destinations is initialized from the store (e.g. which uuids are listening for this message)
-
-        Each iteration:
-     		  Begins with the following data:
-               (a) the original message and meta data (e.g. intent type, context type, origination)
-               (b) a list of all rules that have not yet been triggered
-               (c) the current list of prospective destinations
-
-            Logic:
-               (i) Process each rule (in array order from config)
-                   Possibilities are:
-                     (A) `filter`: Eliminate or add destinations (e.g. from=* filter=#Linker)
-                     (B) `fork` : add destinations (e.g. to=#Chat fork=#Salesforce.Activity)
-                     (C) `selectConnect` : replace destinations (e.g. to=#Chat selectConnect=#Symphony)
-               (ii) Eliminate the rule (to avoid recursion and loops)
-               (iii) Exit loop when no rules are triggered during an iteration
-
-          When complete:
-     		  (a) Eliminate any destinations that don't have a valid handler (dead ends)
-            (b) Run auto-translation algorithm
-            (c) Update the store to reflect new client state
-            (d) Deliver messages using asynchronous thunks
-
- TBD:
- Do rules need to make a destinction between "from":"to" and "origination":"destination"?
-       e.g. to prevent skirting filters by redirection
- How to prevent broadcast storms?
-       Not just internal to the resolver, but if receipt of a message by a destination triggers a broadcast, and vice versa
-         Stitchview ran into this pretty quickly and implemented a timeout, to silently drop any messages of the same contextType if received within x milliseconds
- Translation
-       What do rules look like? How do apps or system channels register translations?
  \*/

/\*\*

- System channels:
-
- By convention, system channels begin with #. Some system channels like #Linker are built in.
- Other system channels, such as #Symphony, would be registered via config. Registering via config prevents
- other apps from hijacking those channel names.
-
- System channels are not "peer" based. When a message is sent to a system channel, only the system channel
- handler receives that message (not any other listeners).
-
- System channels may support a syntax, such as #Symphony@tradebot or #Excel@G6F4.
-
- TBD: how to communicate that syntax to the system app with a given FDC3 message
- TBD: how the system channel can communicate back to a specific app
-         ? implicitly create a channel for every uuid
-         ? how would the system channel be informed
-         ? how would the system channel know when to remove uuid references
-         ? is it even necessary for system channels to communicate back? Maybe data-driven intents is good enough
-
- Private channels:
-
- Apps can specify private channels via config. A private channel essentially establishes a #Fence (see below) around
- a well known channel. For instance, a suite of related apps might need a way to communicate amongst themselves
- without eavesdropped or imposters.
-         ? Could this be accomplished just as easily with a #Fence rule?
-
- Rules Examples:
-
- When an app (e.g. telephony) receives a call, launch an app called "Screenpop" (context is passed automatically)
- intent=call selectConnect=#Launch@Screenpop
-
- When any intent is sent to the #Chat channel, also send it to a Salesforce driver that creates Activity records, and if possible transform the data into a SalesforceRecord
- intent=\* to=#Chat fork=#Salesforce.Activity #transform=#Salesforce.Record
-
- Possible plugins/system channels:
-
- #Linker - Adds or removes destinations based on linkage (probably a filter, maybe a type of #Fence)
- `from=* filter=#Linker`
-
- #DragNDrop - Removes destinations but stores the data so that it can be emitted when the user drags between windows
- `from=Chart contextType=Symbol fork=#DragNDrop`
-
- #Launch@Chart - Launches apps, passing the contextType/intent to the launched app
- `intent=Screenpop selectConnect=#Launch@Chart@SalesforceActivity`
-
- #Logger@info - Sends the info to a log (probably a fork)
- `from=ProjectEditor intent=Error fork=#Logger@error`
-
- #Workspace - Saves info in a workspace, and then when the workspace is relaunched, emits that info back to the app
- `contextType=symbol fork=#Workspace`
-
- #Fence - Prevents messages from going to apps that aren't in the fence (like a composite but maybe other logical groupings)
- `from=Chart contextType=symbol selectConnect=#Fence` - Keeps a symbol broadcast from escaping the fence (but still lets symbol into the fence from outside)
- `to=Chart contextType=date filter=#Fence` - Prevents a date broadcast from entering the fence
-
- #Trash - /dev/null for messages
- `from=Chart to=Grid selectConnect=#Trash`
-
- #ODAC - Open Data Access Control. Filter messages throuh an access control list (ACL)
- `from=CRD filter=#ODAC` - Prevents delivery to any destination not in the ACL
-
- #Notification - Could be used for sending notifications, or to set rules for data that is delivered by a notification.
- Notifications should probably be genericized to publish intent/context when the user clicks on them. So in a sense
- a notification is like #DragNDrop, where broadcast is deferred until the user clicks on something
- `intent=Trade contextType=FixedIncome selectConnect=#Notification#Bob`
- `intent=Trade from=#Notification selectConnect=#Launch@FixedIncomeApp`
-
- #Search - Most useful with a data-driven intent, could take the place of our search providers
- Also, search results should be intents/contextTypes so that clicking on a result either triggers an action or a context switch
- `from=#Search contextType=Link #Launch@Browser`
-
- #Chat@slackbot - Routes messages to and from a chat network. We might build plugins that work with symphony, slack and teams
- `intent=Trade selectConnect=#Chat#tradechannel`
-
- #ChatCreator - Our own pop-up app that allows a user to create a chat message to be sent to #Chat (like our sales demo)
- Maybe this just listens for a specific intent...
- `intent=Trade selectConnect=#Intent@CreateChat`
-
- #CRM@activity - Send data to the CRM system. We could build plugins that work with Salesforce or other systems
- `to=#Chat contextType=Trade fork=#CRM@activity` - Log an activity record every time we send a trade via chat
-
- #Symphony, #Salesforce - Maybe instead of generic #Chat, #CRM we would have specific channels for specific 3rd parties
-
- #Bloomberg@SRCH - Runs a bloomberg command
- `contextType=Symbol to=#Search fork=#Bloomberg@SRCH` - Sends all searches also to Bloomberg
-
- #Excel@MySheet!A1\*10 - Sends data to a specific cell in Excel
- `contextType=Symbol fork=#Excel@MySheet!A1*10`
-
- #Intent@Share - Convert a context broadcast into an intent
- `from=Chart contextType=Symbol selectConnect=#Intent:Quote` - Whenever the chart changes symbols, ensure that an app is available that shows a Quote for that same symbol
- `intent=Trade selectConnect=#Intent@Chat` - If there's a chat tool that only accepts intents we can use conversion. Might require an automatic translation (e.g. stringify into a Chat envelope) \*/

Obscure errors as the result of misuse of Immer

Always call `current` if you need to pass a piece of store state outside of your reducer.

TypeError: Cannot perform 'get' on a proxy that has been revoked TypeError: Cannot perform 'isExtensible' on a proxy that has been revoked TypeError: Cannot read property 'Symbol(nodejs.util.inspect.custom)' of null
