- vault: add vault-get-secret/vault-set-secret wrappers - programming-org: implement org-modify (text search-replace) and org-ast-render (AST to Org text) - programming-literate: implement literate-block-balance-check (paren validation) and literate-tangle-sync-check (org→lisp diff) - system-self-improve: replace stubs with surgical text editing and error diagnosis; remove dead first defskill - system-event-orchestrator: implement orchestrator-bootstrap (scan Org files for HOOK/CRON) - system-archivist: implement Scribe distillation (daily logs→atomic notes) and Gardener link/orphan repair - system-memory: implement memory-inspect with type/todo/orphan statistics - core-skills, core-context: fix path relic (skills/ → lisp/, org/) - docs: add Token Economics section to DESIGN_DECISIONS, remediation roadmap entries
254 lines
12 KiB
Org Mode
254 lines
12 KiB
Org Mode
#+TITLE: v0.2.x Remediation Plan
|
|
#+AUTHOR:
|
|
#+STARTUP: content
|
|
#+FILETAGS: :docs:plan:remediation:
|
|
|
|
* Summary
|
|
|
|
Features marked DONE in the ROADMAP for v0.1.0 and v0.2.0 but whose implementations
|
|
are stubs, no-ops, or missing critical functionality. These should have been
|
|
completed in their respective versions and must be addressed before v0.3.0
|
|
development proceeds.
|
|
|
|
* P0: system-archivist — Proper Distillation and Link Maintenance
|
|
|
|
** Claimed status**: =DONE= (v0.1.0: "Scribe + Gardener background workers" + v0.2.0: "31 org files with full literate prose")
|
|
|
|
** Actual state**: =archivist-log= is a trivial log wrapper (~10 lines). No knowledge
|
|
distillation, no broken link detection, no orphaned node flagging.
|
|
|
|
** What it should do**:
|
|
|
|
*** Scribe (knowledge distillation)
|
|
1. Read daily Org log files from the Memex =daily/= directory
|
|
2. Identify new entries (since last processed commit or timestamp)
|
|
3. Extract conceptual claims, decisions, and atomic facts from prose
|
|
4. Generate atomic Zettelkasten notes in =notes/= with:
|
|
- Descriptive snake_case filename (no dates)
|
|
- =:CREATED:= property from the source log's date
|
|
- =Source:= backlink to the original daily file and headline
|
|
- Tags inferred from content and parent file
|
|
5. Track processed state to avoid re-distilling the same content
|
|
|
|
*** Gardener (structural maintenance)
|
|
1. Scan all Org files in the Memex for broken =[[file:...][...]]= links
|
|
2. Scan =memory-store= for =memory-object= entries whose =:parent-id= or =:children=
|
|
references point to deleted objects (orphaned nodes)
|
|
3. Flag broken links and orphans with =:GARDENER: broken-link= or =:GARDENER: orphan= tags
|
|
4. Generate a maintenance report as a Org buffer the user can review
|
|
|
|
*** Implementation approach
|
|
- Wire into =system-event-orchestrator= as cron jobs:
|
|
- Scribe: daily cron (="<%%Y-%%m-%%d %%a +1d>"=, tier =:cognition=)
|
|
- Gardener: weekly cron (="<%%Y-%%m-%%d %%a +1w>"=, tier =:cognition=)
|
|
- Use =orchestrator-register-cron= to schedule
|
|
- Replace the trivial =archivist-log= function with real implementation
|
|
- Track last-processed state via =memory-store= (:LATEST_PROCESSED_DATETIME property)
|
|
or git commit hash
|
|
|
|
** Dependencies**: =system-event-orchestrator= (cron scheduling), =core-memory= (object store)
|
|
|
|
** Verification**: FiveAM test that creates a daily log with known content, runs the
|
|
Scribe, and asserts that an atomic note was created with correct backlinks.
|
|
|
|
* P0: system-self-improve — Surgical Self-Editing and Self-Repair
|
|
|
|
** Claimed status**: =DONE= (v0.2.0: "Self-editing (error detection, surgical fix, hot-reload)")
|
|
|
|
** Actual state**: =self-improve-edit= does =(declare (ignore old-text new-text))= followed by
|
|
a log message — no actual text transformation. =self-improve-fix= same pattern.
|
|
The skill's trigger is =nil= so it never fires.
|
|
|
|
** What it should do**:
|
|
|
|
*** Self-edit (surgical text replacement)
|
|
1. Accept (=filepath=, =old-text=, =new-text=) and apply the transformation
|
|
2. Read the file, locate =old-text= (with exact match verification), replace with =new-text=
|
|
3. If the target is an Org file with a =#+begin_src lisp= block, tangling the file
|
|
and reloading the skill after edit
|
|
4. Create a memory snapshot before editing (rollback safety)
|
|
5. Verify the edit succeeded (re-read file, confirm =new-text= appears)
|
|
6. Return success/failure with a diff summary
|
|
|
|
*** Self-fix (error diagnosis and repair)
|
|
1. Accept (=skill-name=, =error-log=) and diagnose the failure
|
|
2. Parse the error log for: syntax errors (unmatched parens, invalid forms),
|
|
undefined symbol references, semantic issues (prohibited forms)
|
|
3. For syntax errors: locate the problematic region, propose a correction
|
|
using structural Lisp knowledge
|
|
4. For undefined references: check if the symbol exists in another package,
|
|
if the skill's =#+DEPENDS_ON:= declaration is missing a dependency
|
|
5. For semantic issues: identify the prohibited operation and suggest alternatives
|
|
6. Invoke =self-improve-edit= to apply the fix
|
|
7. After repair, run the skill's tests if they exist; if tests pass, hot-reload
|
|
|
|
*** Implementation approach
|
|
- Add an actual =:trigger= function that activates on =:ERROR= or =:STUCK= signal types
|
|
- =self-improve-edit=: use =uiop:read-file-string=, string replacement with
|
|
=ppcre:regex-replace= or substring operations, write back with =with-open-file=
|
|
- =self-improve-fix=: add structural analysis in =programming-lisp.lisp= for error parsing
|
|
- Leverage the REPL skill for verification after repair (call =lisp-eval= on the fixed code block)
|
|
|
|
** Dependencies**: =programming-lisp= (lisp-structural-check), =programming-org= (tangling),
|
|
=core-memory= (snapshot-memory), =core-skills= (jailed reload)
|
|
|
|
** Verification**: FiveAM test that creates a file with known content, calls self-improve-edit,
|
|
and asserts the replacement was applied. Second test with a file containing a
|
|
deliberate error, calls self-improve-fix, and asserts the error was corrected.
|
|
|
|
* P1: system-event-orchestrator — Bootstrap Implementation
|
|
|
|
** Claimed status**: v0.3.0 partially DONE ("hook-registry + cron-registry + tier classifier")
|
|
|
|
** Actual state**: Hook/cron registries, tier dispatching, and heartbeat integration work.
|
|
But =orchestrator-bootstrap= is a stub: =(log-message "ORCHESTRATOR: Bootstrap complete")=
|
|
|
|
** What it should do**:
|
|
|
|
1. Scan the Memex =projects/= and =notes/= directories for Org files containing =#+HOOK:= properties
|
|
2. For each =#+HOOK:= property found, call =orchestrator-register-hook= with
|
|
the hook name and a gate function
|
|
3. For files with =#+CRON:= properties (or cron expressions in timestamps),
|
|
register them via =orchestrator-register-cron=
|
|
4. Log the count of registered hooks and cron jobs at completion
|
|
5. Run bootstrap once at startup (after memory is loaded but before cognitive loop begins)
|
|
|
|
*** Implementation approach
|
|
- Use =uiop:directory-files= with glob patterns for =*.org= files
|
|
- Use =org-element= from Emacs (via =emacs-bridge= or =org-eval= skill) for parsing,
|
|
or implement a simple regex-based Org property parser in Lisp
|
|
- Walk each file's headlines, extract property drawers, filter for =HOOK:= and =CRON:= keys
|
|
- Call existing =orchestrator-register-hook= / =orchestrator-register-cron=
|
|
|
|
** Dependencies**: =programming-org= (Org file parsing), file system access
|
|
|
|
** Verification**: Create a test Org file with =#+HOOK: on-write=, run bootstrap,
|
|
assert the hook registry contains the expected entry.
|
|
|
|
* P1: system-memory — Memory Introspection
|
|
|
|
** Claimed status**: Skill exists but was never part of a version milestone.
|
|
|
|
** Actual state**: =memory-inspect= is a no-op: =(log-message "MEMORY: Self-inspection triggered.")=
|
|
The =:trigger= is =nil= so the skill never activates.
|
|
|
|
** What it should do**:
|
|
|
|
1. Return a structured report of memory state:
|
|
- Total objects in =*memory-store*=
|
|
- Distribution by type (=:HEADLINE=, =:PARAGRAPH=, etc.)
|
|
- Distribution by =:TODO-STATE= (=TODO=, =NEXT=, =DONE=, etc.)
|
|
- Count of privacy-filtered objects
|
|
- Most recent objects (by =:version= timestamp)
|
|
- Current snapshot count and timestamps
|
|
- Orphaned objects (parent-id references a deleted ID)
|
|
2. Accept an optional filter to narrow the report (by type, by tag, by time range)
|
|
3. Wire the trigger to activate on =:INTROSPECTION= signal type or =/memory= commands
|
|
|
|
*** Implementation approach
|
|
- Iterate =*memory-store*= with =maphash=, collect statistics
|
|
- Add to skill trigger: =(eq (getf (getf ctx :payload) :sensor) :introspection)=
|
|
- Return results as a plist that can be rendered in the TUI
|
|
|
|
** Dependencies**: =core-memory= (memory-store and memory-object struct)
|
|
|
|
** Verification**: Ingest known objects, call memory-inspect, assert type counts and
|
|
object counts match.
|
|
|
|
* P2: core-context — Semantic Retrieval (Embeddings)
|
|
|
|
** Claimed status**: The foveal-peripheral model is implemented and tested, but the
|
|
embedding pipeline that feeds it is listed as TODO for v0.3.0.
|
|
|
|
** Actual state**: The context rendering code (=context-object-render=) computes
|
|
=cosine-similarity= correctly, but =org-object-vector= is never populated.
|
|
All objects have =nil= vectors, all similarities are =0.0=, and the model
|
|
falls back to "include everything within depth 2." This is functionally
|
|
equivalent to no retrieval at all.
|
|
|
|
** What it should do**:
|
|
|
|
1. Add a =populate-vector= function to =core-memory= that calls an embedding
|
|
provider and stores the result in the =memory-object= =:vector= slot
|
|
2. At ingest time (=ingest-ast=), generate embeddings for new objects
|
|
3. Embedding provider options (in priority order):
|
|
- Ollama (local, =nomic-embed-text= or =mxbai-embed-large=)
|
|
- OpenAI-compatible embedding API (=text-embedding-3-small=)
|
|
- Fallback: TF-IDF bag-of-words vector (no external dependency)
|
|
4. Updates: when =memory-object= content changes, mark =:vector= as =:pending=
|
|
and process in a background batch via the event orchestrator
|
|
5. Add an environment variable =EMBEDDING_PROVIDER= with default =ollama=
|
|
|
|
*** Implementation approach
|
|
- Add an =:embedding-provider= function stored in =*config*=
|
|
- =embed-object=: take content string → call provider → store float vector
|
|
- Modify =ingest-ast= to call =embed-object= on each new object
|
|
- Add batch processing in =system-event-orchestrator= for vector updates
|
|
- Use =bordeaux-threads= with a lock for async embedding generation
|
|
|
|
** Dependencies**: External embedding provider (Ollama or API), =core-memory= (vector slot)
|
|
|
|
** Verification**: Create objects with content, run embedding pipeline, assert vectors
|
|
are non-nil and have the correct dimensionality. Verify that =cosine-similarity=
|
|
between semantically similar objects exceeds 0.75 threshold.
|
|
|
|
* P2: core-context — Subtree-Based Skill Source Loading
|
|
|
|
** Claimed status**: DESIGN_DECISIONS §"Org-Mode as Unified AST" describes: "When the
|
|
agent needs information about the =openctl-db= function, it queries for the
|
|
=openctl-db= subtree specifically."
|
|
|
|
** Actual state**: =context-skill-source= reads the ENTIRE Org file as a string via
|
|
=uiop:read-file-string=. No subtree query exists.
|
|
|
|
** What it should do**:
|
|
|
|
1. Add a =context-skill-subtree= function that takes (=skill-name=, =heading-name=)
|
|
and returns only the content under that headline
|
|
2. Add a =context-skill-function-signature= function that returns only the function
|
|
name, lambda list, and docstring
|
|
3. Add a =context-skill-tests= function that returns only test blocks
|
|
4. Modify =context-skill-source= to optionally accept a =:subtree= keyword argument
|
|
5. If the Org file has an Org-element parser available, use it for structural queries;
|
|
otherwise fall back to regex-based headline matching
|
|
|
|
*** Implementation approach
|
|
- Use =org-element= via =org-eval= skill (REPL bridge to Emacs) if available
|
|
- Lisp-native fallback: parse Org headlines with regex (=^*+ = pattern),
|
|
match heading name by string comparison, extract content until next
|
|
headline of equal or higher level
|
|
- Cache parsed results to avoid re-parsing on repeated queries
|
|
|
|
** Dependencies**: =programming-org= (Org parsing utilities), =emacs-bridge= (if Emacs
|
|
Org-element is preferred)
|
|
|
|
** Verification**: Create a test Org file with multiple headlines, query for a specific
|
|
subtree, assert only that subtree's content is returned.
|
|
|
|
* Priority and Sequencing
|
|
|
|
The remediation should proceed in this order:
|
|
|
|
1. **system-event-orchestrator bootstrap** (P1) — needed as infrastructure for Scribe/Gardener cron scheduling
|
|
2. **system-archivist** (P0) — depends on orchestrator for cron scheduling
|
|
3. **system-self-improve** (P0) — independent, can proceed in parallel with #2
|
|
4. **core-context embeddings** (P2) — independent, unlocks semantic retrieval
|
|
5. **core-context subtree loading** (P2) — independent, improves context efficiency
|
|
6. **system-memory inspect** (P1) — lowest priority, nice-to-have introspection
|
|
|
|
P0 items must be completed before v0.3.0 development begins. P1 items should be
|
|
completed before v0.3.0 is released. P2 items can extend into early v0.3.0.
|
|
|
|
* Out of Scope
|
|
|
|
Features listed as TODO in the ROADMAP for v0.3.0+ are NOT in this remediation
|
|
plan. Specifically excluded:
|
|
|
|
- HITL continuation-based suspension (v0.3.0 TODO)
|
|
- Model-tier routing / cost optimization (v0.3.0 TODO)
|
|
- Memory scope segmentation (v0.3.0 TODO)
|
|
- Long-horizon planning / task trees (v0.4.0 TODO)
|
|
- Shadow simulation mode (not on roadmap, aspirational)
|
|
- Formal verification of dispatcher rules (not on roadmap, aspirational)
|
|
- Bouncer rule learning from HITL decisions (not on roadmap, aspirational)
|