PSF: Mass-regeneration complete. 53/53 high-fidelity blueprints and TDD suites established. Zero-cost Pro bridge active.

This commit is contained in:
2026-04-07 08:58:08 -04:00
parent f4a91ae747
commit 77c0dac025
58 changed files with 2154 additions and 1671 deletions

View File

@@ -26,72 +26,71 @@ Define a secure and extensible ingress for external communication channels.
*** TODO Sender verification logic (Whitelisting)
*** TODO Autonomous stimulus injection into the Kernel Bus
* Phase B: Blueprint (PROTOCOL)
:PROPERTIES:
:STATUS: SIGNED
:END:
* Phase B: Blueprint (PROTOCOL)
:PROPERTIES:
:STATUS: DRAFT
:END:
** 1. Architectural Intent
Interfaces for external sensory perception. Source of truth is the external API callbacks and local messaging daemons.
The Inbound Gateway should operate as a modular, asynchronous service.
Each channel (Signal, Telegram, Webhook) will have its own adapter responsible for receiving and normalizing messages.
A central dispatcher will then authenticate and inject these normalized messages as stimuli into the Neurosymbolic Kernels message bus.
Error handling and logging will be crucial for observability and maintainability.
** 2. Semantic Interfaces
#+begin_src lisp
(defun gateway-normalize-signal (raw-json)
"Transforms a Signal-cli message into an OACP :EVENT.")
** 2. Semantic Interfaces (Lisp Signatures)
(defun gateway-normalize-telegram (raw-json)
"Transforms a Telegram Bot payload into an OACP :EVENT.")
*** `inbound-message-handler`
- *Purpose:* Main entry point for processing inbound messages from all channels.
- *Signature:* `(inbound-message-handler channel message-payload)`
- *Arguments:*
- `channel` (keyword): Identifies the source channel (e.g., `:signal`, `:telegram`, `:webhook`).
- `message-payload` (string): The raw message payload received from the channel.
- *Returns:* Boolean indicating successful processing (T) or failure (NIL).
(defun gateway-verify-sender (sender-id channel)
"Ensures the message is from an authorized recipient.")
*** `normalize-message`
- *Purpose:* Converts a platform-specific message payload into a standard Lisp plist.
- *Signature:* `(normalize-message channel message-payload)`
- *Arguments:*
- `channel` (keyword): The source channel.
- `message-payload` (string): The raw message payload.
- *Returns:* A Lisp plist representing the normalized message. Example: `(:sender "+15551234567" :text "Hello, world!" :timestamp 1678886400)`.
(defun gateway-process-inbound (message-event)
"Routes the normalized message through the Economist for cheap classification,
then places it in the 'Holding Pen' (inbox.org).")
#+end_src
*** `authenticate-sender`
- *Purpose:* Verifies the identity of the message sender based on the channel.
- *Signature:* `(authenticate-sender channel sender-id)`
- *Arguments:*
- `channel` (keyword): The source channel.
- `sender-id` (string): The sender's unique identifier (e.g., phone number for Signal, username for Telegram).
- *Returns:* Boolean indicating successful authentication (T) or failure (NIL). Consider using ACLs (Access Control Lists).
* Phase D: Build (Implementation)
*** `inject-stimulus`
- *Purpose:* Injects a normalized message into the Neurosymbolic Kernel's message bus as a stimulus.
- *Signature:* `(inject-stimulus stimulus-plist)`
- *Arguments:*
- `stimulus-plist` (plist): The normalized message plist.
- *Returns:* A unique identifier for the injected stimulus.
** Normalization Logic
#+begin_src lisp :tangle projects/org-skill-inbound-gateway/src/gateway-logic.lisp
(defun gateway-verify-sender (sender-id channel)
(let ((approved (uiop:getenv "RECIPIENT_ID")))
(string= sender-id approved)))
*** `channel-listener`
- *Purpose:* Asynchronously listens for inbound messages on a specific channel.
- *Signature:* `(channel-listener channel-config)`
- *Arguments:*
- `channel-config` (plist): Configuration parameters specific to the channel (e.g., API key, webhook URL).
- *Returns:* (Non-blocking) N/A. The listener will spawn threads to handle incoming messages.
(defun gateway-normalize-signal (raw-json)
(let* ((data (cl-json:decode-json-from-string raw-json))
(sender (cdr (assoc :source data)))
(text (cdr (assoc :message data))))
(if (gateway-verify-sender sender :signal)
`(:type :EVENT :payload (:sensor :inbound-message :channel :signal :text ,text))
(progn
(kernel-log "GATEWAY - Rejected message from unauthorized sender: ~a" sender)
nil))))
(defun gateway-process-inbound (message-event)
"The Holding Pen logic. It uses a low-cost model to classify the message
and appends it to inbox.org."
(let* ((text (getf (getf message-event :payload) :text))
;; Route through Economist for cheap classification
(backend (org-agent:economist-route-task 2)) ; Low complexity
(classification (org-agent:ask-neuro
(format nil "Classify this text into one tag (e.g., :idea:, :todo:, :link:): ~a" text)
:system-prompt "You are a fast, cheap triage agent. Return ONLY the tag."
:cascade (list backend)))
(inbox-path (or (uiop:getenv "INBOX_FILE") "inbox.org"))
(timestamp (local-time:format-timestring nil (local-time:now) :format '("[" :year "-" :month "-" :day " " :weekday "]"))))
(with-open-file (out inbox-path :direction :output :if-exists :append :if-does-not-exist :create)
(format out "* INBOX ~a ~a~% Captured via ~a at ~a~% ~a~%~%"
classification text (getf (getf message-event :payload) :channel) timestamp text))
(kernel-log "GATEWAY - Message routed to Holding Pen (~a)." inbox-path)))
#+end_src
** 3. Example Flow (Signal)
1. `channel-listener` (for `:signal`) receives a new message via `signal-cli`.
2. The raw message is passed to `inbound-message-handler` with `channel` = `:signal`.
3. `inbound-message-handler` calls `normalize-message` to convert the Signal payload to a standard plist.
4. `inbound-message-handler` calls `authenticate-sender` to verify the sender's identity.
5. If authentication succeeds, `inbound-message-handler` calls `inject-stimulus` to inject the message into the Kernel.
6. Error handling and logging are performed at each step.
* Registration
#+begin_src lisp
(defskill :skill-inbound-gateway
:priority 100
:trigger (lambda (context) (eq (getf (getf context :payload) :sensor) :inbound-message))
:neuro (lambda (context) nil)
:symbolic (lambda (action context) (gateway-process-inbound context) nil)) ; Side-effect only
#+end_src