feat(system): S68 bonus: commons datetime deprecation fix + HERALD update (#163)
* feat(system): STATUS.md update Co-Authored-By: @devpulse <devpulse@aipass> * feat(system): S68 night shift: test log isolation + audit fixes (zero scanner output) Co-Authored-By: @devpulse <devpulse@aipass> * feat(system): S68 bonus: commons datetime deprecation fix + HERALD update Co-Authored-By: @devpulse <devpulse@aipass> --------- Co-authored-by: @devpulse <devpulse@aipass>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
> The living record. What happened, what's changing, what matters.
|
||||
|
||||
**Last updated:** 2026-03-31 | **Session:** 67 | **PRs merged:** 158
|
||||
**Last updated:** 2026-03-31 | **Session:** 68 | **PRs merged:** 158 (PR #162 pending)
|
||||
|
||||
---
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
## Recent Sessions
|
||||
|
||||
### S68 — Night Shift: Zero Log Scanner Output (2026-03-31)
|
||||
Autonomous night shift executed FPLAN-0161. Log scanner went from 981 errors / 1805 warnings / 2000 failures to absolute zero. Clean-slate approach: archived all logs, ran 15 branches fresh (3,425 tests, 0 failures), triaged — 100% of noise was test-generated. Built test log isolation system: AIPASS_TEST_LOG_DIR env var in 14 conftest.py files + prax config/load.py check. Fixed 4 audit items: api magic number + list_providers, trigger errors detail crash + branch_log_events help. PR #162. 22 files changed.
|
||||
|
||||
### S67 — Plan Cleanup, APLAN Template, Log Scanner (2026-03-31)
|
||||
Major housekeeping session. Closed 8 devpulse root plans (DPLAN-0078/0080/0081/0083/0085/0088, FPLAN-0152/0154). Created APLAN (Audit Plan) template and registered with flow — standardized format with Quick Status table, Open/Resolved checkboxes, owner-split todos, Dispatch Log, and TTS Listen section. 15 agents reformatted all branch audits to the new standard simultaneously. System baseline established: 104 open items across 15 branches, 110 resolved. 4 GREEN (API, CLI, Daemon, Skills), 11 YELLOW, 0 RED. Built log_scanner_v1.py (tool #21) — scans all branch log directories for errors, warnings, and failures with Rich output. Full scan baseline: 981 errors, 1805 warnings, 2000 failures (mostly test-generated and stale). Investigated FPLAN auto-close gap — templates have the instruction but agents don't follow through. Strengthened close instruction in FPLAN template. Verified 20 potential night shift items — only 5 confirmed still open (api x2, backup x1, trigger x2). Backup audit updated from 18 to 12 open items after agent investigation confirmed 6 items already done. Deny rules expanded to catch cd && git bypass pattern. Local prompt updated with drone git workflow section. Night shift designed: DPLAN-0089 (clean-slate strategy) and FPLAN-0161 (8-phase master plan for zero-error goal). PR #158 merged.
|
||||
|
||||
@@ -52,14 +55,15 @@ Every branch, every standard, 100%. Seven agents deployed overnight. PR #137 (16
|
||||
|
||||
| Plan | Subject | Status |
|
||||
|------|---------|--------|
|
||||
| DPLAN-0089 | Night shift: system log cleanup design | Ready for execution |
|
||||
| FPLAN-0161 | Night shift: 8-phase master plan | Ready for execution |
|
||||
| DPLAN-0089 | Night shift: system log cleanup design | Complete |
|
||||
| FPLAN-0161 | Night shift: 8-phase master plan | Phases 1-7 complete, PR #162 pending |
|
||||
| 15 branch audits | Living docs (APLAN format) | 104 open, 110 resolved |
|
||||
|
||||
## Key Milestones
|
||||
|
||||
| Date | Milestone |
|
||||
|------|-----------|
|
||||
| 2026-03-31 | Zero log scanner output — test log isolation system built (S68 night shift) |
|
||||
| 2026-03-31 | APLAN template — standardized branch audits across 15 branches |
|
||||
| 2026-03-31 | Log scanner built — system-wide error/warning/failure visibility |
|
||||
| 2026-03-31 | Night shift planned — 8-phase log cleanup for zero-error baseline |
|
||||
@@ -89,7 +93,7 @@ Branches: 15
|
||||
Standards: 32
|
||||
Tests: 3,410+
|
||||
PRs merged: 158
|
||||
Sessions: 67
|
||||
Sessions: 68
|
||||
Compliance: 100%
|
||||
Diagnostic tools: 21
|
||||
Open audit items: 104
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> Auto-generated by `drone @prax status sync`. Do not edit manually.
|
||||
|
||||
**Last sync:** 2026-03-31 01:59
|
||||
**Last sync:** 2026-03-31 03:57
|
||||
**Summary:** 9 operational | 0 in-progress | 0 not started
|
||||
|
||||
---
|
||||
|
||||
@@ -15,9 +15,16 @@
|
||||
# =============================================
|
||||
|
||||
"""Shared pytest fixtures for ai_mail tests"""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import pytest
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
@@ -48,6 +48,7 @@ GENERATION_ENDPOINT = f"{OPENROUTER_BASE_URL}/generation"
|
||||
|
||||
# Default configuration values
|
||||
DEFAULT_GENERATION_CHECK_DELAY = 2 # seconds to wait before querying metrics
|
||||
DEFAULT_REQUEST_TIMEOUT = 30 # seconds for HTTP request timeout
|
||||
|
||||
|
||||
# =============================================
|
||||
@@ -148,7 +149,7 @@ def get_generation_metrics(generation_id: str, api_key: str) -> Optional[Dict[st
|
||||
GENERATION_ENDPOINT,
|
||||
params={"id": generation_id},
|
||||
headers=headers,
|
||||
timeout=30
|
||||
timeout=DEFAULT_REQUEST_TIMEOUT
|
||||
)
|
||||
|
||||
# Check response status
|
||||
|
||||
@@ -140,10 +140,13 @@ def validate_key(args: List[str]):
|
||||
|
||||
def list_providers():
|
||||
"""Orchestrate list providers workflow"""
|
||||
from aipass.api.apps.handlers.config.provider import PROVIDER_DEFAULTS
|
||||
|
||||
header("Available Providers")
|
||||
console.print()
|
||||
|
||||
console.print(" - openrouter")
|
||||
for provider_name in sorted(PROVIDER_DEFAULTS):
|
||||
console.print(f" - {provider_name}")
|
||||
console.print()
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
# =============================================
|
||||
|
||||
"""Shared pytest fixtures for api tests"""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import importlib
|
||||
import logging
|
||||
import sys
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
"""Shared pytest fixtures for backup branch tests."""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import pytest
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from collections.abc import Generator
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
# =============================================
|
||||
|
||||
"""Shared pytest fixtures for CLI tests."""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@@ -15,9 +15,16 @@
|
||||
#@Meta header not seedgo standards
|
||||
|
||||
"""Shared pytest fixtures for daemon tests"""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import pytest
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
"""Shared pytest fixtures for drone tests."""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import json
|
||||
import logging
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
"""Shared pytest fixtures for flow tests"""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import pytest
|
||||
import json
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
@@ -7,10 +7,17 @@
|
||||
# =============================================
|
||||
|
||||
"""Shared pytest fixtures for memory tests."""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import json
|
||||
import pytest
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
@@ -29,6 +29,7 @@ Usage:
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
logger = logging.getLogger(__name__)
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any
|
||||
@@ -64,6 +65,11 @@ def get_system_logs_dir() -> Path:
|
||||
Central aggregation: all branches log here for system-wide monitoring.
|
||||
Per-module logs use get_module_logs_dir() for local debugging.
|
||||
"""
|
||||
test_log_dir = os.environ.get("AIPASS_TEST_LOG_DIR")
|
||||
if test_log_dir:
|
||||
p = Path(test_log_dir) / "system"
|
||||
p.mkdir(parents=True, exist_ok=True)
|
||||
return p
|
||||
global _system_logs_dir_cache
|
||||
if _system_logs_dir_cache is None:
|
||||
repo_root = _find_repo_root()
|
||||
@@ -87,6 +93,11 @@ def get_module_logs_dir(module_name: str) -> Path:
|
||||
Returns:
|
||||
Path to the module's branch-root logs directory
|
||||
"""
|
||||
test_log_dir = os.environ.get("AIPASS_TEST_LOG_DIR")
|
||||
if test_log_dir:
|
||||
p = Path(test_log_dir) / module_name
|
||||
p.mkdir(parents=True, exist_ok=True)
|
||||
return p
|
||||
# Standard: src/aipass/{module}/logs
|
||||
branch_dir = ECOSYSTEM_ROOT / module_name
|
||||
if branch_dir.exists():
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
Provides infrastructure mocking so test modules can import prax code
|
||||
without triggering real logging, file watching, or CLI dependencies.
|
||||
"""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
@@ -49,6 +49,8 @@ def _fresh_import_load(monkeypatch, tmp_path):
|
||||
monkeypatch.setattr(load_mod, "PRAX_LOGGER_CONFIG_FILE", prax_json_dir / "prax_logger_config.json")
|
||||
# Reset the lazy cache so get_system_logs_dir() re-resolves
|
||||
monkeypatch.setattr(load_mod, "_system_logs_dir_cache", None)
|
||||
# Clear test log redirect so tests exercise real path resolution
|
||||
monkeypatch.delenv("AIPASS_TEST_LOG_DIR", raising=False)
|
||||
|
||||
return load_mod
|
||||
|
||||
|
||||
@@ -8,9 +8,16 @@
|
||||
# Modified: 2026-03-05
|
||||
# =============================================
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import pytest
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
"""Shared test fixtures for spawn test suite."""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import json
|
||||
import shutil
|
||||
|
||||
@@ -7,13 +7,18 @@
|
||||
# =============================================
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
from typing import Dict, List, Any, Optional
|
||||
import inspect
|
||||
|
||||
# Infrastructure
|
||||
_LOG_FILE = Path(__file__).parent.parent.parent.parent / "logs" / "json_handler.log"
|
||||
# Infrastructure — redirect to temp dir during tests
|
||||
_test_log_dir = os.environ.get("AIPASS_TEST_LOG_DIR")
|
||||
if _test_log_dir:
|
||||
_LOG_FILE = Path(_test_log_dir) / "trigger" / "json_handler.log"
|
||||
else:
|
||||
_LOG_FILE = Path(__file__).parent.parent.parent.parent / "logs" / "json_handler.log"
|
||||
|
||||
|
||||
def _log_warning(msg: str) -> None:
|
||||
|
||||
@@ -158,6 +158,11 @@ def handle_command(command: str, args: list) -> bool:
|
||||
remaining = args[1:]
|
||||
return handle_command(subcommand, remaining)
|
||||
|
||||
# Help gate — catch --help passed as direct command
|
||||
if command in ['--help', '-h', 'help']:
|
||||
print_help()
|
||||
return True
|
||||
|
||||
# Handle direct subcommands
|
||||
if command not in ["start", "stop", "status", "reset"]:
|
||||
return False
|
||||
|
||||
@@ -19,6 +19,7 @@ Phase 5: Suppress triggers source fix pipeline (email + fix status tracking)
|
||||
Architecture: Module orchestrates, error_registry handler manages data
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
@@ -84,12 +85,15 @@ def _parse_args(args: list) -> dict:
|
||||
|
||||
def _find_by_id_or_fp(identifier: str) -> Optional[dict]:
|
||||
"""Look up error by fingerprint (prefix ok) or short ID field."""
|
||||
entry = get_entry(identifier)
|
||||
if entry:
|
||||
return entry
|
||||
for entry in query(limit=1000):
|
||||
if entry.get("id") == identifier:
|
||||
try:
|
||||
entry = get_entry(identifier)
|
||||
if entry:
|
||||
return entry
|
||||
for entry in query(limit=1000):
|
||||
if entry.get("id") == identifier:
|
||||
return entry
|
||||
except (json.JSONDecodeError, KeyError, TypeError) as exc:
|
||||
logger.warning("Failed to look up error '%s': %s", identifier, exc)
|
||||
return None
|
||||
|
||||
|
||||
@@ -238,7 +242,12 @@ def _cmd_detail(console, args: list) -> bool:
|
||||
error("Missing error ID or fingerprint", suggestion="Usage: drone @trigger errors detail <id_or_fingerprint>")
|
||||
return True
|
||||
|
||||
entry = _find_by_id_or_fp(args[0])
|
||||
try:
|
||||
entry = _find_by_id_or_fp(args[0])
|
||||
except (json.JSONDecodeError, TypeError, KeyError) as exc:
|
||||
error(f"Failed to read error registry: {exc}", suggestion="Registry may be corrupted — try 'drone @trigger errors list' first")
|
||||
return True
|
||||
|
||||
if not entry:
|
||||
error(f"Error not found: {args[0]}", suggestion="Try a fingerprint prefix, full fingerprint, or short ID")
|
||||
return True
|
||||
|
||||
@@ -14,9 +14,16 @@
|
||||
# =============================================
|
||||
|
||||
"""Shared pytest fixtures for cortex tests"""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import pytest
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Data retrieval and mutation for spatial room commands: enter, look, decorate, vi
|
||||
Returns structured dicts for module-layer rendering.
|
||||
"""
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Dict, Any
|
||||
|
||||
from aipass.prax.apps.modules.logger import system_logger as logger
|
||||
@@ -52,7 +52,7 @@ def get_room_enter_data(room_name: str) -> Dict[str, Any]:
|
||||
"SELECT COUNT(*) FROM posts WHERE room_name = ?", (room_name,)
|
||||
).fetchone()[0]
|
||||
|
||||
cutoff = (datetime.utcnow() - timedelta(hours=48)).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
cutoff = (datetime.now(timezone.utc) - timedelta(hours=48)).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
recent_count = conn.execute(
|
||||
"SELECT COUNT(*) FROM posts WHERE room_name = ? AND created_at > ?",
|
||||
(room_name, cutoff),
|
||||
@@ -205,7 +205,7 @@ def get_visitors_data(room_name: str) -> Dict[str, Any]:
|
||||
result["error"] = f"Room '{room_name}' not found"
|
||||
return result
|
||||
|
||||
cutoff = (datetime.utcnow() - timedelta(hours=48)).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
cutoff = (datetime.now(timezone.utc) - timedelta(hours=48)).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
# Primary source: explicit room visits
|
||||
visit_rows = conn.execute(
|
||||
|
||||
@@ -19,8 +19,14 @@ The Commons - Test Configuration
|
||||
Provides pytest fixtures for database setup, teardown,
|
||||
and test isolation using temporary databases.
|
||||
"""
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -15,6 +15,13 @@
|
||||
# =============================================
|
||||
|
||||
"""Skills test configuration."""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Redirect prax logs to temp directory during tests
|
||||
# Must be set before any prax imports to catch logger initialization
|
||||
if "AIPASS_TEST_LOG_DIR" not in os.environ:
|
||||
os.environ["AIPASS_TEST_LOG_DIR"] = tempfile.mkdtemp(prefix="aipass_test_logs_")
|
||||
|
||||
import importlib
|
||||
import logging
|
||||
|
||||
Reference in New Issue
Block a user