feat(arch): finalize Universal Literate Note transition for all projects and skills
This commit is contained in:
@@ -1,33 +0,0 @@
|
||||
#+TITLE: PRD: Skill - Technical Analyst Agent
|
||||
#+STATUS: FROZEN
|
||||
#+AUTHOR: Agent
|
||||
#+CREATED: [2026-03-31 Tue 12:25]
|
||||
|
||||
* 1. Purpose
|
||||
Define the automated testing and analysis behaviors for the PSF Consensus Loop. The Technical Analyst skill transforms a SIGNED PROTOCOL (Blueprint) into a comprehensive, failing TDD suite (Success Criteria).
|
||||
|
||||
* 2. User Needs
|
||||
|
||||
** 2.1 Protocol Perception
|
||||
As the system orchestrator, I need the Analyst to identify when an architecture is ready for testing.
|
||||
- The Analyst MUST monitor `$PROJECTS_DIR` for `PROTOCOL.org` files with `#+STATUS: SIGNED`.
|
||||
|
||||
** 2.2 TDD Inception (Success Criteria)
|
||||
I need rigorous test cases generated from semantic interfaces.
|
||||
- The Analyst MUST generate a test suite in the project's `tests/` directory.
|
||||
- It MUST cover both the "Happy Path" and "Edge Case" scenarios.
|
||||
- It MUST ensure that all tests match the function signatures defined in the project's `PROTOCOL.org`.
|
||||
|
||||
** 2.3 Automated Test Execution (Initial)
|
||||
I need the Analyst to verify that the tests *fail* initially (Red-Green-Refactor).
|
||||
- The skill must have a symbolic (Lisp) actuator that writes the generated test code and confirms its existence.
|
||||
|
||||
** 2.4 Structural Enforcement
|
||||
I need the Analyst to ensure the project's `tests/` directory is correctly initialized.
|
||||
- The Analyst MUST be able to scaffold the `tests/` directory if it is missing.
|
||||
|
||||
* 3. Success Criteria
|
||||
- [ ] **Trigger Accuracy:** Analyst correctly identifies a `SIGNED` PROTOCOL and ignores `DRAFT` Protocols.
|
||||
- [ ] **TDD Suite Generation:** Analyst generates a test suite that references at least one interface from the PROTOCOL.
|
||||
- [ ] **Physical Inception:** The generated test code is physically written to `tests/test-suite.lisp` (or equivalent).
|
||||
- [ ] **Edge Case Coverage:** The generated suite includes at least one negative test case (error handling).
|
||||
@@ -1,40 +0,0 @@
|
||||
#+TITLE: PROTOCOL: Skill - Technical Analyst Agent
|
||||
#+STATUS: DRAFT
|
||||
#+AUTHOR: Tech-Analyst-Agent
|
||||
#+CREATED: [2026-03-31 Tue 12:30]
|
||||
|
||||
* 1. Architectural Intent
|
||||
This protocol defines the shared Lisp interfaces for the Technical Analyst skill. It ensures that the PSF Consensus Loop follows a strict TDD mandate by defining how the Analyst perceives signed architectures and actuates failing test suites.
|
||||
|
||||
Following the **Literate Mandate**, the Analyst skill's own implementation must be generated from its Org-mode source.
|
||||
|
||||
* 2. Semantic Interfaces
|
||||
|
||||
** 2.1 Blueprint Perception
|
||||
#+begin_src lisp
|
||||
(defun tech-analyst-perceive-signed-protocol (project-name)
|
||||
"Checks if a project has a SIGNED PROTOCOL.
|
||||
Returns a plist: (:status :signed :path \"path/to/PROTOCOL.org\") or NIL."
|
||||
)
|
||||
#+end_src
|
||||
|
||||
** 2.2 TDD Suite Actuation
|
||||
#+begin_src lisp
|
||||
(defun tech-analyst-actuate-tdd-suite (project-name test-content)
|
||||
"Physically writes the TDD suite (test code) to the project.
|
||||
Input: project name and generated Lisp/Python test code.
|
||||
1. Ensures the 'tests/' directory exists.
|
||||
2. Writes the content to 'tests/test-suite.*'.
|
||||
Returns a success message or error signal."
|
||||
)
|
||||
#+end_src
|
||||
|
||||
** 2.3 Success Criteria Generation
|
||||
#+begin_src lisp
|
||||
(defun tech-analyst-generate-success-criteria (project-name)
|
||||
"Extracts success criteria from the PROTOCOL and PRD to generate the 'RED' test suite."
|
||||
)
|
||||
#+end_src
|
||||
|
||||
* 3. Integration with PSF Lifecycle
|
||||
The Analyst is triggered when a project transitions from `:BLUEPRINT` to `:SUCCESS`. Its output (a failing TDD suite in `tests/`) is the "Safety Gate" that permits the **Coder** (Phase D: Build) to begin implementation.
|
||||
83
projects/org-skill-tech-analyst/src/analyst-logic.lisp
Normal file
83
projects/org-skill-tech-analyst/src/analyst-logic.lisp
Normal file
@@ -0,0 +1,83 @@
|
||||
;;;; analyst-logic.lisp --- TDD automation for the PSF (Unified).
|
||||
;;;; This file is TANGLED from notes/org-skill-tech-analyst.org. DO NOT EDIT MANUALLY.
|
||||
|
||||
(defpackage :org-skill-tech-analyst
|
||||
(:use :cl :uiop :local-time)
|
||||
(:export #:tech-analyst-perceive-signed-protocol
|
||||
#:tech-analyst-scan-all-notes
|
||||
#:trigger-skill-tech-analyst
|
||||
#:neuro-skill-tech-analyst
|
||||
#:tech-analyst-actuate))
|
||||
|
||||
(in-package :org-skill-tech-analyst)
|
||||
|
||||
(defun kernel-log (message &rest args)
|
||||
(format t "~&[ANALYST] ~?" message args))
|
||||
|
||||
(defun tech-analyst-perceive-signed-protocol (note-path)
|
||||
"Checks if a master note has a SIGNED PROTOCOL and lacks a TDD suite in the material project."
|
||||
(let* ((content (uiop:read-file-string note-path))
|
||||
(filename (pathname-name note-path))
|
||||
(project-name (subseq filename 10)) ; Extract 'name' from 'org-skill-name'
|
||||
(projects-dir (or (uiop:getenv "PROJECTS_DIR") "projects/"))
|
||||
(test-path (format nil "~aorg-skill-~a/tests/test-suite.lisp" projects-dir project-name)))
|
||||
(when (and (search "* Phase B: Blueprint (PROTOCOL)" content)
|
||||
(search ":STATUS: SIGNED" content)
|
||||
(not (uiop:file-exists-p test-path)))
|
||||
`(:project-name ,project-name :note-path ,note-path :content ,content))))
|
||||
|
||||
(defun tech-analyst-scan-all-notes ()
|
||||
"Scans all org-skill-*.org notes for blueprints ready for testing."
|
||||
(let ((notes-dir (or (uiop:getenv "MEMEX_NOTES") "notes/"))
|
||||
(ready-notes '()))
|
||||
(dolist (file (uiop:directory-files notes-dir "org-skill-*.org"))
|
||||
(let ((status (tech-analyst-perceive-signed-protocol file)))
|
||||
(when status (push status ready-notes))))
|
||||
ready-notes))
|
||||
|
||||
(defun trigger-skill-tech-analyst (context)
|
||||
"Triggers on heartbeat if any master note is in a SIGNED PROTOCOL state."
|
||||
(let ((type (getf context :type))
|
||||
(payload (getf context :payload)))
|
||||
(when (and (eq type :EVENT) (eq (getf payload :sensor) :heartbeat))
|
||||
(let ((ready (tech-analyst-scan-all-notes)))
|
||||
(when ready
|
||||
(setf (getf (getf context :payload) :ready-blueprints) ready)
|
||||
t)))))
|
||||
|
||||
(defun neuro-skill-tech-analyst (context)
|
||||
(let* ((payload (getf context :payload))
|
||||
(note (car (getf payload :ready-blueprints)))
|
||||
(name (getf note :project-name))
|
||||
(protocol-content (getf note :content)))
|
||||
(format nil "
|
||||
You are the PSF Technical Analyst.
|
||||
The Master Note for project '~a' has a SIGNED PROTOCOL and needs a TDD Suite.
|
||||
|
||||
PROTOCOL CONTENT:
|
||||
---
|
||||
~a
|
||||
---
|
||||
|
||||
TASK:
|
||||
Generate a comprehensive Common Lisp test suite (failing/RED).
|
||||
1. Use FiveAM for testing.
|
||||
2. Match function signatures exactly as defined in the PROTOCOL.
|
||||
|
||||
Return a Lisp plist: (:target :analyst :action :actuate :name \"~a\" :content \"...test code...\")
|
||||
" name protocol-content name)))
|
||||
|
||||
(defun tech-analyst-actuate (action context)
|
||||
(let* ((payload (getf action :payload))
|
||||
(project-name (getf payload :name))
|
||||
(test-content (getf payload :content))
|
||||
(projects-dir (or (uiop:getenv "PROJECTS_DIR") "projects/"))
|
||||
(project-dir (format nil "~aorg-skill-~a/" projects-dir project-name))
|
||||
(test-dir (format nil "~atests/" project-dir))
|
||||
(test-path (format nil "~atests/test-suite.lisp" project-dir)))
|
||||
|
||||
(kernel-log "Actuating TDD Suite for ~a" project-name)
|
||||
(ensure-directories-exist test-dir)
|
||||
(with-open-file (out test-path :direction :output :if-exists :supersede)
|
||||
(format out ";;; TDD Suite for ~a~%~a" project-name test-content))
|
||||
(format nil "SUCCESS - Technical Analyst established TDD Suite for ~a" project-name)))
|
||||
47
projects/org-skill-tech-analyst/tests/simulate_analyst.py
Normal file
47
projects/org-skill-tech-analyst/tests/simulate_analyst.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
def simulate_perceive(project_name, projects_dir):
|
||||
protocol_path = os.path.join(projects_dir, project_name, "PROTOCOL.org")
|
||||
test_path = os.path.join(projects_dir, project_name, "tests", "test-suite.lisp")
|
||||
|
||||
if not os.path.exists(protocol_path):
|
||||
return None
|
||||
|
||||
with open(protocol_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
if "#+STATUS: SIGNED" in content and not os.path.exists(test_path):
|
||||
return {"project": project_name, "protocol_path": protocol_path, "content": content}
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_dir = "/tmp/analyst_test_projects"
|
||||
if os.path.exists(test_dir):
|
||||
shutil.rmtree(test_dir)
|
||||
os.makedirs(os.path.join(test_dir, "test-project", "tests"))
|
||||
|
||||
proto_file = os.path.join(test_dir, "test-project", "PROTOCOL.org")
|
||||
|
||||
print("--- Test 1: Draft Protocol ---")
|
||||
with open(proto_file, "w") as f:
|
||||
f.write("#+TITLE: Test\n#+STATUS: DRAFT\n")
|
||||
res = simulate_perceive("test-project", test_dir)
|
||||
print(f"Result: {res}")
|
||||
status1 = "PASS" if res is None else "FAIL"
|
||||
|
||||
print("\n--- Test 2: Signed Protocol ---")
|
||||
with open(proto_file, "w") as f:
|
||||
f.write("#+TITLE: Test\n#+STATUS: SIGNED\n")
|
||||
res = simulate_perceive("test-project", test_dir)
|
||||
print(f"Result: {res['project'] if res else None}")
|
||||
status2 = "PASS" if res and res['project'] == "test-project" else "FAIL"
|
||||
|
||||
print("\n--- Test 3: TDD suite already exists ---")
|
||||
with open(os.path.join(test_dir, "test-project", "tests", "test-suite.lisp"), "w") as f:
|
||||
f.write("exists")
|
||||
res = simulate_perceive("test-project", test_dir)
|
||||
print(f"Result: {res}")
|
||||
status3 = "PASS" if res is None else "FAIL"
|
||||
|
||||
print(f"\nFinal Status: {'PASS' if all(s == 'PASS' for s in [status1, status2, status3]) else 'FAIL'}")
|
||||
Reference in New Issue
Block a user