:PROPERTIES: :ID: 1063668a-57ab-4d44-8db5-6f6fabb915b9 :CREATED: [2026-03-30 Mon 21:16] :EDITED: [2026-04-07 Tue 13:42] :END: #+TITLE: SKILL: AST Normalization Agent (Universal Literate Note) #+STARTUP: content #+FILETAGS: :ast:normalization:integrity:psf: * Overview The *AST Normalization Agent* maintains the structural integrity of the Org-mode Abstract Syntax Tree. It ensures all nodes adhere to strict metadata requirements and handles deterministic refactoring. * Phase A: Demand (PRD) :PROPERTIES: :STATUS: FROZEN :END: ** 1. Purpose Define automated structural enforcement and refactoring for the Org AST. ** 2. User Needs - *Structural Enforcement:* Mandatory unique IDs for all headlines. - *Deterministic Preemption:* Symbolic verification must override neural suggestions if errors exist. - *Fidelity:* Preservation of content during metadata normalization. ** 3. Success Criteria *** TODO ID Injection *** TODO Neural Preemption *** TODO Subtree Refactoring Verification * Phase B: Blueprint (PROTOCOL) :PROPERTIES: :STATUS: SIGNED :END: * Phase D: Build (Implementation) ** Normalization Logic #+begin_src lisp (defun headline-ensure-id (headline) "Checks if a headline node has a unique ID. If not, generates and injects one." (let* ((props (getf headline :properties)) (id (getf props :ID))) (if (and id (not (equal id ""))) headline (let* ((new-id (org-agent:org-id-new)) (new-props (append props (list :ID new-id)))) (org-agent:kernel-log "AST - Injected new ID ~a into headline '~a'" new-id (getf props :TITLE)) (setf (getf headline :properties) new-props) headline)))) (defun ast-normalize-recursive (ast) "Recursively ensures all headlines in the AST have unique IDs." (let ((type (getf ast :type)) (contents (getf ast :contents))) (when (eq type :HEADLINE) (setf ast (headline-ensure-id ast))) (when contents (setf (getf ast :contents) (mapcar (lambda (child) (if (listp child) (ast-normalize-recursive child) child)) contents))) ast)) (defun ast-normalize-file (filepath) "Reads a file (via Emacs actuator if possible, otherwise local), normalizes it, and returns the AST." (let ((ast (org-agent:context-query-store (format nil "file:~a" filepath)))) (if ast (ast-normalize-recursive ast) (progn (org-agent:kernel-log "AST ERROR - Could not find AST for ~a in store." filepath) nil)))) #+begin_src ** Cognitive Tools #+begin_src lisp (org-agent:def-cognitive-tool :normalize-subtree "Ensures every headline in the current subtree has a unique ID." :parameters ((:id :type :string :description "The ID of the root headline to normalize")) :body (lambda (args) (let* ((id (getf args :id)) (obj (org-agent:lookup-object id))) (if obj (progn (org-agent:kernel-log "AST - Normalizing subtree starting at ~a" id) ;; Implementation note: In a real system, we'd reconstruct the AST from the store, ;; normalize it, and then re-ingest it. "SUBTREE NORMALIZATION INITIATED.") "ERROR: Node not found.")))) #+end_src ** Skill Definition #+begin_src lisp (org-agent:defskill :skill-ast-normalization :priority 150 ; High priority, keeps the graph clean :trigger (lambda (context) (let ((payload (getf context :payload))) (eq (getf payload :sensor) :buffer-save))) :neuro nil :symbolic (lambda (action context) (let* ((payload (getf context :payload)) (ast (getf payload :ast))) (when ast (ast-normalize-recursive ast)) action))) #+end_src