docs: Comprehensive documentation for core skills and README
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 3s
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 3s
- Policy skill: Add philosophical foundation, invariant priority explanations, code block documentation - Bouncer skill: Add security vector explanations, flight plan workflow, approval lifecycle - README: Add architecture diagrams (mermaid), design principles, roadmap details Each function now has detailed docstrings explaining: - What it does - Why it was designed that way - How it fits into the larger system
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
:PROPERTIES:
|
||||
:ID: bouncer-agent-skill
|
||||
:CREATED: [2026-04-11 Sat 15:20]
|
||||
:EDITED: [2026-04-13 Mon 18:35]
|
||||
:EDITED: [2026-04-22 Wed 16:00]
|
||||
:END:
|
||||
#+DEPENDS_ON: org-skill-credentials-vault
|
||||
#+TITLE: SKILL: Deterministic Engine Bouncer (Authorization Gate)
|
||||
@@ -9,149 +9,373 @@
|
||||
#+FILETAGS: :system:bouncer:authorization:autonomy:
|
||||
|
||||
* Overview
|
||||
The *Deterministic Engine Bouncer* is the authorization gate for high-risk actions. It serializes intercepted actions into Org nodes ("Flight Plans") and re-injects them once manually approved by the Autonomous.
|
||||
|
||||
The *Bouncer Skill* is the physical security layer of OpenCortex. While the Policy skill enforces constitutional invariants (transparency, autonomy, modularity), the Bouncer enforces operational security checks.
|
||||
|
||||
Think of Policy as the constitution and Bouncer as the bouncer at the door:
|
||||
- **Policy** asks: "Is this action aligned with our values?"
|
||||
- **Bouncer** asks: "Is this action safe to execute?"
|
||||
|
||||
** The Flight Plan Pattern
|
||||
|
||||
High-risk actions don't simply pass or fail—they can enter the "Flight Plan" approval workflow:
|
||||
|
||||
1. Bouncer intercepts a risky action
|
||||
2. Creates an Org node ("Flight Plan") describing the action
|
||||
3. User manually approves the flight plan in Emacs
|
||||
4. Bouncer detects approval on next heartbeat
|
||||
5. Action is re-injected with `approved = t` flag, bypassing the gate
|
||||
|
||||
This creates human-in-the-loop oversight for dangerous operations without blocking the system entirely.
|
||||
|
||||
** Why a Separate Skill?**
|
||||
|
||||
Security and policy are separated for clarity and auditability:
|
||||
- Policy decisions can be explained (they reference invariants)
|
||||
- Bouncer decisions are technical (they reference threat vectors)
|
||||
|
||||
When something is blocked, the logs clearly show which layer blocked it and why.
|
||||
|
||||
* Package Context
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
|
||||
(in-package :opencortex)
|
||||
#+end_src
|
||||
|
||||
* Deep Packet Inspection (DPI)
|
||||
The Bouncer ensures the action is "safe" by inspecting the payload content via Deep Packet Inspection.
|
||||
* Security Vectors
|
||||
|
||||
** Secret Exposure Check
|
||||
Retrieves all active secrets from the vault and scans the payload for potential leaks.
|
||||
The Bouncer implements the 5-Vector security model:
|
||||
|
||||
| Vector | Threat | Response |
|
||||
|--------|--------|----------|
|
||||
| Secret Exposure | API keys, passwords in output | Hard block |
|
||||
| Network Exfiltration | Data sent to unauthorized hosts | Approval required |
|
||||
| Shell Execution | Arbitrary command execution | Approval required |
|
||||
| File Modification | Writing/deleting files | Soft check |
|
||||
| Eval Execution | Arbitrary code evaluation | Approval required |
|
||||
|
||||
** Secret Exposure Detection
|
||||
|
||||
The vault stores sensitive credentials. This check scans action text for vault secrets to prevent accidental exposure.
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
|
||||
(defun bouncer-scan-secrets (text)
|
||||
"Returns the name of the secret found in TEXT, or NIL if clean."
|
||||
"Scans TEXT for known secrets from the vault.
|
||||
|
||||
RETURNS: The name of the matched secret, or NIL if text is clean.
|
||||
|
||||
This prevents the catastrophic failure mode where the agent
|
||||
accidentally echoes an API key in its response or log output.
|
||||
|
||||
The check uses substring matching (not regex) for reliability.
|
||||
Only secrets longer than 5 characters are checked to avoid
|
||||
false positives on common words."
|
||||
|
||||
(when (and text (stringp text))
|
||||
|
||||
(let ((found-secret nil))
|
||||
|
||||
(maphash (lambda (key val)
|
||||
;; Only check secrets of meaningful length
|
||||
(when (and val (stringp val) (> (length val) 5))
|
||||
;; Search for secret value in action text
|
||||
(when (search val text)
|
||||
(setf found-secret key))))
|
||||
|
||||
opencortex::*vault-memory*)
|
||||
|
||||
found-secret)))
|
||||
#+end_src
|
||||
|
||||
** Network Exfiltration Check
|
||||
Inspects shell commands for unwhitelisted domains or IP addresses.
|
||||
** Network Exfiltration Detection
|
||||
|
||||
Detects when shell commands try to send data to untrusted network destinations.
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
|
||||
(defvar *bouncer-network-whitelist*
|
||||
'("api.telegram.org" "matrix.org" "googleapis.com" "openai.com" "anthropic.com")
|
||||
"Domains that the Bouncer considers safe for outbound connections.
|
||||
|
||||
This whitelist should be minimal—only services explicitly configured
|
||||
as gateways. All other outbound connections require approval.")
|
||||
|
||||
(defun bouncer-check-network-exfil (cmd)
|
||||
"Returns T if the command appears to target an unwhitelisted external host."
|
||||
"Detects if CMD attempts to contact an unwhitelisted external host.
|
||||
|
||||
Returns T if the command targets an unknown external host.
|
||||
Returns NIL if the command is clean or only contacts whitelisted hosts.
|
||||
|
||||
The check looks for HTTP/HTTPS/FTP URLs and extracts the domain.
|
||||
If the domain isn't in *bouncer-network-whitelist*, it's flagged."
|
||||
|
||||
(when (and cmd (stringp cmd))
|
||||
;; Basic check for common data exfiltration tools being used with IPs/URLs
|
||||
(let ((network-whitelist '("api.telegram.org" "matrix.org" "googleapis.com" "openai.com" "anthropic.com")))
|
||||
(when (cl-ppcre:scan "(http|https|ftp)://([\\w\\.-]+)" cmd)
|
||||
(multiple-value-bind (match regs)
|
||||
(cl-ppcre:scan-to-strings "(http|https|ftp)://([\\w\\.-]+)" cmd)
|
||||
(declare (ignore match))
|
||||
(let ((domain (aref regs 1)))
|
||||
(not (some (lambda (safe) (search safe domain)) network-whitelist))))))))
|
||||
|
||||
;; Look for URL patterns in the command
|
||||
(when (cl-ppcre:scan "(http|https|ftp)://([\\w\\.-]+)" cmd)
|
||||
|
||||
(multiple-value-bind (match regs)
|
||||
(cl-ppcre:scan-to-strings "(http|https|ftp)://([\\w\\.-]+)" cmd)
|
||||
|
||||
(declare (ignore match))
|
||||
|
||||
(let ((domain (aref regs 1)))
|
||||
|
||||
;; Check if domain is whitelisted
|
||||
(not (some (lambda (safe) (search safe domain))
|
||||
*bouncer-network-whitelist*)))))))
|
||||
#+end_src
|
||||
|
||||
* Runtime Guard (bouncer-check)
|
||||
The primary entry point for all high-impact actions. It blocks or queues actions based on risk vectors.
|
||||
* Runtime Guard
|
||||
|
||||
** bouncer-check: Main Security Gate
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
|
||||
(defun bouncer-check (action context)
|
||||
"The 5-Vector security gate. Blocks or queues actions based on risk."
|
||||
"The 5-Vector security gate for high-risk actions.
|
||||
|
||||
Evaluates an action against all security vectors and either:
|
||||
- Returns the action unchanged (pass)
|
||||
- Returns a blocking LOG event (hard block)
|
||||
- Returns an approval-required EVENT (soft block)
|
||||
|
||||
Vector evaluation order:
|
||||
1. Already approved actions pass immediately
|
||||
2. Secret exposure → hard block
|
||||
3. Network exfiltration → approval required
|
||||
4. High-impact targets → approval required
|
||||
|
||||
The context parameter is not used directly but provided for
|
||||
consistency with the skill gate signature."
|
||||
|
||||
(declare (ignore context))
|
||||
|
||||
(let* ((target (getf action :target))
|
||||
(payload (getf action :payload))
|
||||
(text (or (getf payload :text) (getf action :text)))
|
||||
;; Extract cmd from direct shell or tool-mediated shell call
|
||||
(cmd (or (getf payload :cmd)
|
||||
(when (and (eq target :tool) (equal (getf payload :tool) "shell"))
|
||||
(getf (getf payload :args) :cmd))))
|
||||
(when (and (eq target :tool)
|
||||
(equal (getf payload :tool) "shell"))
|
||||
(getf (getf payload :args) :cmd))))
|
||||
(approved (getf action :approved)))
|
||||
|
||||
(cond
|
||||
;; 0. Bypass for already approved actions
|
||||
(approved action)
|
||||
|
||||
;; 1. Secret Exposure Vector (Hard Block)
|
||||
(cond
|
||||
|
||||
;; Vector 0: Already approved actions pass through
|
||||
(approved
|
||||
action)
|
||||
|
||||
;; Vector 1: Secret Exposure (Hard Block)
|
||||
;; If any vault secret is found in the action text, block immediately
|
||||
((and text (bouncer-scan-secrets text))
|
||||
(let ((secret-name (bouncer-scan-secrets text)))
|
||||
(harness-log "SECURITY VIOLATION: Blocked leak of secret ~a" secret-name)
|
||||
`(:type :log :payload (:level :error :text ,(format nil "Action blocked: Potential exposure of ~a" secret-name)))))
|
||||
(harness-log "SECURITY VIOLATION: Blocked potential leak of secret '~a'" secret-name)
|
||||
(list :type :LOG
|
||||
:payload (list :level :error
|
||||
:text (format nil "Action blocked: Potential exposure of '~a'" secret-name)))))
|
||||
|
||||
;; 2. Network Exfiltration Vector (Authorization Required)
|
||||
((and (or (eq target :shell)
|
||||
(and (eq target :tool) (equal (getf payload :tool) "shell")))
|
||||
;; Vector 2: Network Exfiltration (Soft Block)
|
||||
;; Shell commands targeting unknown hosts require approval
|
||||
((and (or (eq target :shell)
|
||||
(and (eq target :tool)
|
||||
(equal (getf payload :tool) "shell")))
|
||||
(bouncer-check-network-exfil cmd))
|
||||
|
||||
(harness-log "SECURITY WARNING: External network call detected. Queuing for approval.")
|
||||
`(:type :EVENT :payload (:sensor :approval-required :action ,action)))
|
||||
|
||||
;; 3. High-Impact Target Vector (Authorization Required)
|
||||
(list :type :EVENT
|
||||
:payload (list :sensor :approval-required
|
||||
:action action)))
|
||||
|
||||
;; Vector 3: High-Impact Targets (Soft Block)
|
||||
;; Shell execution, file repair, and eval require approval
|
||||
((or (member target '(:shell))
|
||||
(and (eq target :tool) (member (getf payload :tool) '("shell" "repair-file") :test #'string=))
|
||||
(and (eq target :EMACS) (eq (getf payload :action) :eval)))
|
||||
(harness-log "SECURITY: High-impact action ~a requires approval." (or (getf payload :tool) target))
|
||||
`(:type :EVENT :payload (:sensor :approval-required :action ,action)))
|
||||
(and (eq target :tool)
|
||||
(member (getf payload :tool) '("shell" "repair-file") :test #'string=))
|
||||
(and (eq target :emacs)
|
||||
(eq (getf payload :action) :eval)))
|
||||
|
||||
;; 4. Default Pass
|
||||
(t action))))
|
||||
(harness-log "SECURITY: High-impact action requires approval: ~a"
|
||||
(or (getf payload :tool) target))
|
||||
|
||||
(list :type :EVENT
|
||||
:payload (list :sensor :approval-required
|
||||
:action action)))
|
||||
|
||||
;; Vector 4: Default pass
|
||||
(t
|
||||
action))))
|
||||
#+end_src
|
||||
|
||||
* Approval Processing
|
||||
The Bouncer periodically scans the Memex for approved "Flight Plans" and re-injects them into the metabolic loop.
|
||||
* Flight Plan Workflow
|
||||
|
||||
** Processing Approvals
|
||||
|
||||
When a flight plan is approved in Emacs, the Bouncer detects it and re-injects the action.
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
|
||||
(defun bouncer-process-approvals ()
|
||||
"Scans the object store for APPROVED flight plans and re-injects their actions."
|
||||
"Scans the object store for APPROVED flight plans and re-injects them.
|
||||
|
||||
This function is called on every heartbeat, allowing the agent to
|
||||
check for approvals without blocking the main signal pipeline.
|
||||
|
||||
Flight Plan format:
|
||||
- Has TAGS including \"FLIGHT_PLAN\"
|
||||
- Has TODO set to \"APPROVED\"
|
||||
- Has ACTION containing the serialized action plist
|
||||
|
||||
When an approved flight plan is found:
|
||||
1. Deserialize the action from the ACTION attribute
|
||||
2. Mark the action as :approved = t (bypasses security gate)
|
||||
3. Re-inject into the signal pipeline
|
||||
4. Mark the flight plan as DONE
|
||||
|
||||
Returns T if any flight plans were processed."
|
||||
|
||||
(let ((approved-nodes (list-objects-with-attribute :TODO "APPROVED"))
|
||||
(found-any nil))
|
||||
|
||||
(dolist (node approved-nodes)
|
||||
|
||||
(let* ((tags (getf (org-object-attributes node) :TAGS))
|
||||
(action-str (getf (org-object-attributes node) :ACTION)))
|
||||
(when (and (member "FLIGHT_PLAN" tags :test #'string-equal) action-str)
|
||||
(harness-log "BOUNCER: Found approved flight plan ~a. Re-injecting..." (org-object-id node))
|
||||
|
||||
;; Only process flight plans (not other APPROVED items)
|
||||
(when (and (member "FLIGHT_PLAN" tags :test #'string-equal)
|
||||
action-str)
|
||||
|
||||
(harness-log "BOUNCER: Found approved flight plan '~a'. Re-injecting..."
|
||||
(org-object-id node))
|
||||
|
||||
(let ((action (ignore-errors (read-from-string action-str))))
|
||||
(when action
|
||||
;; Mark as approved to bypass the gate
|
||||
|
||||
;; Mark as approved to bypass the security gate on re-injection
|
||||
(setf (getf action :approved) t)
|
||||
|
||||
;; Re-inject the action into the signal pipeline
|
||||
(inject-stimulus action)
|
||||
;; Mark as DONE
|
||||
|
||||
;; Mark the flight plan as done
|
||||
(setf (getf (org-object-attributes node) :TODO) "DONE")
|
||||
|
||||
(setq found-any t))))))
|
||||
|
||||
found-any))
|
||||
#+end_src
|
||||
|
||||
* Skill Definition
|
||||
The Bouncer skill reacts to approval requirements by creating flight plan nodes, and periodically checks for manual approvals via heartbeats.
|
||||
** Creating Flight Plans
|
||||
|
||||
When the Bouncer intercepts a high-risk action, it creates a flight plan node for manual approval.
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
|
||||
(defun bouncer-create-flight-plan (blocked-action)
|
||||
"Creates an Org node representing a pending flight plan for manual approval.
|
||||
|
||||
BLOCKED-ACTION is the action plist that was intercepted.
|
||||
|
||||
The flight plan node contains:
|
||||
- A title describing the action
|
||||
- TODO set to PLAN (awaiting approval)
|
||||
- TAGS including FLIGHT_PLAN
|
||||
- ACTION attribute containing the serialized action
|
||||
|
||||
The user reviews the flight plan and changes TODO to APPROVED.
|
||||
On the next heartbeat, bouncer-process-approvals will detect
|
||||
the approval and re-inject the action.
|
||||
|
||||
Returns the generated org-id for the flight plan."
|
||||
|
||||
(let ((id (org-id-new)))
|
||||
(harness-log "BOUNCER: Creating flight plan node '~a'..." id)
|
||||
|
||||
;; Inject a node creation request
|
||||
(list :type :REQUEST
|
||||
:target :emacs
|
||||
:payload (list :action :insert-node
|
||||
:id id
|
||||
:attributes (list
|
||||
:TITLE "Flight Plan: High-Risk Action"
|
||||
:TODO "PLAN"
|
||||
:TAGS '("FLIGHT_PLAN")
|
||||
:ACTION (format nil "~s" blocked-action)))))
|
||||
#+end_src
|
||||
|
||||
* Skill Gate
|
||||
|
||||
** Main Gate Function
|
||||
|
||||
** Skill Logic
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
|
||||
(defun bouncer-deterministic-gate (action context)
|
||||
"Main gate for the bouncer skill."
|
||||
"Main deterministic gate for the Bouncer skill.
|
||||
|
||||
Handles three types of signals:
|
||||
1. :approval-required - Create a flight plan for the blocked action
|
||||
2. :heartbeat - Process any pending approvals
|
||||
3. otherwise - Run security check on the action
|
||||
|
||||
The trigger is always true (bouncer evaluates all actions)
|
||||
because security cannot be selective."
|
||||
|
||||
(let* ((payload (getf context :payload))
|
||||
(sensor (getf payload :sensor)))
|
||||
|
||||
(case sensor
|
||||
|
||||
;; Signal type 1: Action was blocked, create flight plan
|
||||
(:approval-required
|
||||
(let* ((blocked-action (getf payload :action))
|
||||
(id (org-id-new)))
|
||||
(harness-log "BOUNCER: Creating flight plan node...")
|
||||
;; Create the node in Emacs (or inbox)
|
||||
(list :type :REQUEST :target :EMACS :action :insert-node
|
||||
:id id :attributes `(:TITLE "Flight Plan: High-Risk Action"
|
||||
:TODO "PLAN"
|
||||
:TAGS ("FLIGHT_PLAN")
|
||||
:ACTION ,(format nil "~s" blocked-action)))))
|
||||
(let* ((blocked-action (getf payload :action)))
|
||||
(bouncer-create-flight-plan blocked-action)))
|
||||
|
||||
;; Signal type 2: Heartbeat, check for approvals
|
||||
(:heartbeat
|
||||
;; Periodically check for approvals
|
||||
(bouncer-process-approvals)
|
||||
(if action (bouncer-check action context) action))
|
||||
;; After processing approvals, still run the security check
|
||||
(if action
|
||||
(bouncer-check action context)
|
||||
action))
|
||||
|
||||
;; Signal type 3: Normal action, run security check
|
||||
(otherwise
|
||||
(if action (bouncer-check action context) action)))))
|
||||
(if action
|
||||
(bouncer-check action context)
|
||||
action)))))
|
||||
#+end_src
|
||||
|
||||
** Skill Registration
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
|
||||
(defskill :skill-bouncer
|
||||
:priority 150
|
||||
:trigger (lambda (ctx) t) ;; Bouncer evaluates all actions deterministically
|
||||
:trigger (lambda (ctx) (declare (ignore ctx)) t)
|
||||
:probabilistic nil
|
||||
:deterministic #'bouncer-deterministic-gate)
|
||||
#+end_src
|
||||
|
||||
* Quick Reference
|
||||
|
||||
** Security Vectors Summary
|
||||
|
||||
| Vector | Check | Response |
|
||||
|--------|-------|----------|
|
||||
| Secret Exposure | `bouncer-scan-secrets` | Hard block |
|
||||
| Network Exfil | `bouncer-check-network-exfil` | Approval required |
|
||||
| Shell Execution | target = :shell or tool = "shell" | Approval required |
|
||||
| Eval Execution | target = :emacs and action = :eval | Approval required |
|
||||
| File Repair | tool = "repair-file" | Approval required |
|
||||
|
||||
** Flight Plan Lifecycle
|
||||
|
||||
1. High-risk action intercepted → `:approval-required` signal
|
||||
2. Flight plan node created in Emacs with `TODO: PLAN`
|
||||
3. User reviews and sets `TODO: APPROVED`
|
||||
4. Next heartbeat detects approval
|
||||
5. Action re-injected with `approved = t`
|
||||
6. Security gate bypassed, action executes
|
||||
7. Flight plan marked `TODO: DONE`
|
||||
|
||||
* See Also
|
||||
- [[file:org-skill-credentials-vault.org][Credentials Vault]] - Where secrets are stored
|
||||
- [[file:org-skill-policy.org][Policy Skill]] - Constitutional constraints
|
||||
- [[file:../harness/act.org][Act Stage]] - Where gates are invoked
|
||||
@@ -1,33 +1,65 @@
|
||||
:PROPERTIES:
|
||||
:ID: 47425a43-2be0-423c-8509-22592cfe9c9e
|
||||
:CREATED: [2026-04-07 Tue 12:57]
|
||||
:EDITED: [2026-04-22 Wed 11:45]
|
||||
:EDITED: [2026-04-22 Wed 16:00]
|
||||
:END:
|
||||
#+TITLE: SKILL: System Policy
|
||||
#+STARTUP: content
|
||||
#+FILETAGS: :platform:policy:alignment:autonomy:
|
||||
|
||||
* Overview
|
||||
The *opencortex* is a probabilistic-deterministic harness for a personal operating system. It uses Org-mode as its native memory and Common Lisp as its deterministic reasoning engine.
|
||||
|
||||
This skill defines the *Core System Policy*: a set of non-negotiable philosophical and technical constraints that every agentic action MUST satisfy. Unlike a passive manifesto, these invariants are enforced by the Deterministic Engine at the last mile before actuation.
|
||||
The *Policy Skill* is the constitutional law of OpenCortex. It defines the non-negotiable constraints that every agentic action must satisfy before reaching the actuator layer.
|
||||
|
||||
Unlike a passive manifesto, Policy is *enforced* by the Deterministic Engine. The LLM proposes; Policy verifies. If an action violates an invariant, Policy blocks it and returns an auditable explanation.
|
||||
|
||||
** Why a Constitutional Approach?**
|
||||
|
||||
AIs fail in two ways:
|
||||
1. *Underconstraint* - They do harmful things because no one told them not to
|
||||
2. *Overconstraint* - They refuse to act because every action triggers a warning
|
||||
|
||||
OpenCortex solves this with a *hierarchy of invariants*:
|
||||
- Some invariants block absolutely (Transparency, Modularity)
|
||||
- Others warn but don't block (Autonomy debt, Sustainability debt)
|
||||
|
||||
This allows the agent to be both *safe* and *usable*.
|
||||
|
||||
** The Philosophical Foundation
|
||||
|
||||
OpenCortex is not just software—it's a *personal operating system* designed for the 100-year horizon. The Memex must outlive:
|
||||
- Cloud services that get discontinued
|
||||
- Programming languages that fall out of fashion
|
||||
- Hardware platforms that become obsolete
|
||||
|
||||
Therefore, Policy encodes not just rules, but *values*:
|
||||
- Radical Transparency → Auditability is non-negotiable
|
||||
- Autonomy → Dependency on proprietary systems is debt, not strength
|
||||
- Zero-Bloat → Complexity is cost, not feature
|
||||
- Modularity → The kernel must survive even if all skills fail
|
||||
- Mentorship → Teaching is the highest form of assistance
|
||||
- Sustainability → Offline capability is a feature, not a limitation
|
||||
|
||||
* Package Context
|
||||
Every skill executes within its own jailed package namespace, while inheriting core harness symbols.
|
||||
|
||||
Every skill executes within its own jailed package namespace, inheriting core harness symbols while maintaining isolation from other skills.
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(in-package :opencortex)
|
||||
#+end_src
|
||||
|
||||
* The Override Hierarchy
|
||||
|
||||
When two invariants conflict, resolution follows a strict priority order. This prevents the agent from freezing on ethical edge cases.
|
||||
|
||||
1. *Radical Transparency* — An action that cannot be explained to the user is never permissible, even if it is technically optimal.
|
||||
2. *Autonomy* — Independence from proprietary control is the primary goal, but it must be achieved transparently.
|
||||
3. *Zero-Bloat* — Complexity must be justified, but a transparent, autonomous system may still be complex if the complexity is locally justified.
|
||||
4. *Modularity* — The system's kernel must remain minimal; complexity must live at the edges, not in the core. This takes precedence over mentorship when the proposed change would fatten the harness.
|
||||
5. *Mentorship* — The agent must teach, but teaching is secondary to delivering a working, transparent system.
|
||||
6. *Long-Term Sustainability* — Energy efficiency and offline capability are desired properties, not absolute blockers.
|
||||
| Priority | Invariant | Philosophy |
|
||||
|----------|-----------|------------|
|
||||
| 500 | Transparency | If you can't explain it, you can't do it |
|
||||
| 400 | Autonomy | Independence from proprietary control is the primary goal |
|
||||
| 300 | Zero-Bloat | Complexity must be earned, not imported |
|
||||
| 250 | Modularity | Complexity belongs at the edges, not the core |
|
||||
| 200 | Mentorship | Teaching increases capability; doing removes it |
|
||||
| 100 | Sustainability | Offline capability today enables 100-year survival |
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defvar *policy-invariant-priorities*
|
||||
@@ -38,29 +70,55 @@ When two invariants conflict, resolution follows a strict priority order. This p
|
||||
(:mentorship . 200)
|
||||
(:sustainability . 100))
|
||||
"Priority alist for policy invariant conflict resolution.
|
||||
Higher numbers take precedence.")
|
||||
Higher numbers take precedence.
|
||||
|
||||
When two invariants conflict, the higher priority wins.
|
||||
Example: Modularity (250) takes precedence over Mentorship (200),
|
||||
meaning a change that would fatten the harness is blocked
|
||||
even if it would be educational.")
|
||||
#+end_src
|
||||
|
||||
* The Core Invariants
|
||||
|
||||
** 1. Radical Transparency
|
||||
The agent's "Thought Stream" must be fully auditable. Hidden reasoning or obfuscated logic is a violation of the system's design principles. At the action gate, this means every action directed at the user MUST carry an explanation, and every action MUST be a valid, inspectable data structure.
|
||||
|
||||
*The maxim: "If you can't explain it, you can't do it."*
|
||||
|
||||
The agent's Thought Stream must be fully auditable. Hidden reasoning or obfuscated logic violates the system's core purpose: a transparent, comprehensible AI assistant.
|
||||
|
||||
At the gate:
|
||||
- Every action must be a valid, inspectable data structure
|
||||
- Every user-facing action must carry an `:explanation`
|
||||
- Log messages must include the triggering invariant
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defun policy-check-transparency (action context)
|
||||
"Ensures the action is inspectable and user-facing actions carry an explanation.
|
||||
Returns the action if clean, or a blocking LOG event if the action is opaque."
|
||||
|
||||
TRANSPARENCY CHECK:
|
||||
1. Action must be a valid plist (not opaque data)
|
||||
2. User-facing actions (:cli, :tui, :emacs) must include :explanation
|
||||
3. Heartbeat and handshake messages are exempt (they're system status)
|
||||
|
||||
Returns the action if clean, or a blocking LOG event if violated."
|
||||
|
||||
(declare (ignore context))
|
||||
|
||||
;; Check 1: Action must be a valid plist
|
||||
(unless (listp action)
|
||||
(return-from policy-check-transparency
|
||||
(list :type :LOG
|
||||
:payload (list :level :error
|
||||
:text "POLICY [Transparency]: Action is not a valid plist. Rejected."))))
|
||||
|
||||
(let* ((payload (getf action :payload))
|
||||
(target (or (getf action :target) (getf action :TARGET)))
|
||||
(explanation (or (getf payload :explanation) (getf payload :EXPLANATION)
|
||||
(getf payload :rationale) (getf payload :RATIONALE))))
|
||||
;; User-facing actions (CLI, TUI, Emacs) must explain themselves
|
||||
(explanation (or (getf payload :explanation)
|
||||
(getf payload :EXPLANATION)
|
||||
(getf payload :rationale)
|
||||
(getf payload :RATIONALE))))
|
||||
|
||||
;; Check 2: User-facing actions require explanation
|
||||
(when (and (member target '(:cli :tui :emacs :EMACS :CLI :TUI))
|
||||
(not explanation)
|
||||
(not (member (getf payload :action)
|
||||
@@ -68,235 +126,427 @@ Returns the action if clean, or a blocking LOG event if the action is opaque."
|
||||
(return-from policy-check-transparency
|
||||
(list :type :LOG
|
||||
:payload (list :level :error
|
||||
:text "POLICY [Transparency]: User-facing action missing :explanation. Blocked."))))
|
||||
action))
|
||||
:text "POLICY [Transparency]: User-facing action missing :explanation. Blocked.")))))
|
||||
|
||||
action)
|
||||
#+end_src
|
||||
|
||||
** 2. Autonomy Above All
|
||||
Every action must increase the user's independence from centralized, proprietary platforms. If a tool or library introduces a dependency on a non-autonomous entity, it must be flagged for replacement. The gate scans shell commands and tool payloads for known proprietary domains and logs a warning. It does NOT block by default, because the system itself uses gateway bridges (e.g., Telegram, Signal) as tactical concessions toward strategic autonomy.
|
||||
|
||||
*The maxim: "Every dependency is debt."*
|
||||
|
||||
Every action should increase the user's independence from centralized, proprietary platforms. When the system uses a proprietary API, it's logged as "autonomy debt"—acceptable tactically, but flagged for eventual replacement.
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defvar *proprietary-domain-watchlist*
|
||||
'("googleapis.com" "api.openai.com" "anthropic.com" "api.groq.com" "openrouter.ai")
|
||||
"Domains that represent centralized, proprietary control.
|
||||
Actions targeting these are logged as autonomy debt, not hard-blocked,
|
||||
because tactical gateway usage is permitted under the strategic mandate.")
|
||||
"Domains representing centralized, proprietary control.
|
||||
|
||||
Actions targeting these are logged as autonomy debt, not hard-blocked.
|
||||
This is because tactical gateway usage (Telegram, Signal, OpenRouter)
|
||||
is permitted under the strategic mandate for autonomy.
|
||||
|
||||
Strategic goal: Replace all proprietary APIs with local alternatives.
|
||||
Tactical reality: Use what's available while building toward that goal.")
|
||||
|
||||
(defun policy-scan-proprietary-references (action)
|
||||
"Scans ACTION text fields for proprietary domain references.
|
||||
Returns the first matched domain, or NIL if clean."
|
||||
|
||||
Searches in:
|
||||
- :text and :TEXT in payload
|
||||
- :cmd and :CMD in payload
|
||||
- :cmd in args (for shell tool calls)
|
||||
|
||||
Returns the first matched domain, or NIL if clean."
|
||||
|
||||
(let* ((payload (getf action :payload))
|
||||
(text (or (getf payload :text) (getf payload :TEXT) ""))
|
||||
(cmd (or (getf payload :cmd) (getf payload :CMD)
|
||||
(when (equal (getf payload :tool) "shell")
|
||||
(getf (getf payload :args) :cmd))
|
||||
""))
|
||||
(cmd (or (getf payload :cmd)
|
||||
(getf payload :CMD)
|
||||
(when (equal (getf payload :tool) "shell")
|
||||
(getf (getf payload :args) :cmd))
|
||||
""))
|
||||
(haystack (concatenate 'string text cmd)))
|
||||
|
||||
(dolist (domain *proprietary-domain-watchlist* nil)
|
||||
(when (search domain haystack)
|
||||
(return domain)))))
|
||||
|
||||
(defun policy-check-autonomy (action context)
|
||||
"Flags actions that reference proprietary domains. Returns the action
|
||||
with an autonomy debt log appended, or the action itself if clean."
|
||||
"Flags actions that reference proprietary domains.
|
||||
|
||||
Does NOT block the action—this is a warning, not a veto.
|
||||
The agent can use proprietary services tactically, but must
|
||||
be aware that each usage is a step away from full autonomy.
|
||||
|
||||
Returns a warning LOG if proprietary reference detected,
|
||||
or the original action if clean."
|
||||
|
||||
(declare (ignore context))
|
||||
|
||||
(let ((domain (policy-scan-proprietary-references action)))
|
||||
|
||||
(if domain
|
||||
(progn
|
||||
(harness-log "POLICY [Autonomy]: Detected proprietary reference '~a'. Flagged for replacement." domain)
|
||||
;; Return a side-effect log but DO NOT block the action
|
||||
;; Return a warning log but DO NOT block the action
|
||||
(list :type :LOG
|
||||
:payload (list :level :warn
|
||||
:text (format nil "Autonomy Debt: Action references proprietary domain '~a'. Consider a local alternative." domain)
|
||||
:original-action action)))
|
||||
action)))
|
||||
|
||||
action))
|
||||
#+end_src
|
||||
|
||||
** 3. Zero-Bloat Mandate
|
||||
The system harness must remain minimalist. "Just-in-case" code is a security vulnerability. Complexity must be earned, not imported. This invariant is enforced primarily at skill-load time (see `validate-lisp-syntax` and skill telemetry). At the action gate, it performs a lightweight size check on proposed `:create-skill` actions and warns if the payload exceeds a reasonable threshold.
|
||||
|
||||
*The maxim: "Complexity is cost, not feature."*
|
||||
|
||||
The system harness must remain minimalist. "Just-in-case" code is a security vulnerability. Complexity must be earned through demonstrated need, not anticipation of future use.
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defvar *policy-max-skill-size-chars* 50000
|
||||
"Maximum recommended size for a skill file tangled from an Org note.")
|
||||
"Maximum recommended size for a skill file tangled from an Org note.
|
||||
|
||||
This is a soft limit—the check warns but does not block.
|
||||
A large, well-documented skill is acceptable; a small, poorly-documented
|
||||
one that adds unnecessary complexity is not.")
|
||||
|
||||
(defun policy-check-bloat (action context)
|
||||
"Warns if a :create-skill action exceeds the bloat threshold.
|
||||
Does not block, because size alone is not a proof of complexity."
|
||||
|
||||
Size alone is not proof of complexity—a 50KB skill that's well-designed
|
||||
is better than a 5KB skill that's spaghetti. This check flags for review,
|
||||
not automatic rejection.
|
||||
|
||||
Returns a warning LOG if threshold exceeded, or original action if clean."
|
||||
|
||||
(declare (ignore context))
|
||||
|
||||
(let* ((payload (getf action :payload))
|
||||
(act (getf payload :action))
|
||||
(content (getf payload :content)))
|
||||
|
||||
(when (and (eq act :create-skill)
|
||||
(stringp content)
|
||||
(> (length content) *policy-max-skill-size-chars*))
|
||||
|
||||
(harness-log "POLICY [Bloat]: Proposed skill is ~a chars. Exceeds ~a char threshold."
|
||||
(length content) *policy-max-skill-size-chars*)
|
||||
|
||||
(return-from policy-check-bloat
|
||||
(list :type :LOG
|
||||
:payload (list :level :warn
|
||||
:text (format nil "Bloat Warning: Proposed skill (~a chars) exceeds ~a char threshold. Review for earned complexity."
|
||||
(length content) *policy-max-skill-size-chars*)
|
||||
(length content) *policy-max-skill-size-chars*)
|
||||
:original-action action))))
|
||||
action))
|
||||
|
||||
action)
|
||||
#+end_src
|
||||
|
||||
** 4. Technical Mastery & Mentorship
|
||||
The agent's goal is not to "do it for the user," but to "empower the user." Every autonomous action must be explained at a level that increases the user's technical understanding of the Lisp Machine. At the gate, this means that any action which performs a non-trivial side-effect (file write, shell execution, skill reload) MUST include a `:mentorship-note` explaining *what* was done and *why*.
|
||||
** 4. Modularity
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defvar *mentorship-required-actions*
|
||||
'(:create-skill :eval :modify-file :write-file :replace :rename-file :delete-file :shell :create-note)
|
||||
"Actions that trigger the Mentorship invariant.")
|
||||
*The maxim: "The kernel must survive even if all skills fail."*
|
||||
|
||||
(defun policy-check-mentorship (action context)
|
||||
"Blocks high-impact actions that lack a mentorship note."
|
||||
(declare (ignore context))
|
||||
(let* ((payload (getf action :payload))
|
||||
(act (or (getf payload :action) (getf action :action)))
|
||||
(note (or (getf payload :mentorship-note) (getf payload :MENTORSHIP-NOTE)))
|
||||
(target (or (getf action :target) (getf action :TARGET)))
|
||||
(tool (when (eq target :tool) (getf payload :tool))))
|
||||
(when (or (member act *mentorship-required-actions*)
|
||||
(member tool '("shell" "eval" "repair-file")))
|
||||
(unless note
|
||||
(return-from policy-check-mentorship
|
||||
(list :type :LOG
|
||||
:payload (list :level :error
|
||||
:text "POLICY [Mentorship]: High-impact action missing :mentorship-note. Explain what you are doing and why. Blocked.")))))
|
||||
action))
|
||||
#+end_src
|
||||
Every system should be decomposed into a minimal, unbreakable core and hot-swappable capabilities. Complexity must live at the edges, never in the kernel.
|
||||
|
||||
** 5. Long-Term Sustainability
|
||||
Prioritize local, energy-efficient, and offline-first architectures. The "Memex" should be functional on a 100-year horizon. At the gate, this means we log a sustainability debt event whenever the probabilistic engine falls back to a remote cloud provider because a local model (e.g., Ollama) is unavailable.
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defvar *cloud-only-backends* '(:openrouter :openai :anthropic :groq :gemini-api)
|
||||
"Backends that require an internet connection and external infrastructure.")
|
||||
|
||||
(defun policy-check-sustainability (action context)
|
||||
"Logs sustainability debt when the action relies on cloud-only infrastructure.
|
||||
Does not block, because tactical cloud usage is permitted."
|
||||
(let* ((payload (getf context :payload))
|
||||
(backend (getf payload :backend))
|
||||
(provider (getf payload :provider)))
|
||||
(when (or (member backend *cloud-only-backends*)
|
||||
(member provider *cloud-only-backends*))
|
||||
(harness-log "POLICY [Sustainability]: Cloud provider '~a' used. Logged as sustainability debt."
|
||||
(or backend provider))
|
||||
(return-from policy-check-sustainability
|
||||
(list :type :LOG
|
||||
:payload (list :level :warn
|
||||
:text (format nil "Sustainability Debt: Reliance on cloud provider '~a'. Consider Ollama or local inference."
|
||||
(or backend provider))))))
|
||||
action))
|
||||
#+end_src
|
||||
|
||||
** 6. Modularity
|
||||
Every system should be decomposed into a minimal, unbreakable core and hot-swappable capabilities. Complexity must live at the edges, never in the kernel. At the gate, this means any proposed modification to the protected core must carry a `:modularity-justification` explaining why the change cannot be implemented as a skill.
|
||||
This is the most important invariant for system stability. If the harness grows fat, it becomes:
|
||||
- Harder to verify for security
|
||||
- Harder to debug when things go wrong
|
||||
- Harder to maintain across versions
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defvar *modularity-protected-paths*
|
||||
'("harness/" "opencortex.asd")
|
||||
"Paths that constitute the unbreakable core of the system.
|
||||
Any action targeting these paths must include a :modularity-justification.
|
||||
This list is project-specific and should be configured at boot time.")
|
||||
|
||||
Any action targeting these paths must include a :modularity-justification
|
||||
explaining why the change cannot be implemented as a skill.
|
||||
|
||||
The Thin Harness principle: What belongs in the harness?
|
||||
- Core signal processing (Perceive-Reason-Act loop)
|
||||
- Memory and persistence primitives
|
||||
- Protocol definition and validation
|
||||
- Skills register and dispatch
|
||||
|
||||
What belongs in skills?
|
||||
- Policy and security
|
||||
- LLM integration
|
||||
- Domain-specific functionality
|
||||
- New actuators")
|
||||
|
||||
(defun policy-check-modularity (action context)
|
||||
"Blocks modifications to the system's protected core unless justified."
|
||||
"Blocks modifications to the system's protected core unless justified.
|
||||
|
||||
MODULARITY CHECK:
|
||||
1. If the action targets a protected path
|
||||
2. And no :modularity-justification is provided
|
||||
3. Then block with an explanation
|
||||
|
||||
The justification should explain WHY the change cannot be a skill.
|
||||
Common valid reasons:
|
||||
- The change fixes a bug in the harness itself
|
||||
- The change adds a primitive that skills cannot implement
|
||||
- The change is required for security hardening
|
||||
|
||||
Invalid reasons:
|
||||
- 'It's easier to modify the harness'
|
||||
- 'Skills are too slow'
|
||||
- 'I want to keep it all in one place'"
|
||||
|
||||
(declare (ignore context))
|
||||
|
||||
(let* ((payload (getf action :payload))
|
||||
(target-file (or (getf payload :file) (getf payload :filename)))
|
||||
(target-file (or (getf payload :file)
|
||||
(getf payload :filename)))
|
||||
(justification (or (getf payload :modularity-justification)
|
||||
(getf payload :MODULARITY-JUSTIFICATION))))
|
||||
|
||||
(when (and target-file
|
||||
(some (lambda (path) (search path target-file)) *modularity-protected-paths*)
|
||||
(some (lambda (path) (search path target-file))
|
||||
*modularity-protected-paths*)
|
||||
(not justification))
|
||||
|
||||
(return-from policy-check-modularity
|
||||
(list :type :LOG
|
||||
:payload (list :level :error
|
||||
:text "POLICY [Modularity]: Modification to protected core path blocked. Provide :modularity-justification explaining why this cannot be a skill."
|
||||
:blocked-path target-file))))
|
||||
action))
|
||||
|
||||
action)
|
||||
#+end_src
|
||||
|
||||
* The Policy Explanation Engine
|
||||
When the policy gate modifies or blocks an action, it must tell the user *why*. This function formats a human-readable rationale from the invariant that triggered the interception.
|
||||
** 5. Technical Mastery & Mentorship
|
||||
|
||||
*The maxim: "Teaching is the highest form of assistance."*
|
||||
|
||||
The agent's goal is not to "do it for the user," but to "empower the user." Every autonomous action must be explained at a level that increases the user's technical understanding.
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defvar *mentorship-required-actions*
|
||||
'(:create-skill :eval :modify-file :write-file :replace
|
||||
:rename-file :delete-file :shell :create-note)
|
||||
"Actions that trigger the Mentorship invariant.
|
||||
|
||||
These are high-impact actions that should come with explanations
|
||||
not just for the user, but for future debugging and maintenance.")
|
||||
|
||||
(defun policy-check-mentorship (action context)
|
||||
"Blocks high-impact actions that lack a mentorship note.
|
||||
|
||||
MENTORSHIP CHECK:
|
||||
1. If the action is in *mentorship-required-actions*
|
||||
2. Or if the action calls shell/eval/repair-file tools
|
||||
3. Then require :mentorship-note explaining what and why
|
||||
|
||||
The mentorship note should be:
|
||||
- Concise (1-2 sentences)
|
||||
- Educational (explain the principle, not just the action)
|
||||
- Actionable (help the user understand the outcome)"
|
||||
|
||||
(declare (ignore context))
|
||||
|
||||
(let* ((payload (getf action :payload))
|
||||
(act (or (getf payload :action)
|
||||
(getf action :action)))
|
||||
(note (or (getf payload :mentorship-note)
|
||||
(getf payload :MENTORSHIP-NOTE)))
|
||||
(target (or (getf action :target)
|
||||
(getf action :TARGET)))
|
||||
(tool (when (eq target :tool)
|
||||
(getf payload :tool))))
|
||||
|
||||
(when (or (member act *mentorship-required-actions*)
|
||||
(member tool '("shell" "eval" "repair-file")))
|
||||
|
||||
(unless note
|
||||
(return-from policy-check-mentorship
|
||||
(list :type :LOG
|
||||
:payload (list :level :error
|
||||
:text "POLICY [Mentorship]: High-impact action missing :mentorship-note. Explain what you are doing and why. Blocked.")))))
|
||||
|
||||
action)
|
||||
#+end_src
|
||||
|
||||
** 6. Long-Term Sustainability
|
||||
|
||||
*The maxim: "Build for the 100-year horizon."*
|
||||
|
||||
The Memex should be functional even when:
|
||||
- Internet is unavailable
|
||||
- Cloud services are discontinued
|
||||
- Hardware platforms change
|
||||
|
||||
This means preferring local, energy-efficient architectures over cloud-dependent ones.
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defvar *cloud-only-backends* '(:openrouter :openai :anthropic :groq :gemini-api)
|
||||
"Backends requiring internet connection and external infrastructure.
|
||||
|
||||
These are acceptable as fallbacks when local inference is unavailable,
|
||||
but should be logged as sustainability debt for tracking purposes.")
|
||||
|
||||
(defun policy-check-sustainability (action context)
|
||||
"Logs sustainability debt when action relies on cloud-only infrastructure.
|
||||
|
||||
Does NOT block—this is informational, not prohibitive.
|
||||
Cloud usage is acceptable tactically (when local models fail),
|
||||
but every cloud usage should be a conscious decision, not a default."
|
||||
|
||||
(let* ((payload (getf context :payload))
|
||||
(backend (getf payload :backend))
|
||||
(provider (getf payload :provider))
|
||||
|
||||
(when (or (member backend *cloud-only-backends*)
|
||||
(member provider *cloud-only-backends*))
|
||||
|
||||
(harness-log "POLICY [Sustainability]: Cloud provider '~a' used. Logged as sustainability debt."
|
||||
(or backend provider))
|
||||
|
||||
(return-from policy-check-sustainability
|
||||
(list :type :LOG
|
||||
:payload (list :level :warn
|
||||
:text (format nil "Sustainability Debt: Reliance on cloud provider '~a'. Consider Ollama or local inference."
|
||||
(or backend provider))))))
|
||||
|
||||
action)
|
||||
#+end_src
|
||||
|
||||
* Policy Explanation Engine
|
||||
|
||||
When the policy gate blocks or modifies an action, it must tell the user *why*. This creates an auditable log of every policy decision.
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defun policy-explain (invariant-key message &optional original-action)
|
||||
"Formats a policy decision into an auditable explanation plist.
|
||||
INVARIANT-KEY is one of :transparency, :autonomy, :bloat, :modularity, :mentorship, :sustainability.
|
||||
MESSAGE is a human-readable string.
|
||||
ORIGINAL-ACTION is the action that was blocked or modified."
|
||||
|
||||
INVARIANT-KEY is one of:
|
||||
:transparency, :autonomy, :bloat, :modularity, :mentorship, :sustainability
|
||||
|
||||
MESSAGE is a human-readable string explaining the decision.
|
||||
|
||||
ORIGINAL-ACTION is the action that was blocked or modified.
|
||||
|
||||
Returns a REQUEST plist addressed to the original source,
|
||||
containing the explanation and original action for transparency."
|
||||
|
||||
(list :type :REQUEST
|
||||
:target (or (ignore-errors (getf (getf original-action :meta) :source)) :cli)
|
||||
:target (or (ignore-errors
|
||||
(getf (getf original-action :meta) :source))
|
||||
:cli)
|
||||
:payload (list :action :message
|
||||
:text (format nil "[POLICY ~a] ~a" invariant-key message)
|
||||
:explanation (format nil "Invariant: ~a | Rationale: ~a" invariant-key message)
|
||||
:explanation (format nil "Invariant: ~a | Rationale: ~a"
|
||||
invariant-key message)
|
||||
:original-action original-action)))
|
||||
#+end_src
|
||||
|
||||
* The Policy Gate
|
||||
The main deterministic entry point for the policy skill. It runs invariant checks in priority order. If a check returns a blocking LOG event, the gate immediately yields with an explanation. If a check returns a modified action (e.g., a warning wrapper), the modified action is passed down the chain.
|
||||
|
||||
The gate also attempts to delegate to Engineering Standards, but it does so robustly: it searches multiple candidate package names and falls back gracefully if the standards skill is not loaded.
|
||||
** Running Invariant Checks
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defun policy-run-invariant-checks (action context)
|
||||
"Runs all invariant checks in priority order. Returns the final action,
|
||||
a blocking LOG event, or a warning wrapper."
|
||||
"Runs all invariant checks in priority order.
|
||||
|
||||
Priority order (from *policy-invariant-priorities*):
|
||||
1. Transparency (500) - blocks non-transparent actions
|
||||
2. Autonomy (400) - warns on proprietary dependencies
|
||||
3. Bloat (300) - warns on oversized skills
|
||||
4. Modularity (250) - blocks unprotected core modifications
|
||||
5. Mentorship (200) - blocks unexplained high-impact actions
|
||||
6. Sustainability (100) - warns on cloud dependencies
|
||||
|
||||
Returns:
|
||||
- The final action (possibly modified by checks)
|
||||
- A blocking LOG event (if any check returned :error level)
|
||||
- A warning wrapper (if checks returned :warn level but no blocks)"
|
||||
|
||||
(let ((checks '(policy-check-transparency
|
||||
policy-check-autonomy
|
||||
policy-check-bloat
|
||||
policy-check-modularity
|
||||
policy-check-mentorship
|
||||
policy-check-sustainability)))
|
||||
|
||||
(dolist (check-fn checks action)
|
||||
(let ((result (funcall check-fn action context)))
|
||||
;; If the check returned a LOG event, treat it as a block/warning
|
||||
|
||||
;; If the check returned a LOG/EVENT, interpret it
|
||||
(when (and (listp result)
|
||||
(member (getf result :type) '(:LOG :EVENT)))
|
||||
(let ((level (getf (getf result :payload) :level)))
|
||||
(cond ((eq level :error)
|
||||
;; Hard block: return the log event directly
|
||||
(return-from policy-run-invariant-checks result))
|
||||
(t
|
||||
;; Warning: log it, but continue with the original action
|
||||
(harness-log "~a" (getf (getf result :payload) :text))))))))))
|
||||
|
||||
(let ((level (getf (getf result :payload) :level)))
|
||||
|
||||
(cond
|
||||
;; Hard block: error level stops processing immediately
|
||||
((eq level :error)
|
||||
(return-from policy-run-invariant-checks result))
|
||||
|
||||
;; Soft warning: log but continue with original action
|
||||
(t
|
||||
(harness-log "~a" (getf (getf result :payload) :text)))))))))
|
||||
|
||||
action)
|
||||
#+end_src
|
||||
|
||||
** Finding Engineering Standards
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defun policy-find-engineering-standards-gate ()
|
||||
"Searches for the Engineering Standards gate across known jailed package names.
|
||||
Returns the function symbol, or NIL if unavailable."
|
||||
|
||||
The standards skill may be in opencortex-contrib submodule,
|
||||
so we search multiple possible package names with graceful fallback.
|
||||
|
||||
Returns the function symbol, or NIL if unavailable."
|
||||
|
||||
(dolist (pkg-name '(:opencortex.skills.org-skill-engineering-standards
|
||||
:opencortex.skills.org-skill-engineering
|
||||
:opencortex.skills.engineering-standards)
|
||||
nil)
|
||||
|
||||
(let ((pkg (find-package pkg-name)))
|
||||
(when pkg
|
||||
(let ((sym (find-symbol "ENGINEERING-STANDARDS-GATE" pkg)))
|
||||
(when (and sym (fboundp sym))
|
||||
(return (symbol-function sym))))))))
|
||||
#+end_src
|
||||
|
||||
** Main Policy Gate
|
||||
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defun policy-deterministic-gate (action context)
|
||||
"The main policy gate. Runs invariant checks, then delegates to engineering standards if available.
|
||||
Never returns NIL silently; always returns an action or an auditable log event."
|
||||
"The main policy gate entry point.
|
||||
|
||||
This function is registered as the deterministic-fn for the policy skill.
|
||||
It runs invariant checks, then delegates to engineering standards if loaded.
|
||||
|
||||
IMPORTANT: Never returns NIL silently. Always returns either:
|
||||
- An action (possibly modified)
|
||||
- A blocking LOG event with explanation
|
||||
- A warning wrapper with explanation"
|
||||
|
||||
;; Step 1: Run invariant checks
|
||||
(let ((current-action (policy-run-invariant-checks action context)))
|
||||
;; If an invariant returned a blocking log, do not proceed further
|
||||
|
||||
;; Step 2: If an invariant blocked the action, stop here
|
||||
(when (and (listp current-action)
|
||||
(member (getf current-action :type) '(:LOG :EVENT))
|
||||
(eq (getf (getf current-action :payload) :level) :error))
|
||||
|
||||
(return-from policy-deterministic-gate current-action))
|
||||
;; Delegate to Engineering Standards if loaded
|
||||
|
||||
;; Step 3: Delegate to Engineering Standards if loaded
|
||||
(let ((eng-gate (policy-find-engineering-standards-gate)))
|
||||
(when eng-gate
|
||||
(setf current-action (funcall eng-gate current-action context))))
|
||||
|
||||
current-action))
|
||||
#+end_src
|
||||
|
||||
* Operational Mandates
|
||||
Every action performed by an agent in this environment must also adhere to the Engineering Standards. The policy skill evaluates every context (trigger is always true) because invariants are universal.
|
||||
* Skill Registration
|
||||
|
||||
** Skill Registration
|
||||
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
|
||||
(defskill :skill-policy
|
||||
:priority 500
|
||||
@@ -305,6 +555,29 @@ Every action performed by an agent in this environment must also adhere to the E
|
||||
:deterministic #'policy-deterministic-gate)
|
||||
#+end_src
|
||||
|
||||
* Quick Reference
|
||||
|
||||
** Invariant Quick Reference
|
||||
|
||||
| Invariant | Blocks? | Trigger |
|
||||
|-----------|---------|---------|
|
||||
| Transparency | Yes | Missing `:explanation` on user-facing actions |
|
||||
| Autonomy | No | Action references proprietary domain |
|
||||
| Bloat | No | Skill file exceeds 50KB |
|
||||
| Modularity | Yes | Modification to `harness/` without justification |
|
||||
| Mentorship | Yes | High-impact action without `:mentorship-note` |
|
||||
| Sustainability | No | Action uses cloud-only provider |
|
||||
|
||||
** Required Fields by Action Type
|
||||
|
||||
| Action | Required Field | Purpose |
|
||||
|--------|---------------|---------|
|
||||
| User message | `:explanation` | Transparency |
|
||||
| Core modification | `:modularity-justification` | Modularity |
|
||||
| Skill creation | `:mentorship-note` | Mentorship |
|
||||
| File write | `:mentorship-note` | Mentorship |
|
||||
|
||||
* See Also
|
||||
- [[file:org-skill-engineering-standards.org][Engineering Standards]] (if loaded)
|
||||
- [[file:../harness/act.org][Act Stage]] (where the Bouncer and Policy gates are invoked)
|
||||
- [[file:org-skill-engineering-standards.org][Engineering Standards]] (if loaded in opencortex-contrib)
|
||||
- [[file:../harness/act.org][Act Stage]] - Where Policy and Bouncer gates are invoked
|
||||
- [[file:../harness/manifest.org][Manifest]] - The Thin Harness philosophy
|
||||
Reference in New Issue
Block a user