docs: add literate prose to naming-drift aliases and HITL gateway changes
Some checks failed
Deploy (Gitea) / deploy (push) Failing after 3s
Some checks failed
Deploy (Gitea) / deploy (push) Failing after 3s
Adds prose sections before every code block to satisfy the prose-before-code discipline. Each backward-compatibility alias (process-signal, perceive-gate, reason-gate, act-gate, inject-stimulus) now has its own subsection explaining why it exists and what new code should use instead. Also: - Fixes double #+end_src in core-loop-perceive.org - Renames inject-stimulus → stimulus-inject in heartbeat-start and client-handle-connection (both already had aliases) - Adds HITL interception prose to gateway-manager.org telegram/signal sections - Splits Pre-Reason Handler Registry into two code blocks (defvar + defun) for one-per-block compliance
This commit is contained in:
@@ -71,7 +71,7 @@
|
||||
nil))))
|
||||
(format stream "~a" (frame-message health-msg))
|
||||
(finish-output stream)))
|
||||
(t (inject-stimulus msg :stream stream))))))
|
||||
(t (stimulus-inject msg :stream stream))))))
|
||||
(error (c) (log-message "CLIENT ERROR: ~a" c)))
|
||||
(ignore-errors (usocket:socket-close socket))))
|
||||
|
||||
|
||||
@@ -96,10 +96,6 @@
|
||||
(t (format nil "TOOL [~a] RESULT: ~s" tool-name result))))
|
||||
(format nil "TOOL [~a] RESULT: ~a" tool-name result)))
|
||||
|
||||
;; Alias: act-gate → loop-gate-act
|
||||
(defun act-gate (signal)
|
||||
(loop-gate-act signal))
|
||||
|
||||
(defun loop-gate-act (signal)
|
||||
"Final stage of the metabolic pipeline: Actuation.
|
||||
For approval-required actions, creates a Flight Plan instead of executing."
|
||||
@@ -155,6 +151,9 @@ For approval-required actions, creates a Flight Plan instead of executing."
|
||||
(setf (getf signal :status) :acted)
|
||||
feedback))
|
||||
|
||||
(defun act-gate (signal)
|
||||
(loop-gate-act signal))
|
||||
|
||||
(eval-when (:compile-toplevel :load-toplevel :execute)
|
||||
(ql:quickload :fiveam :silent t))
|
||||
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
FN receives (signal) and returns T if consumed, nil to continue."
|
||||
(setf (gethash sensor *pre-reason-handlers*) fn))
|
||||
|
||||
;; Alias for backward compatibility
|
||||
(defun inject-stimulus (raw-message &key stream (depth 0))
|
||||
"Alias for stimulus-inject."
|
||||
(stimulus-inject raw-message :stream stream :depth depth))
|
||||
|
||||
(defun stimulus-inject (raw-message &key stream (depth 0))
|
||||
@@ -53,10 +51,6 @@ FN receives (signal) and returns T if consumed, nil to continue."
|
||||
(skip-event ()
|
||||
(log-message "SYSTEM RECOVERY: Stimulus dropped."))))))
|
||||
|
||||
;; Alias: perceive-gate → loop-gate-perceive
|
||||
(defun perceive-gate (signal)
|
||||
(loop-gate-perceive signal))
|
||||
|
||||
(defun loop-gate-perceive (signal)
|
||||
"Stage 1 of the metabolic pipeline: Normalize sensory input."
|
||||
(let* ((payload (getf signal :payload))
|
||||
@@ -110,6 +104,9 @@ FN receives (signal) and returns T if consumed, nil to continue."
|
||||
(setf (getf signal :foveal-focus) *loop-focus-id*)
|
||||
signal))
|
||||
|
||||
(defun perceive-gate (signal)
|
||||
(loop-gate-perceive signal))
|
||||
|
||||
(eval-when (:compile-toplevel :load-toplevel :execute)
|
||||
(ql:quickload :fiveam :silent t))
|
||||
|
||||
|
||||
@@ -121,10 +121,6 @@ modified action (for approval-required or pass)."
|
||||
:action approval-action))
|
||||
current-action)))
|
||||
|
||||
;; Alias: reason-gate → loop-gate-reason
|
||||
(defun reason-gate (signal)
|
||||
(loop-gate-reason signal))
|
||||
|
||||
(defun loop-gate-reason (signal)
|
||||
(let* ((type (proto-get signal :type))
|
||||
(payload (proto-get signal :payload))
|
||||
@@ -162,6 +158,9 @@ modified action (for approval-required or pass)."
|
||||
(setf (getf signal :status) :reasoned)
|
||||
(return signal))))))))
|
||||
|
||||
(defun reason-gate (signal)
|
||||
(loop-gate-reason signal))
|
||||
|
||||
(eval-when (:compile-toplevel :load-toplevel :execute)
|
||||
(ql:quickload :fiveam :silent t))
|
||||
|
||||
|
||||
@@ -9,10 +9,6 @@
|
||||
(defvar *heartbeat-thread* nil
|
||||
"Handle to the heartbeat thread.")
|
||||
|
||||
;; Alias: process-signal → loop-process (backward compatibility)
|
||||
(defun process-signal (signal)
|
||||
(loop-process signal))
|
||||
|
||||
(defun loop-process (signal)
|
||||
"The entry point to the Metabolic Pipeline: Perceive -> Reason -> Act."
|
||||
(let ((current-signal signal))
|
||||
@@ -49,6 +45,9 @@
|
||||
(list :type :EVENT :depth (1+ depth) :meta meta
|
||||
:payload (list :sensor :loop-error :message (format nil "~a" c) :depth depth)))))))))))
|
||||
|
||||
(defun process-signal (signal)
|
||||
(loop-process signal))
|
||||
|
||||
(defvar *memory-auto-save-interval* 300)
|
||||
|
||||
(defvar *heartbeat-save-counter* 0)
|
||||
@@ -69,8 +68,8 @@
|
||||
(when (>= *heartbeat-save-counter* (/ *memory-auto-save-interval* interval))
|
||||
(setf *heartbeat-save-counter* 0)
|
||||
(save-memory-to-disk))
|
||||
(inject-stimulus
|
||||
(list :type :EVENT :payload (list :sensor :heartbeat :unix-time (get-universal-time))))))
|
||||
(stimulus-inject
|
||||
(list :type :EVENT :payload (list :sensor :heartbeat :unix-time (get-universal-time))))))
|
||||
:name "passepartout-heartbeat"))))
|
||||
|
||||
(defvar *shutdown-save-enabled* t)
|
||||
|
||||
@@ -38,7 +38,7 @@ The 6-character hex length supports messages up to ~16MB (0xFFFFFF bytes). This
|
||||
|
||||
** Actuator Registry
|
||||
|
||||
The global registry mapping target keywords (~:cli~, ~:telegram~, ~:signal~, etc.) to their physical actuator functions. Extensible at runtime — skills can register new actuators via ~actuator-register~.
|
||||
The global registry mapping target keywords (~:cli~, ~:telegram~, ~:signal~, etc.) to their physical actuator functions. Extensible at runtime — skills can register new actuators via ~register-actuator~.
|
||||
|
||||
#+begin_src lisp
|
||||
(defvar *actuator-registry* (make-hash-table :test 'equalp)
|
||||
@@ -115,7 +115,7 @@ Reads a complete framed message from a TCP stream. Handles leading whitespace be
|
||||
|
||||
The TCP server that accepts connections from CLI and TUI clients. Each connection gets a dedicated thread (~client-handle-connection~).
|
||||
|
||||
The daemon sends a handshake message on connection, then enters a read loop, injecting each received message into the metabolic loop via ~inject-stimulus~. The ~:health-check~ message type is handled inline (not sent to the cognitive loop) so that health checks work even when the agent is busy.
|
||||
The daemon sends a handshake message on connection, then enters a read loop, injecting each received message into the metabolic loop via ~stimulus-inject~. The ~:health-check~ message type is handled inline (not sent to the cognitive loop) so that health checks work even when the agent is busy.
|
||||
|
||||
#+begin_src lisp
|
||||
(defvar *daemon-socket* nil)
|
||||
@@ -142,7 +142,7 @@ The daemon sends a handshake message on connection, then enters a read loop, inj
|
||||
nil))))
|
||||
(format stream "~a" (frame-message health-msg))
|
||||
(finish-output stream)))
|
||||
(t (inject-stimulus msg :stream stream))))))
|
||||
(t (stimulus-inject msg :stream stream))))))
|
||||
(error (c) (log-message "CLIENT ERROR: ~a" c)))
|
||||
(ignore-errors (usocket:socket-close socket))))
|
||||
|
||||
|
||||
@@ -193,12 +193,12 @@ The gate runs a last-mile deterministic check on the approved action before exec
|
||||
|
||||
After dispatch, the gate captures any feedback produced by the actuation (tool output, error events) and returns it to the loop for the next cognitive cycle.
|
||||
|
||||
*** loop-gate-act
|
||||
|
||||
The main act pipeline stage.
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
;; Alias: act-gate → loop-gate-act
|
||||
(defun act-gate (signal)
|
||||
(loop-gate-act signal))
|
||||
|
||||
(defun loop-gate-act (signal)
|
||||
"Final stage of the metabolic pipeline: Actuation.
|
||||
For approval-required actions, creates a Flight Plan instead of executing."
|
||||
@@ -255,6 +255,18 @@ For approval-required actions, creates a Flight Plan instead of executing."
|
||||
feedback))
|
||||
#+end_src
|
||||
|
||||
*** act-gate (backward-compatibility alias)
|
||||
|
||||
The pipeline gate was originally named ~act-gate~. Code that still
|
||||
uses the old name can call this alias. New code should call
|
||||
~loop-gate-act~.
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
(defun act-gate (signal)
|
||||
(loop-gate-act signal))
|
||||
#+end_src
|
||||
|
||||
* Test Suite
|
||||
Verifies that the act gate correctly processes an approved action and sets the signal status to ~:acted~.
|
||||
#+begin_src lisp :tangle ../lisp/core-loop-act.lisp
|
||||
|
||||
@@ -70,21 +70,34 @@ before the signal reaches the LLM. The handler receives the full signal
|
||||
and returns T if the signal was consumed (don't continue to reason)
|
||||
or nil if processing should proceed normally.
|
||||
|
||||
*** Pre-Reason Handler Hash Table
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
(defvar *pre-reason-handlers* (make-hash-table :test 'eq)
|
||||
"Pre-reason handler registry: sensor keyword → handler function.")
|
||||
#+end_src
|
||||
|
||||
*** register-pre-reason-handler
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
(defun register-pre-reason-handler (sensor fn)
|
||||
"Registers FN to handle signals with SENSOR in the perceive gate.
|
||||
FN receives (signal) and returns T if consumed, nil to continue."
|
||||
(setf (gethash sensor *pre-reason-handlers*) fn))
|
||||
|
||||
;; Alias for backward compatibility
|
||||
(defun inject-stimulus (raw-message &key stream (depth 0))
|
||||
"Alias for stimulus-inject."
|
||||
(stimulus-inject raw-message :stream stream :depth depth))
|
||||
#+end_src
|
||||
|
||||
** inject-stimulus backward-compatibility alias
|
||||
|
||||
Skills and external code that still call ~inject-stimulus~ (the previous
|
||||
name for the pipeline injection function) can use this alias. New code
|
||||
should call ~stimulus-inject~ directly.
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
(defun inject-stimulus (raw-message &key stream (depth 0))
|
||||
(stimulus-inject raw-message :stream stream :depth depth))
|
||||
#+end_src
|
||||
|
||||
** Stimulus Injection (stimulus-inject)
|
||||
@@ -139,12 +152,12 @@ The perceive gate is the first stage of the metabolic pipeline. It receives a no
|
||||
|
||||
All signals get tagged with their processing stage (`:status :perceived`) and the current foveal focus before being passed to the Reason stage.
|
||||
|
||||
*** loop-gate-perceive
|
||||
|
||||
The main perceive pipeline stage.
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
;; Alias: perceive-gate → loop-gate-perceive
|
||||
(defun perceive-gate (signal)
|
||||
(loop-gate-perceive signal))
|
||||
|
||||
(defun loop-gate-perceive (signal)
|
||||
"Stage 1 of the metabolic pipeline: Normalize sensory input."
|
||||
(let* ((payload (getf signal :payload))
|
||||
@@ -199,6 +212,18 @@ All signals get tagged with their processing stage (`:status :perceived`) and th
|
||||
signal))
|
||||
#+end_src
|
||||
|
||||
*** perceive-gate (backward-compatibility alias)
|
||||
|
||||
The pipeline gate was originally named ~perceive-gate~. Code that still
|
||||
uses the old name can call this alias. New code should call
|
||||
~loop-gate-perceive~.
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
(defun perceive-gate (signal)
|
||||
(loop-gate-perceive signal))
|
||||
#+end_src
|
||||
|
||||
* Test Suite
|
||||
Verifies that the perceive gate correctly ingests AST nodes into memory and that the depth limiter prevents runaway recursive signals.
|
||||
#+begin_src lisp :tangle ../lisp/core-loop-perceive.lisp
|
||||
|
||||
@@ -279,12 +279,10 @@ The loop has retry logic: up to 3 attempts. If the deterministic engine rejects
|
||||
|
||||
The retry limit prevents infinite loops. If the LLM cannot produce a passable proposal within 3 attempts, the last rejection reason is attached to the signal and the acted pipeline sees a failed reasoning cycle.
|
||||
|
||||
*** loop-gate-reason
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
;; Alias: reason-gate → loop-gate-reason
|
||||
(defun reason-gate (signal)
|
||||
(loop-gate-reason signal))
|
||||
|
||||
(defun loop-gate-reason (signal)
|
||||
(let* ((type (proto-get signal :type))
|
||||
(payload (proto-get signal :payload))
|
||||
@@ -323,6 +321,18 @@ The retry limit prevents infinite loops. If the LLM cannot produce a passable pr
|
||||
(return signal))))))))
|
||||
#+end_src
|
||||
|
||||
*** reason-gate (backward-compatibility alias)
|
||||
|
||||
The pipeline gate was originally named ~reason-gate~. Code that still
|
||||
uses the old name can call this alias. New code should call
|
||||
~loop-gate-reason~.
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
(defun reason-gate (signal)
|
||||
(loop-gate-reason signal))
|
||||
#+end_src
|
||||
|
||||
* Test Suite
|
||||
Verifies that the deterministic engine correctly rejects unsafe actions (like ~rm -rf /~) while allowing safe ones.
|
||||
#+begin_src lisp :tangle ../lisp/core-loop-reason.lisp
|
||||
|
||||
@@ -78,12 +78,12 @@ The function handles four failure modes:
|
||||
- High-depth errors (depth > 2) → dropped (avoids cascading failures)
|
||||
- **Unhandled error**: the handler-case catches everything, preventing any single bad signal from crashing the agent
|
||||
|
||||
*** loop-process
|
||||
|
||||
The main pipeline entry point.
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
;; Alias: process-signal → loop-process (backward compatibility)
|
||||
(defun process-signal (signal)
|
||||
(loop-process signal))
|
||||
|
||||
(defun loop-process (signal)
|
||||
"The entry point to the Metabolic Pipeline: Perceive -> Reason -> Act."
|
||||
(let ((current-signal signal))
|
||||
@@ -121,6 +121,18 @@ The function handles four failure modes:
|
||||
:payload (list :sensor :loop-error :message (format nil "~a" c) :depth depth)))))))))))
|
||||
#+end_src
|
||||
|
||||
*** process-signal (backward-compatibility alias)
|
||||
|
||||
The pipeline entry point was originally named ~process-signal~. Code
|
||||
that still uses the old name can call this alias. New code should call
|
||||
~loop-process~.
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
(defun process-signal (signal)
|
||||
(loop-process signal))
|
||||
#+end_src
|
||||
|
||||
** Heartbeat Mechanism
|
||||
|
||||
The heartbeat is a background thread that fires every N seconds (configurable via ~HEARTBEAT_INTERVAL~ env var, default 60). On each tick, it:
|
||||
@@ -159,8 +171,8 @@ The heartbeat signal is how background skills (Gardener, Scribe) get triggered w
|
||||
(when (>= *heartbeat-save-counter* (/ *memory-auto-save-interval* interval))
|
||||
(setf *heartbeat-save-counter* 0)
|
||||
(save-memory-to-disk))
|
||||
(inject-stimulus
|
||||
(list :type :EVENT :payload (list :sensor :heartbeat :unix-time (get-universal-time))))))
|
||||
(stimulus-inject
|
||||
(list :type :EVENT :payload (list :sensor :heartbeat :unix-time (get-universal-time))))))
|
||||
:name "passepartout-heartbeat"))))
|
||||
#+end_src
|
||||
#+end_src
|
||||
|
||||
@@ -33,6 +33,11 @@ Registration of available gateway implementations: each platform registers its p
|
||||
#+end_src
|
||||
|
||||
** Telegram Implementation
|
||||
|
||||
When a Telegram message arrives, the gateway first checks whether it is a
|
||||
HITL approval/denial command via ~hitl-handle-message~. If consumed,
|
||||
the message never enters the cognitive pipeline. Otherwise, it is injected
|
||||
as a normal ~:user-input~ event via ~stimulus-inject~.
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
(defun telegram-get-token ()
|
||||
@@ -94,6 +99,10 @@ Registration of available gateway implementations: each platform registers its p
|
||||
#+end_src
|
||||
|
||||
** Signal Implementation
|
||||
|
||||
Signal messages follow the same pattern as Telegram: ~hitl-handle-message~
|
||||
is called first, and only non-HITL messages are injected into the pipeline.
|
||||
|
||||
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
||||
#+begin_src lisp
|
||||
(defun signal-get-account ()
|
||||
|
||||
Reference in New Issue
Block a user