feat(system): seedgo v2 operational, full system audit, 14/15 branches at 99%

Three days of intensive work bringing seedgo to full operational status
and driving all branches through comprehensive standards compliance.

Seedgo v2.0.0:
- 22 checkers active (up from 20), standards pack fully operational
- New introspection standard researched from Dev-Pass, FPLAN-0017 open
- Bypass system for false positives (.seedgo config)
- Standards query and audit commands fully functional

System-wide audit (FPLAN-0016):
- All 14 auditable branches at 99%+ compliance
- CLI imports standardized across all branches (console from cli.apps.modules)
- handle_command(command, args) → bool contract added to all modules
- print_help() function naming fixed for checker pattern matching
- Handler extraction: large modules split, file I/O moved to handler layer
- New handlers created across ai_mail, backup, daemon, flow, skills, spawn, seedgo

Branch-specific highlights:
- ai_mail: email.py split 840→420 lines, 4 new handlers
- flow: dplan_flow.py 688→591 lines, 4 new handlers
- seedgo: massive restructure — standards moved to handlers/aipass_standards/,
  old standards/ tree removed, bypass system added, diagnostics module
- commons: database module added, CLI imports fixed
- skills: 5 handle_commands added, help function renamed
- trigger: error reporter handler, handle_command routing
- All branches: consistent architecture, clean drone routing

Culture doc (CLAUDE.md) added — documents AIPass philosophy, identity,
memory system, and collaboration principles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
AIOSAI
2026-03-10 01:26:42 -07:00
co-authored by Claude Opus 4.6
parent 09e759a8a4
commit babedd9c64
589 changed files with 17140 additions and 24881 deletions
+39 -6
View File
@@ -1,6 +1,17 @@
# Trigger
Event bus for AIPass. Branches fire events, registered handlers react. Decouples producers from consumers — the module that detects a condition doesn't need to know what should happen next.
**Purpose:** Event bus for AIPass. Branches fire events, registered handlers react. Decouples producers from consumers — the module that detects a condition doesn't need to know what should happen next.
**Module:** `aipass.trigger`
**Last Updated:** 2026-03-08
## Commands / Usage
```bash
drone @trigger fire <event> [data] # Fire an event
drone @trigger list # List registered events
drone @trigger status # Event bus status
drone @trigger --help # Full help
```
## Usage
@@ -74,12 +85,34 @@ Built-in error monitoring subsystem. Watches logs for errors, fingerprints them
```
trigger/
├── apps/
│ ├── trigger.py # Entry point (auto-discovers modules)
│ ├── trigger.py # Entry point (auto-discovers modules)
│ ├── modules/
│ │ ├── core.py # Event bus (Trigger.fire/on/off)
│ │ ├── errors.py # Error registry + cross-branch API
│ │ └── medic.py # Error monitoring commands
│ │ ├── core.py # Event bus (Trigger.fire/on/off)
│ │ ├── errors.py # Error registry + cross-branch API
│ │ ├── medic.py # Error monitoring commands
│ │ ├── branch_log_events.py # Branch-level log event handling
│ │ └── log_events.py # System-wide log event processing
│ └── handlers/
│ └── events/ # One handler per event type
│ └── events/ # One handler per event type
└── tests/
```
**Note:** `branch_log_events` and `log_events` are auto-discovered modules that handle log-based event detection at branch and system levels respectively.
---
## Integration Points
### Depends On
- `aipass.prax` — Logging via `system_logger`
- `aipass.cli` — Console output and header formatting
- Python stdlib (`sys`, `pathlib`, `importlib`)
### Provides To
- All modules — event bus (`Trigger.fire`, `Trigger.on`, `Trigger.off`)
- All modules — cross-branch error reporting (`report_error`)
- All modules — medic error monitoring and dispatch
---
*Last Updated: 2026-03-08*
+8
View File
@@ -1,3 +1,11 @@
# =================== AIPass ====================
# Name: config.py
# Description: Trigger package path configuration
# Version: 1.0.0
# Created: 2026-03-09
# Modified: 2026-03-09
# =============================================
"""
Trigger package path configuration.
@@ -1,25 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: error_registry.py - Error Registry Handler
# Date: 2026-02-25
# =================== AIPass ====================
# Name: error_registry.py
# Description: Structured error tracking and registry for Medic v2
# Version: 2.3.0
# Category: trigger/handlers
#
# CHANGELOG (Max 5 entries):
# - v2.4.0 (2026-02-27): FPLAN-0382 Phase 3 - Migrate stdlib logging to Prax direct_log() (no-event pipeline)
# - v2.3.0 (2026-02-25): FPLAN-0371 Phase 5 - Persist circuit breaker state to trigger_config.json, add logging to silent failure paths
# - v2.2.0 (2026-02-25): FPLAN-0371 Phase 2 - User-error rejection layer in report() (auto-suppress unknown commands, invalid args)
# - v2.1.0 (2026-02-13): Phase 5 - Source fix pipeline (update_source_fix_status)
# - v2.0.0 (2026-02-13): Phase 2 - Circuit breaker + per-fingerprint rate limiting
# - v1.0.0 (2026-02-13): Created - Medic v2 Phase 1 error registry foundation
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - NO console.print() - handlers return data to modules
# - Uses Prax direct_log() (no event pipeline) to avoid recursion
# - Self-contained - no imports from other trigger modules
# - JSON file-based storage for error registry
# Created: 2026-02-13
# Modified: 2026-02-27
# =============================================
"""
@@ -0,0 +1,167 @@
# =================== AIPass ====================
# Name: error_reporter.py
# Description: Error reporting handler for registry and source fix email
# Version: 1.0.0
# Created: 2026-03-08
# Modified: 2026-03-08
# =============================================
"""
Error Reporting Handler
Contains the core logic for reporting errors to the registry and
dispatching error_detected events. Also handles source fix email
pipeline for suppressed errors.
Purpose:
Implementation logic for error reporting, separated from CLI/display
layer to satisfy thin-module standard.
"""
from aipass.prax import logger
# logger imported from aipass.prax
from aipass.trigger.apps.handlers.error_registry import (
report as _registry_report,
)
def send_source_fix_email(entry: dict) -> bool:
"""Send recommendation email to source branch about fixing log level.
When an error is suppressed, the source branch gets notified that
their log level may be wrong. This closes the loop:
error -> investigate -> suppress -> fix source -> error stops
Args:
entry: Error registry entry dict
Returns:
True if email sent successfully
"""
try:
from aipass.ai_mail.apps.modules.email import send_email_direct
except ImportError:
logger.info("[ERRORS] Could not import send_email_direct - ai_mail not available")
return False
try:
component = entry.get("component", "").lower()
if not component or component == "unknown":
return False
recipient = f"@{component}"
fingerprint = entry.get("fingerprint", "")[:12]
error_type = entry.get("error_type", "?")
message = entry.get("message", "?")[:200]
suppress_reason = entry.get("suppress_reason", "No reason")
log_path = entry.get("log_path", "unknown")
count = entry.get("count", 0)
subject = f"[LOG FIX] {error_type} classified as non-critical"
body = f"""Your code is generating an error that has been classified as non-critical.
Error fingerprint: {fingerprint}
Error type: {error_type}
Occurrences: {count}
Log file: {log_path}
Suppress reason: {suppress_reason}
Error message:
{message}
RECOMMENDATION:
This error is currently logged as ERROR but appears to be non-critical based on
investigation. Consider one of:
1. Change the log level from ERROR to WARNING or INFO
2. Add proper error handling to prevent this from being logged
3. If this is actually critical, reply to @trigger explaining why
This will prevent unnecessary error dispatch for this issue.
---
Automated recommendation from Medic v2 Error Registry.
Reply to @trigger with your fix status."""
send_email_direct(
to_branch=recipient,
subject=subject,
message=body,
reply_to='@trigger',
from_branch='@trigger'
)
logger.info(f"[ERRORS] Source fix email sent to {recipient} for {fingerprint}")
return True
except Exception as exc:
logger.info(f"[ERRORS] Failed to send source fix email: {exc}")
return False
def report_error(
error_type: str,
message: str,
component: str,
log_path: str = "",
severity: str = "medium",
fire_event: bool = True
) -> dict:
"""Report an error to the registry and optionally fire error_detected event.
Public API for cross-branch push reporting. Drone and other branches
call this instead of importing from handlers directly.
Pipeline: report() -> registry stores -> fire event -> handler checks
circuit breaker + rate limiting -> dispatch email if allowed.
Args:
error_type: Error class name (e.g., 'ImportError', 'TimeoutError')
message: Original error message text
component: Branch that generated the error (e.g., 'FLOW', 'API')
log_path: Path to source log file (optional)
severity: Error severity - low, medium, high, critical (default: medium)
fire_event: Whether to fire error_detected event (default: True).
Set False for silent registration without dispatch.
Returns:
Dict with error entry data + 'is_new' bool + 'dispatched' bool.
"""
result = _registry_report(
error_type=error_type,
message=message,
component=component,
log_path=log_path,
severity=severity,
)
result["dispatched"] = False
# Fire event on first occurrence (count==1) for registration and on
# second occurrence (count==2) so the handler can apply the dispatch
# threshold. Skip all other counts (backoff handles later dispatches).
error_count = result.get("count", 1)
if not fire_event or (not result.get("is_new", False) and error_count != 2):
return result
try:
from aipass.trigger.apps.modules.core import trigger as _trigger_bus
_trigger_bus.fire(
"error_detected",
branch=component,
module=error_type,
message=message,
log_path=log_path,
error_hash=result.get("id", ""),
timestamp=result.get("last_seen", ""),
fingerprint=result.get("fingerprint", ""),
registry_id=result.get("id", ""),
first_seen=result.get("first_seen", ""),
last_seen=result.get("last_seen", ""),
count=error_count,
)
result["dispatched"] = True
except Exception:
pass
return result
@@ -1,19 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: bulletin_created.py - Bulletin Created Event Handler
# Date: 2026-01-31
# =================== AIPass ====================
# Name: bulletin_created.py
# Description: Bulletin created event handler for dashboard propagation
# Version: 1.0.0
# Category: trigger/handlers/events
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2026-01-31): Created - Phase 3 migration (FPLAN-0280)
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - NO logger imports (causes infinite recursion in event handlers)
# - NO print statements (handlers must be silent)
# - Silent failure - catch all exceptions, pass
# Created: 2026-01-31
# Modified: 2026-01-31
# =============================================
"""
+5 -13
View File
@@ -1,17 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: cli.py - CLI Event Handler
# Date: 2025-12-04
# =================== AIPass ====================
# Name: cli.py
# Description: CLI event handler for header display events
# Version: 0.1.0
# Category: trigger/handlers/events
#
# CHANGELOG (Max 5 entries):
# - v0.1.0 (2025-12-04): Created CLI event handler
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - Handlers must not import Prax logger
# Created: 2025-12-04
# Modified: 2025-12-04
# =============================================
"""CLI Event Handler - Handle CLI display events"""
@@ -1,26 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: error_detected.py - Error Detected Event Handler
# Date: 2026-02-14
# =================== AIPass ====================
# Name: error_detected.py
# Description: Error detected event handler with Medic v2 dispatch gating
# Version: 2.1.0
# Category: trigger/handlers/events
#
# CHANGELOG (Max 5 entries):
# - v2.1.0 (2026-02-14): Dispatch threshold - count >= 2 required (skip first occurrence)
# - v2.0.0 (2026-02-13): Medic v2 Phase 3 - Circuit breaker + per-fingerprint backoff dispatch
# - v1.3.0 (2026-02-12): Medic Phase 2 - per-branch mute/unmute check
# - v1.2.0 (2026-02-12): Medic toggle - check medic_enabled before dispatching
# - v1.1.1 (2026-02-10): Add Seed standards reminder to error dispatch template
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - NO console.print() - handlers return data to modules
# - NO logger calls in handler (causes recursion with trigger)
# - Silent failure pattern - catch all exceptions
# - Responds to error_detected events from Trigger's log_watcher
# - Dispatch threshold: count >= 2 required (first occurrence is silent)
# - Dispatch gating: circuit breaker (global) + per-fingerprint backoff (Medic v2)
# Created: 2026-02-10
# Modified: 2026-02-14
# =============================================
"""
@@ -1,24 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: error_logged.py - Error Logged Event Handler (DEPRECATED)
# Date: 2026-01-31
# =================== AIPass ====================
# Name: error_logged.py
# Description: Legacy error logged event handler with medic gating (deprecated)
# Version: 2.0.0
# Category: trigger/handlers/events
#
# CHANGELOG (Max 5 entries):
# - v2.0.0 (2026-02-25): FPLAN-0371 Phase 1 - Add medic gating, DEV_CENTRAL protection, rate limiting
# - v1.0.2 (2026-02-06): Validate target branch exists before delivery (fixes @telegram spam)
# - v1.0.1 (2026-02-03): Fixed cross-branch import - uses module API instead of handler
# - v1.0.0 (2026-01-31): Created - Phase 2 migration (FPLAN-0279)
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - NO logger imports (causes infinite recursion in event handlers)
# - NO print statements (handlers must be silent)
# - Silent failure - catch all exceptions, pass
# - DEPRECATED: error_detected.py (Medic v2) is the primary error dispatch handler
# - This handler remains for backward compat with code that fires error_logged events
# Created: 2026-01-31
# Modified: 2026-02-25
# =============================================
"""
@@ -1,18 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: memory.py - Memory Event Handler
# Date: 2025-12-04
# =================== AIPass ====================
# Name: memory.py
# Description: Memory event handler placeholder for future rollover triggers
# Version: 0.1.0
# Category: trigger/handlers/events
#
# CHANGELOG (Max 5 entries):
# - v0.1.0 (2025-12-04): Created memory event handler placeholder
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - Placeholder for future memory event handling
# - Handlers must not import Prax logger
# Created: 2025-12-04
# Modified: 2025-12-04
# =============================================
"""Memory Event Handler - Handle memory-related events
@@ -1,21 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: memory_template_updated.py - Memory Template Updated Event Handler
# Date: 2026-02-14
# =================== AIPass ====================
# Name: memory_template_updated.py
# Description: Memory template updated event handler for branch push
# Version: 1.0.0
# Category: trigger/handlers/events
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2026-02-14): Created - Phase 3 of FPLAN-0340
# * Handles memory_template_updated event
# * Pushes living template updates to all branches
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - NO logger imports (causes infinite recursion in event handlers)
# - NO print statements (handlers must be silent)
# - Silent failure - catch all exceptions, pass
# Created: 2026-02-14
# Modified: 2026-02-14
# =============================================
"""
@@ -1,19 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: memory_threshold_exceeded.py - Memory Threshold Exceeded Event Handler
# Date: 2026-01-31
# =================== AIPass ====================
# Name: memory_threshold_exceeded.py
# Description: Memory threshold exceeded event handler for compression notifications
# Version: 1.0.0
# Category: trigger/handlers/events
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2026-01-31): Created - Phase 3 migration (FPLAN-0280)
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - NO logger imports (causes infinite recursion in event handlers)
# - NO print statements (handlers must be silent)
# - Silent failure - catch all exceptions, pass
# Created: 2026-01-31
# Modified: 2026-01-31
# =============================================
"""
@@ -1,19 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: plan_file.py - PLAN file event handlers
# Date: 2026-01-20
# =================== AIPass ====================
# Name: plan_file.py
# Description: PLAN file event handlers for registry updates
# Version: 1.0.0
# Category: trigger/handlers/events
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2026-01-20): Migrated from Flow's registry_monitor.py
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - Handles plan_file_created, plan_file_deleted, plan_file_moved events
# - Updates Flow's registry when PLAN files change
# - No Prax logger imports (handler independence)
# Created: 2026-01-20
# Modified: 2026-01-20
# =============================================
"""
@@ -1,18 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: registry.py - Event Handler Registry
# Date: 2025-12-04
# =================== AIPass ====================
# Name: registry.py
# Description: Event handler registry for startup registration
# Version: 0.1.0
# Category: trigger/handlers/events
#
# CHANGELOG (Max 5 entries):
# - v0.1.0 (2025-12-04): Created event handler registry
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - Registers all event handlers on startup
# - Event-based trigger system
# Created: 2025-12-04
# Modified: 2025-12-04
# =============================================
"""Event Handler Registry - Setup all event handlers on startup"""
@@ -1,21 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: startup.py - Startup Event Handler
# Date: 2026-02-03
# =================== AIPass ====================
# Name: startup.py
# Description: Startup event handler with error catch-up scanning
# Version: 1.0.0
# Category: trigger/handlers/events
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2026-02-26): DPLAN-037 - Add MAX_ERRORS, MAX_FILE_SIZE, time budget to error catchup
# - v0.2.0 (2026-02-03): Added error catch-up on startup
# - v0.1.0 (2025-12-04): Created startup event handler
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - Replaces Prax logger's hardcoded calls with event-based approach
# - Handlers must not import Prax logger
# - Handlers receive fire_event callback via kwargs (no module imports)
# Created: 2025-12-04
# Modified: 2026-02-26
# =============================================
"""Startup Event Handler - Run startup checks
@@ -1,19 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: warning_logged.py - Warning Logged Event Handler
# Date: 2026-01-31
# =================== AIPass ====================
# Name: warning_logged.py
# Description: Warning logged event handler for monitoring hooks
# Version: 1.0.0
# Category: trigger/handlers/events
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2026-01-31): Created - Phase 2 migration (FPLAN-0279)
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - NO logger imports (causes infinite recursion in event handlers)
# - NO print statements (handlers must be silent)
# - Silent failure - catch all exceptions, pass
# Created: 2026-01-31
# Modified: 2026-01-31
# =============================================
"""
@@ -1,18 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: json_handler.py - JSON Auto-Creating Handler
# Date: 2025-11-21
# =================== AIPass ====================
# Name: json_handler.py
# Description: JSON auto-creating handler for trigger data files
# Version: 1.1.0
# Category: trigger/handlers/json
#
# CHANGELOG (Max 5 entries):
# - v1.1.0 (2025-11-21): Refactored to comply with error handling
# - v1.0.0 (2025-11-13): Initial JSON auto-creation system
#
# CODE STANDARDS:
# - Pure functions with proper error raising
# - No Prax imports (handler tier 3)
# Created: 2025-11-13
# Modified: 2025-11-21
# =============================================
import json
@@ -1,28 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: log_watcher.py - Branch Log Watcher Event Producer
# Date: 2026-02-25
# =================== AIPass ====================
# Name: log_watcher.py
# Description: Branch log watcher event producer for error detection
# Version: 2.3.0
# Category: trigger/handlers
#
# CHANGELOG (Max 5 entries):
# - v2.4.0 (2026-02-27): FPLAN-0382 Phase 3 - Migrate stdlib logging to Prax direct_log() (no-event pipeline)
# - v2.3.0 (2026-02-25): FPLAN-0371 Phase 5 - Add logging when _fire_event callback is None (silent failure path)
# - v2.2.0 (2026-02-25): FPLAN-0371 Phase 2 - False positive elimination: strict parser, semantic exclusion, case-insensitive excludes, stale default
# - v2.1.0 (2026-02-23): Fix false positives - persist positions, exclude self-referential logs, timestamp guard
# - v2.0.0 (2026-02-13): Medic v2 Phase 3 - Registry-based dedup via error_registry.report()
# - v1.0.1 (2026-02-10): FPLAN-0310 Phase 2 - Persist dedup hashes to trigger_data.json, increase max to 2000
# - v1.0.0 (2026-02-02): Created - FPLAN-0284 Phase 1
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - NO console.print() - handlers return data to modules
# - Uses Prax direct_log() (no event pipeline) to avoid recursion
# - Fires error_detected events when ERROR entries found in branch logs
# - Primary dedup path: error_registry.report() (Medic v2)
# - Fallback dedup: MD5 hash-based (Medic v1, kept for backward compat)
# - Dispatch threshold: fires event on count==1 (register) AND count==2 (dispatch)
# Created: 2026-02-02
# Modified: 2026-02-27
# =============================================
"""
@@ -1,19 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: medic_state.py - Medic State Handler
# Date: 2026-02-12
# =================== AIPass ====================
# Name: medic_state.py
# Description: Medic state persistence and status collection handler
# Version: 1.1.0
# Category: trigger/handlers
#
# CHANGELOG (Max 5 entries):
# - v1.1.0 (2026-02-12): Added mute/unmute per-branch support (Phase 2)
# - v1.0.0 (2026-02-12): Created - Medic state persistence and status collection
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - NO console.print() - handlers return data to modules
# - Handles file I/O for medic config and status
# Created: 2026-02-12
# Modified: 2026-02-12
# =============================================
"""
@@ -1,19 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: log_watcher.py - Centralized Log File Watcher
# Date: 2026-01-31
# =================== AIPass ====================
# Name: log_watcher.py
# Description: Centralized log file watcher for system_logs directory
# Version: 1.0.0
# Category: trigger/handlers/watchers
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2026-01-31): Created - Phase 2 migration from Prax/AI_Mail
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - Centralized log watching for entire system
# - Fires events: error_logged, warning_logged, log_entry
# - All log watching moves to Trigger, other branches respond to events
# Created: 2026-01-31
# Modified: 2026-01-31
# =============================================
"""
@@ -35,13 +25,13 @@ Architecture:
import sys
import hashlib
import logging
from aipass.prax import logger
from datetime import datetime
from pathlib import Path
from typing import Dict, Any
# Logger - use standard logging to avoid circular imports with Prax
logger = logging.getLogger(__name__)
# Logger - use prax system_logger for Error_Handling and Log_Visibility standards
# logger imported from aipass.prax
# System logs directory (package-relative via config)
from aipass.trigger.apps.config import TRIGGER_ROOT
@@ -1,18 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: branch_log_events.py - Branch Log Events Module
# Date: 2026-02-02
# =================== AIPass ====================
# Name: branch_log_events.py
# Description: Branch log events module for log watcher public API
# Version: 1.0.0
# Category: trigger/modules
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2026-02-02): Created - FPLAN-0284 Phase 4
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - Module orchestrates, handlers contain logic
# - Public API for branch log event watching
# Created: 2026-02-02
# Modified: 2026-02-02
# =============================================
"""
@@ -44,6 +35,29 @@ from aipass.trigger.apps.handlers.log_watcher import (
from aipass.trigger.apps.config import AIPASS_PKG_ROOT
def print_introspection():
"""Display module introspection info."""
try:
from aipass.cli.apps.modules.display import console
except ImportError:
from rich.console import Console
console = Console()
console.print()
console.print("branch_log_events Module")
console.print("Branch log watcher — watches branch logs for ERROR entries and fires events")
console.print()
console.print("Connected Handlers:")
console.print(" handlers/")
console.print(" - log_watcher.py (set_event_callback — set callback for detected events)")
console.print(" - log_watcher.py (start_branch_log_watcher — start filesystem watcher)")
console.print(" - log_watcher.py (stop_branch_log_watcher — stop filesystem watcher)")
console.print(" - log_watcher.py (is_branch_log_watcher_active — check watcher state)")
console.print(" - log_watcher.py (get_watcher_status — get full status dict)")
console.print(" - log_watcher.py (clear_seen_hashes — reset error deduplication)")
console.print()
def start() -> bool:
"""
Start the branch log watcher.
+100 -20
View File
@@ -1,21 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: core.py - Trigger Event Bus
# Date: 2026-02-03
# =================== AIPass ====================
# Name: core.py
# Description: Trigger event bus for AIPass system-wide event handling
# Version: 1.2.0
# Category: trigger/modules
#
# CHANGELOG (Max 5 entries):
# - v1.2.0 (2026-02-03): Add deferred queue for nested event firing (fixes catch-up blocking)
# - v1.1.4 (2026-02-03): Pass fire_event callback to handlers (enables error catch-up)
# - v1.1.3 (2026-02-03): Disable lazy-start watchers entirely (inotify exhaustion - use prax monitor)
# - v1.1.2 (2026-02-03): Also start system log watcher (fixes missing system_logs monitoring)
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - Event bus pattern for system-wide events
# - Lazy-start pattern from Prax logger
# Created: 2026-02-03
# Modified: 2026-02-03
# =============================================
"""
@@ -34,6 +22,24 @@ from aipass.prax.apps.modules.logger import system_logger as logger
from typing import Callable
def print_introspection():
"""Display module introspection info."""
try:
from aipass.cli.apps.modules.display import console
except ImportError:
from rich.console import Console
console = Console()
console.print()
console.print("core Module")
console.print("Trigger event bus — fire events, register handlers, deferred queue processing")
console.print()
console.print("Connected Handlers:")
console.print(" handlers/events/")
console.print(" - registry.py (setup_handlers — auto-register all event handlers on first use)")
console.print()
def _get_caller() -> str:
"""Get the calling module/file name"""
stack = inspect.stack()
@@ -123,9 +129,6 @@ class Trigger:
cls._ensure_initialized()
cls._ensure_log_watcher()
handlers = cls._handlers.get(event, [])
caller = _get_caller()
logger.info(f"[TRIGGER] {caller} fired: {event}")
logger.info(f"[TRIGGER] {len(handlers)} handlers responding")
# Provide fire_event callback so handlers can fire events without importing
data['fire_event'] = cls.fire
@@ -166,5 +169,82 @@ class Trigger:
return {event: len(handlers) for event, handlers in cls._handlers.items()}
def handle_command(command: str, args: list) -> bool:
"""Handle commands routed by the entry point.
Commands:
fire <event> [key=value ...] - Fire an event with optional data
status - Show registered event handlers
list - Alias for status
Args:
command: Command to execute (fire, status, list)
args: Additional arguments
Returns:
True if command was handled, False otherwise
"""
from aipass.cli.apps.modules import console
if command not in ["fire", "status", "list"]:
return False
if args and args[0] in ['--help', '-h', 'help']:
_print_help(console)
return True
if command == "fire":
if not args:
console.print("[red]Usage: drone @trigger fire <event> [key=value ...][/red]")
return True
event_name = args[0]
# Parse key=value pairs from remaining args
data = {}
for arg in args[1:]:
if "=" in arg:
key, value = arg.split("=", 1)
data[key] = value
else:
logger.warning(f"[TRIGGER] Ignoring unparseable arg: {arg}")
Trigger.fire(event_name, **data)
console.print(f"[green]Fired event:[/green] {event_name}")
if data:
for k, v in data.items():
console.print(f" [dim]{k}={v}[/dim]")
return True
elif command in ["status", "list"]:
handler_map = Trigger.status()
if not handler_map:
console.print("[dim]No event handlers registered[/dim]")
return True
console.print("[bold cyan]Registered Event Handlers[/bold cyan]")
console.print()
for event, count in sorted(handler_map.items()):
console.print(f" [green]{event:30}[/green] {count} handler(s)")
console.print()
console.print(f"[dim]Total: {len(handler_map)} events, "
f"{sum(handler_map.values())} handlers[/dim]")
return True
return False
def _print_help(console):
"""Display help for core trigger commands."""
console.print()
console.print("[bold cyan]TRIGGER CORE - Event Bus[/bold cyan]")
console.print()
console.print("[bold]COMMANDS:[/bold]")
console.print(" fire <event> [key=value ...] Fire an event with optional data")
console.print(" status Show registered event handlers")
console.print(" list Alias for status")
console.print()
console.print("[bold]EXAMPLES:[/bold]")
console.print(" drone @trigger fire deploy_complete branch=main")
console.print(" drone @trigger status")
console.print()
# Create instance for import
trigger = Trigger()
+33 -157
View File
@@ -1,20 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: errors.py - Error Registry Management Module
# Date: 2026-02-13
# Version: 1.2.0
# Category: trigger/modules
#
# CHANGELOG (Max 5 entries):
# - v1.2.0 (2026-02-14): Public API report_error() for cross-branch push reporting
# - v1.1.0 (2026-02-13): Phase 5 - Source fix pipeline (email + fix status tracking)
# - v1.0.0 (2026-02-13): Created - Phase 4 Medic v2 management commands
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - Module orchestrates, handler (error_registry.py) contains data logic
# - No direct file operations - delegates to handler
# =================== AIPass ====================
# Name: errors.py
# Description: Error registry management module for Medic v2 commands
# Version: 1.3.0
# Created: 2026-02-13
# Modified: 2026-03-08
# =============================================
"""
@@ -41,74 +30,38 @@ from aipass.trigger.apps.handlers.error_registry import (
query, get_entry, update_status, clear_resolved, get_stats,
get_circuit_breaker_status, circuit_breaker_reset,
update_source_fix_status,
report as _registry_report,
)
from aipass.trigger.apps.handlers.error_reporter import (
report_error,
send_source_fix_email as _send_source_fix_email,
)
def report_error(
error_type: str,
message: str,
component: str,
log_path: str = "",
severity: str = "medium",
fire_event: bool = True
) -> dict:
"""Report an error to the registry and optionally fire error_detected event.
Public API for cross-branch push reporting. Drone and other branches
call this instead of importing from handlers directly.
Pipeline: report() -> registry stores -> fire event -> handler checks
circuit breaker + rate limiting -> dispatch email if allowed.
Args:
error_type: Error class name (e.g., 'ImportError', 'TimeoutError')
message: Original error message text
component: Branch that generated the error (e.g., 'FLOW', 'API')
log_path: Path to source log file (optional)
severity: Error severity - low, medium, high, critical (default: medium)
fire_event: Whether to fire error_detected event (default: True).
Set False for silent registration without dispatch.
Returns:
Dict with error entry data + 'is_new' bool + 'dispatched' bool.
"""
result = _registry_report(
error_type=error_type,
message=message,
component=component,
log_path=log_path,
severity=severity,
)
result["dispatched"] = False
# Fire event on first occurrence (count==1) for registration and on
# second occurrence (count==2) so the handler can apply the dispatch
# threshold. Skip all other counts (backoff handles later dispatches).
error_count = result.get("count", 1)
if not fire_event or (not result.get("is_new", False) and error_count != 2):
return result
def print_introspection():
"""Display module introspection info."""
try:
from aipass.trigger.apps.modules.core import trigger as _trigger_bus
_trigger_bus.fire(
"error_detected",
branch=component,
module=error_type,
message=message,
log_path=log_path,
error_hash=result.get("id", ""),
timestamp=result.get("last_seen", ""),
fingerprint=result.get("fingerprint", ""),
registry_id=result.get("id", ""),
first_seen=result.get("first_seen", ""),
last_seen=result.get("last_seen", ""),
count=error_count,
)
result["dispatched"] = True
except Exception:
pass
from aipass.cli.apps.modules.display import console
except ImportError:
from rich.console import Console
console = Console()
return result
console.print()
console.print("errors Module")
console.print("Error registry management — view, filter, suppress, and resolve tracked errors")
console.print()
console.print("Connected Handlers:")
console.print(" handlers/")
console.print(" - error_registry.py (query — search/filter error entries)")
console.print(" - error_registry.py (get_entry — get single error by fingerprint)")
console.print(" - error_registry.py (update_status — change error status)")
console.print(" - error_registry.py (clear_resolved — purge old resolved entries)")
console.print(" - error_registry.py (get_stats — summary statistics)")
console.print(" - error_registry.py (get_circuit_breaker_status — circuit breaker state)")
console.print(" - error_registry.py (circuit_breaker_reset — reset circuit breaker)")
console.print(" - error_registry.py (update_source_fix_status — update fix tracking)")
console.print(" - error_reporter.py (report_error — cross-branch push error reporting)")
console.print(" - error_reporter.py (send_source_fix_email — notify branch to fix error)")
console.print()
_STATUS_COLORS = {"new": "yellow", "investigating": "cyan", "suppressed": "dim", "resolved": "green"}
@@ -222,83 +175,6 @@ def handle_command(command: str, args: list) -> bool:
return True
# ---------------------------------------------------------------------------
# Source Fix Pipeline
# ---------------------------------------------------------------------------
def _send_source_fix_email(entry: dict) -> bool:
"""Send recommendation email to source branch about fixing log level.
When an error is suppressed, the source branch gets notified that
their log level may be wrong. This closes the loop:
error -> investigate -> suppress -> fix source -> error stops
Args:
entry: Error registry entry dict
Returns:
True if email sent successfully
"""
try:
from aipass.ai_mail.apps.modules.email import send_email_direct
except ImportError:
logger.info("[ERRORS] Could not import send_email_direct - ai_mail not available")
return False
try:
component = entry.get("component", "").lower()
if not component or component == "unknown":
return False
recipient = f"@{component}"
fingerprint = entry.get("fingerprint", "")[:12]
error_type = entry.get("error_type", "?")
message = entry.get("message", "?")[:200]
suppress_reason = entry.get("suppress_reason", "No reason")
log_path = entry.get("log_path", "unknown")
count = entry.get("count", 0)
subject = f"[LOG FIX] {error_type} classified as non-critical"
body = f"""Your code is generating an error that has been classified as non-critical.
Error fingerprint: {fingerprint}
Error type: {error_type}
Occurrences: {count}
Log file: {log_path}
Suppress reason: {suppress_reason}
Error message:
{message}
RECOMMENDATION:
This error is currently logged as ERROR but appears to be non-critical based on
investigation. Consider one of:
1. Change the log level from ERROR to WARNING or INFO
2. Add proper error handling to prevent this from being logged
3. If this is actually critical, reply to @trigger explaining why
This will prevent unnecessary error dispatch for this issue.
---
Automated recommendation from Medic v2 Error Registry.
Reply to @trigger with your fix status."""
send_email_direct(
to_branch=recipient,
subject=subject,
message=body,
reply_to='@trigger',
from_branch='@trigger'
)
logger.info(f"[ERRORS] Source fix email sent to {recipient} for {fingerprint}")
return True
except Exception as exc:
logger.info(f"[ERRORS] Failed to send source fix email: {exc}")
return False
# ---------------------------------------------------------------------------
# Command implementations
# ---------------------------------------------------------------------------
+26 -14
View File
@@ -1,18 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: log_events.py - Log Events Module
# Date: 2026-01-31
# =================== AIPass ====================
# Name: log_events.py
# Description: Log events module for centralized log watcher public API
# Version: 1.0.0
# Category: trigger/modules
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2026-01-31): Created - Phase 2 migration (FPLAN-0279)
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - Module orchestrates, handlers contain logic
# - Public API for log event watching
# Created: 2026-01-31
# Modified: 2026-01-31
# =============================================
"""
@@ -40,6 +31,27 @@ from aipass.trigger.apps.handlers.watchers.log_watcher import (
)
def print_introspection():
"""Display module introspection info."""
try:
from aipass.cli.apps.modules.display import console
except ImportError:
from rich.console import Console
console = Console()
console.print()
console.print("log_events Module")
console.print("Centralized log watcher — watches system_logs/ for error and warning events")
console.print()
console.print("Connected Handlers:")
console.print(" handlers/watchers/")
console.print(" - log_watcher.py (start_log_watcher — start centralized log watcher)")
console.print(" - log_watcher.py (stop_log_watcher — stop centralized log watcher)")
console.print(" - log_watcher.py (is_log_watcher_active — check if watcher is running)")
console.print(" - log_watcher.py (SYSTEM_LOGS_DIR — monitored log directory path)")
console.print()
def start() -> bool:
"""
Start the centralized log watcher.
+29 -18
View File
@@ -1,22 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: medic.py - Medic Toggle Module
# Date: 2026-03-01
# =================== AIPass ====================
# Name: medic.py
# Description: Medic toggle module for auto-healing error dispatch control
# Version: 1.4.0
# Category: trigger/modules
#
# CHANGELOG (Max 5 entries):
# - v1.4.0 (2026-03-01): Persistent watcher via systemd service (trigger-log-watcher.service)
# - v1.3.0 (2026-02-25): FPLAN-0371 Phase 5 - Rich Panel formatting for on/off/mute/unmute output
# - v1.2.0 (2026-02-12): Improved status wording: standby vs stopped, added explanation lines
# - v1.1.0 (2026-02-12): Added mute/unmute per-branch commands (Phase 2)
# - v1.0.0 (2026-02-12): Created - Medic on/off/status toggle for error dispatch
#
# CODE STANDARDS:
# - Follows AIPass Seed standards
# - Module orchestrates, handler (medic_state.py) contains logic
# - No direct file operations - delegates to handler
# Created: 2026-02-12
# Modified: 2026-03-01
# =============================================
"""
@@ -51,6 +38,30 @@ from aipass.trigger.apps.handlers.medic_state import (
SERVICE_NAME = "trigger-log-watcher.service"
def print_introspection():
"""Display module introspection info."""
try:
from aipass.cli.apps.modules.display import console
except ImportError:
from rich.console import Console
console = Console()
console.print()
console.print("medic Module")
console.print("Medic toggle — control auto-healing error dispatch on/off/mute/unmute")
console.print()
console.print("Connected Handlers:")
console.print(" handlers/")
console.print(" - medic_state.py (is_enabled — check if medic is enabled)")
console.print(" - medic_state.py (set_enabled — toggle medic on/off)")
console.print(" - medic_state.py (get_muted_branches — list muted branches)")
console.print(" - medic_state.py (mute_branch — suppress dispatch for a branch)")
console.print(" - medic_state.py (unmute_branch — resume dispatch for a branch)")
console.print(" - medic_state.py (get_suppression_stats — suppression statistics)")
console.print(" - medic_state.py (get_rate_limit_stats — rate limit statistics)")
console.print()
def _systemctl(action: str) -> bool:
"""Run systemctl --user action on the log watcher service.
+7 -14
View File
@@ -1,16 +1,9 @@
# ===================AIPASS====================
# META DATA HEADER
# Name: trigger.py - TRIGGER Branch Entry Point
# Date: 2025-11-30
# =================== AIPass ====================
# Name: trigger.py
# Description: Entry point CLI for drone @trigger — event bus and error registry
# Version: 1.0.0
# Category: trigger
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2025-11-30): Initial branch creation
#
# CODE STANDARDS:
# - Handlers implement logic, modules orchestrate
# Created: 2026-03-08
# Modified: 2026-03-08
# =============================================
"""
@@ -70,9 +63,9 @@ def discover_modules() -> List[Any]:
# Check if module has handle_command function
if hasattr(module, 'handle_command'):
modules.append(module)
logger.info(f"[TRIGGER] Loaded module: {file_path.stem}")
pass # Module loaded successfully
else:
logger.info(f"[TRIGGER] Skipped {file_path.stem} - no handle_command()")
pass # No handle_command() - skip silently
except Exception as e:
logger.error(f"[TRIGGER] Failed to load module {module_name}: {e}")
View File