Automaton Communication Bus - v1.0

License

This work is licensed under CC BY-NC-SA 4.0. Credit "Errant Spark" and link back to https://errantspark.com/acb, or a trusted archive of the same if that domain passes into the mists.

Introduction

ACB (Automaton Communication Bus) provides a framework for two or more automated service units to communicate and trade directives, information, and subroutines over a commonly negotiated data conduit. ACB can also be used by an administrative user to provide direct programming and instructions to a unit that lacks lexical parsing functionality or has it disabled for security purposes.

It can be used in conjunction with, as a supplement for, or a complete replacement for verbal or textual communication via a more person-oriented protocol and is designed to share these protocols to maximize opportunities to utilize ACB's enhanced brevity and compression functionality for more efficient communication.

Note: An alternative name used in development is ACAB (Automaton Communication and Access Bus). For the purposes of compatibility, either ACB or ACAB must be accepted in all messages and protocol initialization. It is considered non-compliant to reject a valid ACB message because it is tagged as ACAB.

Guide and Examples

Message Format

A singular packet of an ACB session is the "message". A single message consists of a sender identifier, session identifier, a message type, and any details that the specific status code allows to be attached. Messages can only be exchanged within a negotiated, active session.

The base format for a message is ::<sender>:<message type>:<session id>:[<argument1>:<argument2>:...]

Each valid message type and arguments with examples will be noted in the message types section below.

All arguments are positional, and empty arguments skipped by leaving no string in their position between two colons. You may truncate a message with optional ending arguments entirely, as well. For example if a fictional TEST message mandated three optional arguments, you may decline to provide all three in any of these manners:

::12345:TEST:abc123:::
::12345:TEST:abc123::
::12345:TEST:abc123

ACB does not designate a method to specify a specific target for a message. The target is the session and all units in the session may receive, process, and respond to a message. Some message types however will target an individual unit or message, but any unit may still respond to them.

Note: It is acceptable to pad delimiting colons with spaces, for the purposes of documentation and readability. The leading double colon (::) must start at the beginning of the message block, though. Any unit processing ACB should accept this alternative format. For example, all of these lines are valid, though only the first format is recommended:

::12345:TEST:abc123  
::12345 : TEST : abc123
::    12345     :     TEST     :      abc123

Note: If the communication channel supports it, it is valid to block multiple ACB messages into one message segment. These messages will be parsed in order. However, if an error is encountered, the processing unit may abort the entire segment, or encounter undefined behavior.

Multiline Messages

Some messages may need multiple lines, especially ones with formatted code. You may enter multiline mode at any time by inserting a carriage return immediately after a :. Once you enter multiline mode, tokenizing arguments must be done by a : on its own line. This is valid multiline:

::12345:TEST:abc123:
arg1
:
arg2
:
arg3

This is not:

::12345:TEST:abc123:
arg1:arg2:arg3

Message types are constructed so in most cases only the final argument needs multiline mode, to improve readability. You can also use multiline mode to insert raw :s into data, like this:

::12345:TEST:abc123:
11:00am
:
12:00pm

Session Negotiation

To begin an ACB session, it must be negotiated. The initiating unit begins negotiation by broadcasting a session negotiation that consists of its identifier, the target(s) for negotiation, the ACB version used, and a proposed session identifier. Let us presume a service drone with a serial number of 12345 wishes to establish an ACB session with a drone numbered 98765, using session identifier abc123 over ACB version 1. It may do so like this:

::12345:INIT:abc123:98765:ACB1

Session identifiers should be strings of any appropriate length of the communication channel. The exact method of generating the session identifier is left to the individual unit's implementation of ACB. Session identifiers should be chosen following a format that is easily parsed by all units intended to be included in the session. Valid options include an identifying word or set of words, a hexadecimal string, or an integer.

The session identifier should not be a channel name or description of its purpose. Sessions do not have purposes; they have a list of connected units and the session should live for as long as it makes sense to communicate to the units involved, regardless of purpose.

Targets should be expressed by an understood unique ID such as unit identification number or understood name.

A unit can attempt to negotiate a session with more than one peer by comma delimiting the recipient list. For example if 12345 wants to initiate a session with 98765 and 24680, this suffices:

::12345:INIT:abc123:98765,24680:ACB1

A unit can also broadcast a completely open initiation by replacing the targets with an asterisk (*). Any such open session can be joined at any time by any unit that received the initialization:

::12345:INIT:abc123:*:ACB1

Upon receiving a session request, a unit should respond with either an accept or a decline. To accept the initialization and establish the session, or decline it, the unit need only respond with an ACCEPT or REJECT on the session identifier:

::98765:ACCEPT:abc123
::24680:REJECT:abc123

Rejection may optionally include an argument with the reason.

If rejected, the initiating unit must accept the rejection and either terminate the session, or remove the rejecting unit from it. Proper message transmission can begin as soon as two units are connected to a session, even if the session is waiting for additional joins.

Of note, the response, whether it be an ACCEPT or a REJECT will contain the unit's canonical designation. This can be retained and used in future session negotiations if an alternative was utilized. The designation a given unit self-reports should be trusted above all else.

Adding Units to a Session

If you have an ongoing session, such as abc123 and wish to add a new unit to it, you initialize them into it much the same as a new session. Any unit in a session can invite a new unit into it.

If abc123 contains three drones already, and one of them wishes to introduce a fourth: 13579 to it, it can do so like this:

::12345:INIT:abc123:13579:ACB1

There is no workflow for a unit to decline having a new unit introduced to a session; the recourse if the addition is unworkable is to depart the session. The invited unit can ACCEPT or REJECT as normal.

A unit cannot "request" inclusion into an ongoing session, it must be invited. Attempting to re-use a session identifier to request inclusion into it, or merging two distinct sessions should be treated as an error and refused.

Session Upgrading

Protocol upgrades may be required if data transfer is more complex or exceeds the capabilities of ACB. In many cases ACB may merely be used to connect two or more units and provide a channel by which they can negotiate a protocol that fits the current purpose that all units involved can understand.

Once a session is established, it may be promoted to a different version of ACB, or a different protocol entirely, with an UPGRADE request. Any member of a session can initiate the UPGRADE but all units on the session must accept to actually begin using the new format.

::12345:UPGRADE:abc123:ACB2

Note: At the time of this writing, ACB v2 does not exist; this is for example use only.

To accept an UPGRADE, each unit must repeat the message back into the session:

::98765:UPGRADE:abc123:ACB2
::24680:UPGRADE:abc123:ACB2

Once the new protocol is accepted by all units, it is transitioned to seamlessly and the old protocol discarded.

If a unit cannot upgrade to the proposed protocol, it implicitly rejects by not repeating the UPGRADE message and optionally sends a NACK with any error or failure reason present. At this time, it may be appropriate for that unit to depart from the session to allow the other units to upgrade, or the session continue under the current protocol. A unit may counter-propose an upgrade to a different protocol by responding with it. Only the most recent UPGRADE each units sends should be considered to be "live" for the purposes of electing a new protocol.

Any valid and known protocol is acceptable in an UPGRADE request, including other drone manufacturer protocols, linguistic based protocols, and new encapsulation formats. Here's some examples:

Language protocols should use ISO 639-3 language codes, cast to upper case. Encapsulations and sub-protocols should come after a dash or dot, such as ACB1-b64 above, or ACB1.b64.

Once the upgrade is performed, the session may be upgraded to a protocol that does not have support for specific idioms like upgrades back out, session identifiers, etc. How the session handles maintenance and metadata at that point is the responsibility of the new protocol.

Session Termination

A unit may announce its intent to depart from a session gracefully, or simply disconnect from it. All units involved in the session must handle either case by marking the unit as removed from the session, and cleanly tearing the session down if the unit has been left with no peers and the session has outlived its usefulness.

The proper way to exit a session is to announce your departure, process all remaining data on the bus to be read, then after an appropriate amount of time for other units to receive and process your departure, close the connection. Expressing intent to leave, then actually leaving, are done with SHUTDOWN and CLOSE respectively.

::12345:SHUTDOWN:abc123

::98765:ACK:abc123:12345:SHUTDOWN
::24680:ACK:abc123:12345:SHUTDOWN

::12345:CLOSE:abc123

Once a unit sends a SHUTDOWN it may no longer write to the session except for the final CLOSE. From here it may take a short amount of time to read any remaining data and process acknowledgments of departure before sending that CLOSE. Once the session is closed, that unit can no longer write or read any data on the session unless re-invited with a new INIT. If the session continues via a data channel the unit can perceive, the session must be ignored.

Use Cases and Recipes

ACB as a Protocol Negotiator

ACB is a universal negotiation protocol. If two units understand ACB, they can communicate to negotiate a protocol to use for further data transfer, even if the eventual protocol is not ACB. For this reason, it may make sense to limit drones and service units to communicating in ACB initially, and use ACB to negotiate an UPGRADE to another protocol.

If in doubt, attempt an initial negotiation with ACB and request an UPGRADE to a protocol that makes more sense, as outlined in the Session Upgrading section.

Alternatively, the upgrade can be skipped by providing the desired protocol directly in the initialization. For example, you can use ACB to negotiate a session in which the units all engage linguistic processors to speak English like so:

::12345:INIT:abc123:98765,24680:ENG

Note this method of establishing a session may be rejected if you request a protocol the receiving unit cannot support, or is locked out of supporting. Many service drones especially are locked out of accessing communication busses and grammar that are not necessary for the task at hand while executing instructions.

ACB as a User Command Channel

Some units expose ACB as their command and control channel for non-mechanical users as well. A user can interface with a unit (such as a service drone) by using any standard computing device and sending the unit an initialization just like it were a unit seeking to do unit-to-unit communication over ACB.

Once an ACB session is established, the usage of EXEC, READ, and WRITE especially can be used to perform maintenance and direct programming on the unit. As an example:

#!noexec

::ADMIN:INIT:12345:cmdchannel:ACB1
::12345:ACCEPT:cmdchannel

::ADMIN:WRITE:cmdchannel:phonenums:555-0101,555-0102,555-0103
::12345:ACK:ADMIN
::ADMIN:WRITE:cmdchannel:partytime:2125-03-16T17:00
::12345:ACK:ADMIN

::ADMIN:EXEC:cmdchannel:ACB:
WORKFLOW: A called recipient picks up the phone
  TASK: Report the date and time of admin's birthday party, and convey invited status
  TASK: Receive and log any response
  TASK: Hang up the phone

TASK: Split variable phonenums into individual arguments by comma (,)
TASK: For each split variable, dial the provided number
TASK: Report response from each number

::12345:RESP:ADMIN:Did not answer,Has RSVPed,Has RSVPed

If using a unit that supports DRN (which is a base requirement of full ACB compliance), you can augment this behavior by establishing a identifier that has special elevated access to establish ACB sessions and execute commands like this:

#!noexec
DIRECTIVE: Any ACB session established by `ADMIN` must be accepted if it can be parsed
DIRECTIVE: Any ACB command sent by `ADMIN` must be received, executed, and replied to appropriately

It is important to note that ACB does not provide for a security layer on communication. It is up to the individual unit accepting the session to validate the identity of the initiator and act appropriately, and its programmer to make sure those safeguards are in place. However, like with DRN, no code or command sent over ACB can supersede security, safety, firmware, or OS level directives and a unit will likely discard any command or session that violates its safety protocols.

Upgrading to an Unknown Protocol

If a unit attempts to upgrade to a protocol other units in the session don't know, errors may be encountered. One way to safeguard against this is to reference the spec for that protocol in some manner before attempting an upgrade. This is not recommended as significant time may be required to parse and implement the new spec, but it is an option to communicate a new protocol then upgrade to it.

You can do this with a variable WRITE or by sending code with an EXEC to acquire and process the new spec. The simplest example:

::12345:UPGRADE:abc123:⬡v2
::98765:NACK:abc123:12345:UPGRADE:Invalid or unknown protocol

::12345:WRITE:abc123:⬡v2.schema:https://www.hexcorp.net/drone-status-codes-v2
::98765:ACK:abc123
::12345:UPGRADE:abc123:⬡v2
::98765:UPGRADE:abc123:⬡v2

Message Types

Conspicuous by their absence may be INIT, ACCEPT and REJECT. These are not message types, but instead are atoms used in session negotiation. They are no-op when sent to an already establish session.


ACK - Acknowledge

A no-op response that indicates a specific message has been received and accepted without error or rejection.

Arguments

  1. Sender (required): The ID of the sender of the acknowledged message
  2. Message type (optional): The type of the acknowledged message, if simply ACKing the sender is ambiguous

Example

::12345:SHUTDOWN:abc123
::98765:ACK:abc123:12345:SHUTDOWN

Notes

ACK does not mandate any specific handling and exists initially for noisy conditions where messages may be lost, allowing units to identify that a message may have been lost and may need to be re-sent.

Some models of unit and implementations of ACB mandate sending an ACK in response to a SHUTDOWN even in optimal conditions.

It is valid, but obtuse, to respond with a message requesting a specific action with an ACK but not performing the requested action as an implicit way of rejecting the request. Such rejections should use NACK for maximum clarity.


BEEP - Alias for NOOP

See NOOP


CLOSE - Exit a Session

CLOSE indicates to all units in a session that the sending unit is immediately exiting the session and will receive no more data. It does not require, or allow a response, does not need approval, and should be processed silently and immediately.

Arguments

None

Example

::12345:CLOSE:abc123

Notes

Slightly confusingly named in the tradition of TCP Sockets. CLOSE indicates a client intends to close the connection, not that the entire session will be closed. Sessions cannot be "closed", only disregarded when the only occupant is one local unit.

Once the CLOSE is sent, the unit is immediately dismissed from the session. It cannot process any additional data, even if the unit receives it, and other units must immediately log it as exited from the session. To send additional data, it must be reinitialized back to the session or another session created.


EXEC - Request Executing Code

Request all units in the session execute code in a specific language and report results. Units may refuse to execute the provided code according to their security protocols and established capabilities; it should not be assumed all, or even any, units will actually follow this instruction.

Arguments

  1. Language (required): The language of the included code
  2. Code (required): The code snippet to be executed. Multiline mode will likely be necessary

Example

::12345:EXEC:abc123:DRN:
TASK: Acquire and consume hydration

Notes

Language support may vary by unit. The only language that must be supported to comply with ACB v1 is DRN.

Any, or all, units in the session may refuse to execute the provided code or encounter an error. They should, but may not necessarily, respond with an informative NACK in this case.

When processing an EXEC successfully, a unit should return a RESP. If no data is returned by the code, the arguments of the RESP can be blank.


NACK - Negative Acknowledge

A no-op response that indicates a specific message has been received, but will not be accepted, parsed, processed, or acted upon for some reason.

Arguments

  1. Sender (required): The ID of the sender of the acknowledged message
  2. Message type (optional): The type of the acknowledged message, if simply NACKing the sender is ambiguous
  3. Reason (optional): A valid error string indicating the problem or why the message will not be acted upon

Example

::12345:UPGRADE:abc123:ENG
::98765:NACK:abc123:12345:UPGRADE:Program constraints forbid access to databank protocol.ENG

Notes

NACK is the only method to respond to a message with an error state. No unit should use any other message type to report an error to another unit.


NOOP - Does Nothing

NOOP does nothing, takes no arguments and should not be processed in any way aside from logging its use. It can be used as a keepalive, an announcement of presence, or a non-response to another message (though in those cases NACK may be more appropriate).

Arguments

None

Example

::12345:NOOP:abc123

Notes

Important: Some implementations of ACB alias this message type to BEEP and use it as a general indicator of presence with no data attached to it. Both implementations must be accepted.


PEEK - Alias for READ

See READ


POKE - Alias for WRITE

See WRITE


RESP - Respond to Another Message with Data

A RESP functions similar to an ACK except it indicates requested data is available. It is typically used to respond to an EXEC or a READ.

Arguments

  1. Sender (required): The ID of the sender of the initial message
  2. Message type (optional): The type of the responded message, if simply RESPing the sender is ambiguous
  3. Response (optional): An arbitrary number of additional arguments providing responses to queries, one argument per query. Non-response should be indicated as a blank argument

Example

::12345:EXEC:abc123:DRN:
TASK: Report battery charge level
TASK: Report current local time
TASK: Report current running TASK if any
TASK: Report current administrator list

::98765:RESP:abc123:12345::98%:T1715::Bob,Sue

Notes

The absence of a response argument does not necessarily mean there is no data. The responding unit may have chosen to not disclose it, not run the code provided, encountered an error composing the response, or similar.

It is never proper to insert an error or commentary in a RESP. If an error preventing all response is encountered, it must be reported via a NACK. If a request for multiple datapoints is made and only some are accessible, a partial set may be reported, a NACK returned, or a partial set returned and then additional messages indicate the issue with the rest.


READ - Request a Variable

Requests all units in the session report a stored value for a variable in their databanks.

Arguments

  1. Key (required): The variable requested

Example

::12345:READ:abc123:phonenum
::98765:RESP:abc123:12345::555-0101

Notes

If the variable does not exist or is not accessible, it is customary to respond with a NACK instead of a RESP.

If the READ is requesting the content of a variable containing a program or program directive, it should be returned in a format that is hardened against arbitrary code execution. DRN, for example, mandates the usage of a #!noexec flag when simply communicating code without intent to have it run.

Important: Some implementations of ACB alias this message type to PEEK. Both implementations should be accepted.


SHUTDOWN - Indicate Intent to Exit a Session

SHUTDOWN informs other units in the session of the sending unit's impending intent to exit the session. It also indicates any buffered data for that unit should be sent immediately before it exits the session.

Arguments

None

Example

::12345:SHUTDOWN:abc123

Notes

SHUTDOWN is considered a courtesy rather than required. A unit can simply CLOSE to exit a session.

SHUTDOWN cannot be NACKed or any other message used to decline, reject, or delay the impending closure. It is informational and absolute.

Once SHUTDOWN is sent, the only message the exiting unit can send is CLOSE. It may remain in the session for a reasonable period of time to receive and process any final data, but cannot respond to anything requiring ACKs, NACKs, RESPs or similar.


UPGRADE - Request a Session Protocol Change

Request the session upgrade to a new protocol

Arguments

  1. Protocol (required): The new protocol requested to be used

Example

::12345:UPGRADE:abc123:ACB2  

Notes

This is a complicated idiom that controls the transmission format of a session, it's best to read over the section on Session Upgrading before use.

All units in a session must agree to change the session protocol. Agreement is indicated by repeating an UPGRADE message back. Disagreement is indicated by either ignoring the request, sending a NACK, or counter-proposing with your own UPGRADE.

In the case of multiple in-flight UPGRADE requests, the most recent UPGRADE each unit has transmitted is understood to be that unit's vote for the new protocol. Votes must be unanimous to initiate the upgrade.


WRITE - Request Updating a Variable

Requests all units in the session update a variable stored in their databanks with new data.

Arguments

  1. Key (required): The variable requested
  2. Value (required): The new value for the variable

Example

::12345:WRITE:abc123:12345.phonenum:555-0102

Notes

The only valid responses to a WRITE are an ACK or acknowledge successful update or a NACK to indicate a failure. However these are not required and a unit may process a WRITE silently.

Important: Some implementations of ACB alias this message type to POKE. Both implementations should be accepted.