918 lines
18 KiB
Markdown
918 lines
18 KiB
Markdown
# Yonexus Protocol Specification
|
|
|
|
Version: draft v0.1
|
|
Status: planning
|
|
|
|
---
|
|
|
|
## 1. Purpose
|
|
|
|
This document defines the **Yonexus built-in communication protocol** used between OpenClaw instances.
|
|
|
|
Yonexus has two roles:
|
|
- `main`: the central WebSocket server/hub
|
|
- `follower`: an outbound WebSocket client connected to `main`
|
|
|
|
This protocol covers only the **built-in/system channel** required for:
|
|
- connection setup
|
|
- pairing
|
|
- authentication
|
|
- heartbeat
|
|
- status/lifecycle events
|
|
- protocol-level errors
|
|
|
|
Application-level business messages are transported separately through the Yonexus rule dispatch layer, but they still use the same WebSocket connection.
|
|
|
|
---
|
|
|
|
## 2. Transport
|
|
|
|
## 2.1 Protocol Transport
|
|
|
|
Transport is WebSocket.
|
|
|
|
- `main` listens as WebSocket server
|
|
- `follower` connects as WebSocket client
|
|
- all protocol frames are UTF-8 text messages in the first version
|
|
|
|
Binary frames are not required in v1.
|
|
|
|
## 2.2 Endpoint
|
|
|
|
The `follower` connects to `mainHost`, which may be configured as:
|
|
- full URL: `ws://host:port/path` or `wss://host:port/path`
|
|
- or raw `host:port` if implementation normalizes it
|
|
|
|
Recommended canonical configuration for docs and production:
|
|
- prefer full WebSocket URL
|
|
|
|
---
|
|
|
|
## 3. Message Categories
|
|
|
|
Yonexus messages over WebSocket are split into two categories:
|
|
|
|
### 3.1 Builtin Protocol Messages
|
|
|
|
Builtin/system messages always use the reserved rule identifier:
|
|
|
|
```text
|
|
builtin::${json_payload}
|
|
```
|
|
|
|
User code must never register a handler for `builtin`.
|
|
|
|
### 3.2 Application Rule Messages
|
|
|
|
Application messages use the normal format:
|
|
|
|
```text
|
|
${rule_identifier}::${message_content}
|
|
```
|
|
|
|
When received by `main` from a follower, before dispatch they are rewritten to:
|
|
|
|
```text
|
|
${rule_identifier}::${sender_identifier}::${message_content}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Builtin Message Envelope
|
|
|
|
Builtin messages use this wire format:
|
|
|
|
```text
|
|
builtin::{JSON}
|
|
```
|
|
|
|
Where the JSON payload has this envelope shape:
|
|
|
|
```ts
|
|
interface BuiltinEnvelope {
|
|
type: string;
|
|
requestId?: string;
|
|
timestamp?: number;
|
|
payload?: Record<string, unknown>;
|
|
}
|
|
```
|
|
|
|
Field semantics:
|
|
- `type`: builtin message type
|
|
- `requestId`: optional correlation id for request/response pairs
|
|
- `timestamp`: sender-side UTC unix timestamp in seconds or milliseconds (must be standardized in implementation)
|
|
- `payload`: type-specific object
|
|
|
|
## 4.1 Timestamp Unit
|
|
|
|
To avoid ambiguity, protocol implementation should standardize on:
|
|
|
|
```text
|
|
UTC Unix timestamp in seconds
|
|
```
|
|
|
|
If milliseconds are ever used internally, they must not leak into protocol payloads without explicit versioning.
|
|
|
|
---
|
|
|
|
## 5. Builtin Message Types
|
|
|
|
The first protocol version should define these builtin message types.
|
|
|
|
## 5.1 Session / Connection
|
|
|
|
### `hello`
|
|
Sent by follower immediately after WebSocket connection opens.
|
|
|
|
Purpose:
|
|
- identify follower intent
|
|
- declare identifier
|
|
- advertise available auth material/state
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"hello",
|
|
"requestId":"req_001",
|
|
"timestamp":1711886400,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"hasSecret":true,
|
|
"hasKeyPair":true,
|
|
"publicKey":"<optional-public-key>",
|
|
"protocolVersion":"1"
|
|
}
|
|
}
|
|
```
|
|
|
|
Notes:
|
|
- `publicKey` may be included during first connection and may also be re-sent during re-pair
|
|
- `hasSecret` indicates whether follower believes it already holds a valid secret
|
|
- `hasKeyPair` indicates whether follower has generated a key pair locally
|
|
|
|
### `hello_ack`
|
|
Sent by main in response to `hello`.
|
|
|
|
Purpose:
|
|
- acknowledge identifier
|
|
- indicate required next step
|
|
|
|
Possible next actions:
|
|
- `pair_required`
|
|
- `auth_required`
|
|
- `rejected`
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"hello_ack",
|
|
"requestId":"req_001",
|
|
"timestamp":1711886401,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"nextAction":"pair_required"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5.2 Pairing Flow
|
|
|
|
### `pair_request`
|
|
Sent by main when follower needs pairing.
|
|
|
|
Purpose:
|
|
- start pairing challenge
|
|
- deliver pairing code and expiry
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"pair_request",
|
|
"requestId":"req_002",
|
|
"timestamp":1711886402,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"pairingCode":"ABCD-1234-XYZ",
|
|
"expiresAt":1711886702,
|
|
"ttlSeconds":300,
|
|
"publicKeyAccepted":true
|
|
}
|
|
}
|
|
```
|
|
|
|
### `pair_confirm`
|
|
Sent by follower to confirm pairing.
|
|
|
|
Purpose:
|
|
- prove receipt of pairing code before expiry
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"pair_confirm",
|
|
"requestId":"req_002",
|
|
"timestamp":1711886410,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"pairingCode":"ABCD-1234-XYZ"
|
|
}
|
|
}
|
|
```
|
|
|
|
### `pair_success`
|
|
Sent by main after successful pairing.
|
|
|
|
Purpose:
|
|
- return generated secret
|
|
- confirm trusted pairing state
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"pair_success",
|
|
"requestId":"req_002",
|
|
"timestamp":1711886411,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"secret":"<random-secret>",
|
|
"pairedAt":1711886411
|
|
}
|
|
}
|
|
```
|
|
|
|
### `pair_failed`
|
|
Sent by main if pairing fails.
|
|
|
|
Example reasons:
|
|
- expired
|
|
- invalid_code
|
|
- identifier_not_allowed
|
|
- internal_error
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"pair_failed",
|
|
"requestId":"req_002",
|
|
"timestamp":1711886710,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"reason":"expired"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5.3 Authentication Flow
|
|
|
|
After pairing, reconnect authentication uses the stored `secret`, nonce, timestamp, and follower private key.
|
|
|
|
## 5.3.1 Authentication Payload Construction
|
|
|
|
Follower constructs plaintext proof data as:
|
|
|
|
```text
|
|
secret + nonce + timestamp
|
|
```
|
|
|
|
Where:
|
|
- `secret`: the current shared secret issued by main
|
|
- `nonce`: 24 random characters
|
|
- `timestamp`: current UTC Unix timestamp in seconds
|
|
|
|
Recommended future improvement:
|
|
- use a canonical delimiter or JSON encoding before signing to avoid ambiguity
|
|
|
|
For v1 planning, the required logical content is unchanged, but implementation should prefer a canonical serialized object like:
|
|
|
|
```json
|
|
{
|
|
"secret":"...",
|
|
"nonce":"...",
|
|
"timestamp":1711886500
|
|
}
|
|
```
|
|
|
|
and then sign the serialized bytes.
|
|
|
|
## 5.3.2 Signature Primitive
|
|
|
|
The requirement says the follower uses the private key to encrypt/sign the proof.
|
|
|
|
For implementation, the recommended primitive is:
|
|
- **digital signature using the private key**
|
|
- verified by main using the stored public key
|
|
|
|
This should replace any literal “private-key encryption” wording in implementation docs.
|
|
|
|
### `auth_request`
|
|
Sent by follower to authenticate after pairing.
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"auth_request",
|
|
"requestId":"req_003",
|
|
"timestamp":1711886500,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"nonce":"RANDOM24CHARACTERSTRINGX",
|
|
"proofTimestamp":1711886500,
|
|
"signature":"<base64-signature>",
|
|
"publicKey":"<optional-public-key-if-rotating>"
|
|
}
|
|
}
|
|
```
|
|
|
|
Validation performed by main:
|
|
1. identifier is allowlisted
|
|
2. identifier exists in registry
|
|
3. follower is in paired state
|
|
4. public key matches expected key if provided
|
|
5. signature verifies successfully against canonical proof payload
|
|
6. proof contains correct secret
|
|
7. `abs(now - proofTimestamp) < 10`
|
|
8. nonce has not appeared in recent nonce window
|
|
9. handshake attempts in last 10 seconds do not exceed 10
|
|
|
|
### `auth_success`
|
|
Sent by main on successful authentication.
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"auth_success",
|
|
"requestId":"req_003",
|
|
"timestamp":1711886501,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"authenticatedAt":1711886501,
|
|
"status":"online"
|
|
}
|
|
}
|
|
```
|
|
|
|
### `auth_failed`
|
|
Sent by main if authentication fails.
|
|
|
|
Allowed failure reasons include:
|
|
- unknown_identifier
|
|
- not_paired
|
|
- invalid_signature
|
|
- invalid_secret
|
|
- stale_timestamp
|
|
- future_timestamp
|
|
- nonce_collision
|
|
- rate_limited
|
|
- re_pair_required
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"auth_failed",
|
|
"requestId":"req_003",
|
|
"timestamp":1711886501,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"reason":"stale_timestamp",
|
|
"rePairRequired":false
|
|
}
|
|
}
|
|
```
|
|
|
|
### `re_pair_required`
|
|
Sent by main when unsafe conditions or trust reset require full pairing again.
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"re_pair_required",
|
|
"requestId":"req_004",
|
|
"timestamp":1711886510,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"reason":"nonce_collision"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5.4 Heartbeat
|
|
|
|
### `heartbeat`
|
|
Sent by follower every 5 minutes after authentication.
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"heartbeat",
|
|
"timestamp":1711886800,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"status":"alive"
|
|
}
|
|
}
|
|
```
|
|
|
|
### `heartbeat_ack`
|
|
Optional response by main.
|
|
|
|
Purpose:
|
|
- confirm receipt
|
|
- provide server time or status hints if desired
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"heartbeat_ack",
|
|
"timestamp":1711886801,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"status":"online"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5.5 Status / Lifecycle Notifications
|
|
|
|
### `status_update`
|
|
Sent by main when follower state changes.
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"status_update",
|
|
"timestamp":1711887220,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"status":"unstable",
|
|
"reason":"heartbeat_timeout_7m"
|
|
}
|
|
}
|
|
```
|
|
|
|
### `disconnect_notice`
|
|
Sent before main deliberately closes a follower connection.
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"disconnect_notice",
|
|
"timestamp":1711887460,
|
|
"payload":{
|
|
"identifier":"follower-a",
|
|
"reason":"heartbeat_timeout_11m"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5.6 Errors
|
|
|
|
### `error`
|
|
Generic protocol-level error envelope.
|
|
|
|
Example:
|
|
|
|
```text
|
|
builtin::{
|
|
"type":"error",
|
|
"requestId":"req_999",
|
|
"timestamp":1711887000,
|
|
"payload":{
|
|
"code":"MALFORMED_MESSAGE",
|
|
"message":"missing type field"
|
|
}
|
|
}
|
|
```
|
|
|
|
Recommended builtin error codes:
|
|
- `MALFORMED_MESSAGE`
|
|
- `UNSUPPORTED_PROTOCOL_VERSION`
|
|
- `IDENTIFIER_NOT_ALLOWED`
|
|
- `PAIRING_REQUIRED`
|
|
- `PAIRING_EXPIRED`
|
|
- `AUTH_FAILED`
|
|
- `NONCE_COLLISION`
|
|
- `RATE_LIMITED`
|
|
- `RE_PAIR_REQUIRED`
|
|
- `FOLLOWER_OFFLINE`
|
|
- `INTERNAL_ERROR`
|
|
|
|
---
|
|
|
|
## 6. Builtin State Machines
|
|
|
|
## 6.1 Follower State Machine
|
|
|
|
Suggested follower states:
|
|
- `idle`
|
|
- `connecting`
|
|
- `connected`
|
|
- `pairing_required`
|
|
- `pairing_pending`
|
|
- `paired`
|
|
- `authenticating`
|
|
- `authenticated`
|
|
- `reconnecting`
|
|
- `error`
|
|
|
|
Typical transitions:
|
|
|
|
```text
|
|
idle
|
|
-> connecting
|
|
-> connected
|
|
-> (pairing_required | authenticating)
|
|
|
|
pairing_required
|
|
-> pairing_pending
|
|
-> paired
|
|
-> authenticating
|
|
-> authenticated
|
|
|
|
authenticated
|
|
-> reconnecting (on socket close)
|
|
-> connecting
|
|
```
|
|
|
|
On `re_pair_required`:
|
|
|
|
```text
|
|
authenticated | authenticating -> pairing_required
|
|
```
|
|
|
|
## 6.2 Main-Side Follower Trust State
|
|
|
|
Per follower trust state:
|
|
- `unpaired`
|
|
- `pending`
|
|
- `paired`
|
|
- `revoked`
|
|
|
|
Per follower liveness state:
|
|
- `online`
|
|
- `unstable`
|
|
- `offline`
|
|
|
|
These are related but not identical.
|
|
|
|
Example:
|
|
- follower may be `paired` + `offline`
|
|
- follower may be `pending` + `offline`
|
|
|
|
---
|
|
|
|
## 7. Security Windows and Replay Protection
|
|
|
|
## 7.1 Nonce Requirements
|
|
|
|
Nonce rules:
|
|
- exactly 24 random characters
|
|
- generated fresh for each auth attempt
|
|
- must not repeat within the recent security window
|
|
|
|
## 7.2 Recent Nonce Window
|
|
|
|
Main stores for each follower:
|
|
- the last 10 nonces seen within the recent validity window
|
|
|
|
If a nonce collides with the recent stored set:
|
|
- authentication must fail
|
|
- main must mark the situation unsafe
|
|
- follower must re-pair
|
|
|
|
## 7.3 Handshake Attempt Window
|
|
|
|
Main stores recent handshake attempt timestamps for each follower.
|
|
|
|
If more than 10 handshake attempts occur within 10 seconds:
|
|
- authentication must fail
|
|
- main must mark situation unsafe
|
|
- follower must re-pair
|
|
|
|
## 7.4 Time Drift Validation
|
|
|
|
Main validates:
|
|
|
|
```text
|
|
abs(current_utc_unix_time - proofTimestamp) < 10
|
|
```
|
|
|
|
If validation fails:
|
|
- auth fails
|
|
- no successful session is established
|
|
|
|
Implementation note:
|
|
- use server time only on main as source of truth
|
|
|
|
---
|
|
|
|
## 8. Rule Message Dispatch Semantics
|
|
|
|
## 8.1 Message Format
|
|
|
|
All non-builtin messages use:
|
|
|
|
```text
|
|
${rule_identifier}::${message_content}
|
|
```
|
|
|
|
### Examples
|
|
|
|
Follower to main:
|
|
|
|
```text
|
|
chat_sync::{"conversationId":"abc","body":"hello"}
|
|
```
|
|
|
|
Main rewrites before matching:
|
|
|
|
```text
|
|
chat_sync::follower-a::{"conversationId":"abc","body":"hello"}
|
|
```
|
|
|
|
## 8.2 Rule Matching
|
|
|
|
Initial rule matching should be exact string match against `rule_identifier`.
|
|
|
|
Dispatch algorithm:
|
|
1. parse first delimiter section as `rule_identifier`
|
|
2. if `rule_identifier === builtin`, route to builtin protocol handler
|
|
3. otherwise iterate registered rules in registration order
|
|
4. invoke the first exact match
|
|
5. ignore/log if no match is found
|
|
|
|
## 8.3 Processor Input
|
|
|
|
Processor receives the final message string exactly as seen after protocol-level rewrite.
|
|
|
|
This means:
|
|
- on follower, processor input remains `${rule_identifier}::${message_content}`
|
|
- on main for follower-originated messages, processor input becomes `${rule_identifier}::${sender_identifier}::${message_content}`
|
|
|
|
---
|
|
|
|
## 9. Connection Rules
|
|
|
|
## 9.1 Allowed Connection Policy
|
|
|
|
Main should reject connection attempts when:
|
|
- identifier is absent
|
|
- identifier is not in configured `followerIdentifiers`
|
|
- protocol version is unsupported
|
|
- builtin hello/auth payload is malformed
|
|
|
|
## 9.2 One Active Connection Per Identifier
|
|
|
|
Recommended v1 policy:
|
|
- only one active authenticated connection per follower identifier
|
|
|
|
If a second connection for the same identifier appears:
|
|
- main may reject the new one, or
|
|
- terminate the previous one and accept the new one
|
|
|
|
This behavior must be chosen explicitly in implementation.
|
|
|
|
Recommended default:
|
|
- terminate old, accept new after successful auth
|
|
|
|
---
|
|
|
|
## 10. Persistence Semantics
|
|
|
|
## 10.1 Main Persists
|
|
|
|
At minimum:
|
|
- identifier
|
|
- public key
|
|
- secret
|
|
- trust state
|
|
- pairing code + expiry if pairing is pending
|
|
- last known liveness status
|
|
- metadata timestamps
|
|
|
|
May persist or reset on restart:
|
|
- recent nonces
|
|
- recent handshake attempts
|
|
|
|
Recommended v1:
|
|
- clear rolling security windows on restart
|
|
- keep long-lived trust records
|
|
|
|
## 10.2 Follower Persists
|
|
|
|
At minimum:
|
|
- identifier
|
|
- private key
|
|
- secret
|
|
- protocol version if useful
|
|
- last successful pair/auth metadata if useful
|
|
|
|
---
|
|
|
|
## 11. Versioning
|
|
|
|
Protocol payloads should include a protocol version during `hello`.
|
|
|
|
Initial protocol version:
|
|
|
|
```text
|
|
1
|
|
```
|
|
|
|
If main does not support the provided version, it should respond with:
|
|
- `error`
|
|
- code: `UNSUPPORTED_PROTOCOL_VERSION`
|
|
|
|
---
|
|
|
|
## 12. Recommended Canonical JSON Shapes
|
|
|
|
To reduce ambiguity during implementation, these payload models are recommended.
|
|
|
|
```ts
|
|
interface HelloPayload {
|
|
identifier: string;
|
|
hasSecret: boolean;
|
|
hasKeyPair: boolean;
|
|
publicKey?: string;
|
|
protocolVersion: string;
|
|
}
|
|
|
|
interface PairRequestPayload {
|
|
identifier: string;
|
|
pairingCode: string;
|
|
expiresAt: number;
|
|
ttlSeconds: number;
|
|
publicKeyAccepted: boolean;
|
|
}
|
|
|
|
interface PairConfirmPayload {
|
|
identifier: string;
|
|
pairingCode: string;
|
|
}
|
|
|
|
interface PairSuccessPayload {
|
|
identifier: string;
|
|
secret: string;
|
|
pairedAt: number;
|
|
}
|
|
|
|
interface AuthRequestPayload {
|
|
identifier: string;
|
|
nonce: string;
|
|
proofTimestamp: number;
|
|
signature: string;
|
|
publicKey?: string;
|
|
}
|
|
|
|
interface HeartbeatPayload {
|
|
identifier: string;
|
|
status: "alive";
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 13. Example End-to-End Flows
|
|
|
|
## 13.1 First-Time Pairing Flow
|
|
|
|
```text
|
|
Follower connects WS
|
|
Follower -> builtin::hello
|
|
Main -> builtin::hello_ack(nextAction=pair_required)
|
|
Main -> builtin::pair_request(pairingCode, expiresAt)
|
|
Follower -> builtin::pair_confirm(pairingCode)
|
|
Main -> builtin::pair_success(secret)
|
|
Follower stores secret
|
|
Follower -> builtin::auth_request(signature over secret+nonce+timestamp)
|
|
Main -> builtin::auth_success
|
|
Follower enters authenticated state
|
|
```
|
|
|
|
## 13.2 Normal Reconnect Flow
|
|
|
|
```text
|
|
Follower connects WS
|
|
Follower -> builtin::hello(hasSecret=true)
|
|
Main -> builtin::hello_ack(nextAction=auth_required)
|
|
Follower -> builtin::auth_request(...)
|
|
Main -> builtin::auth_success
|
|
Follower begins heartbeat schedule
|
|
```
|
|
|
|
## 13.3 Unsafe Replay / Collision Flow
|
|
|
|
```text
|
|
Follower -> builtin::auth_request(nonce collision)
|
|
Main detects unsafe condition
|
|
Main -> builtin::re_pair_required(reason=nonce_collision)
|
|
Main invalidates existing secret/session trust
|
|
Follower returns to pairing_required state
|
|
```
|
|
|
|
## 13.4 Heartbeat Timeout Flow
|
|
|
|
```text
|
|
Follower authenticated
|
|
No heartbeat for 7 min -> main marks unstable
|
|
No heartbeat for 11 min -> main marks offline
|
|
Main -> builtin::disconnect_notice
|
|
Main closes WS connection
|
|
```
|
|
|
|
---
|
|
|
|
## 14. Implementation Notes
|
|
|
|
## 14.1 Parsing
|
|
|
|
Because the top-level wire format is string-based with `::` delimiters:
|
|
- only the first delimiter split should determine the `rule_identifier`
|
|
- for `builtin`, the remainder should be treated as JSON string and parsed once
|
|
- message content itself may contain `::`, so avoid naive full split logic
|
|
|
|
## 14.2 Payload Encoding
|
|
|
|
Recommended message content for application rules:
|
|
- JSON string payloads where applicable
|
|
- but Yonexus itself only requires string content
|
|
|
|
## 14.3 Logging
|
|
|
|
Main should log at least:
|
|
- connection open/close
|
|
- hello received
|
|
- pairing created/succeeded/expired/failed
|
|
- auth success/failure
|
|
- nonce collisions
|
|
- handshake rate-limit triggers
|
|
- status transitions
|
|
- unhandled rule messages
|
|
|
|
Sensitive values must never be logged in plaintext:
|
|
- `secret`
|
|
- private key
|
|
- raw proof material
|
|
- full signature verification internals unless safely redacted
|
|
|
|
---
|
|
|
|
## 15. Open Clarifications
|
|
|
|
Before implementation, these should be finalized:
|
|
|
|
1. Exact signing algorithm:
|
|
- Ed25519 is a strong default candidate
|
|
2. Secret length and generation requirements
|
|
3. Pairing code format and length
|
|
4. Whether `pair_request` should require operator confirmation or stay automatic for allowlisted identifiers
|
|
5. Whether `heartbeat_ack` is mandatory or optional
|
|
6. Whether follower should auto-reconnect with backoff strategy after disconnect
|
|
7. Whether duplicate active connections should replace old sessions or be rejected
|
|
|
|
---
|
|
|
|
## 16. Summary of Reserved Builtin Types
|
|
|
|
Current reserved builtin `type` values:
|
|
- `hello`
|
|
- `hello_ack`
|
|
- `pair_request`
|
|
- `pair_confirm`
|
|
- `pair_success`
|
|
- `pair_failed`
|
|
- `auth_request`
|
|
- `auth_success`
|
|
- `auth_failed`
|
|
- `re_pair_required`
|
|
- `heartbeat`
|
|
- `heartbeat_ack`
|
|
- `status_update`
|
|
- `disconnect_notice`
|
|
- `error`
|
|
|
|
These names are reserved by Yonexus and must not be repurposed by user rules. |