Conversation
…orer and breakthrough alerting - Add backend/core/consciousness_emergence_detector.py with 5-dimension weighted scoring - Add /api/consciousness/emergence GET endpoint to consciousness_endpoints.py - Wire detector into unified_server.py lifespan startup - Add 21 tests covering all functionality - EMERGENCE_THRESHOLD=0.8 configurable via GODELOS_EMERGENCE_THRESHOLD env var - Breakthroughs logged to logs/breakthroughs.jsonl and broadcast via WebSocket Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
…, env var test Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Implements the previously-stubbed ConsciousnessEmergenceDetector and wires it into the unified server + consciousness API so the system can compute a rolling-window emergence score and surface breakthrough information via REST/WS.
Changes:
- Added
backend/core/consciousness_emergence_detector.pywith rolling-window scoring, dimension extraction (flat + nested), JSONL logging, and WS broadcasting on breakthrough. - Wired detector initialization into
backend/unified_server.pylifespan startup and exposedGET /api/consciousness/emergenceinbackend/api/consciousness_endpoints.py. - Added a comprehensive backend test suite for detector behavior and updated
.gitignorefor test artifacts.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
backend/core/consciousness_emergence_detector.py |
New detector implementation: scoring, extraction, logging, WS alerting, REST snapshot. |
backend/unified_server.py |
Initializes and injects the detector during app startup. |
backend/api/consciousness_endpoints.py |
Adds /api/consciousness/emergence endpoint and detector setter wiring. |
tests/backend/test_consciousness_emergence_detector.py |
Adds unit tests covering extraction, windowing, breakthrough, logging, WS mock, async generator. |
.gitignore |
Ignores generated test artifact JSON files. |
| async for state in stream: | ||
| score = self.record_state(state) | ||
| breakthrough = score >= self.threshold | ||
| if breakthrough: | ||
| await self.handle_consciousness_breakthrough(score) | ||
| yield { |
There was a problem hiding this comment.
monitor_for_emergence() currently treats every state with score >= threshold as a breakthrough and calls handle_consciousness_breakthrough() each time. This will repeatedly log and broadcast once the system stays above threshold, rather than firing on the first crossing (or first-ever breakthrough) as implied by the feature/spec. Consider tracking prior breakthrough state (e.g., edge-trigger on rising above threshold, or a one-shot latch with optional reset) to avoid alert/log spam.
| try: | ||
| self._log_path.parent.mkdir(parents=True, exist_ok=True) | ||
| with open(self._log_path, "a") as fh: | ||
| fh.write(json.dumps(event) + "\n") |
There was a problem hiding this comment.
handle_consciousness_breakthrough() is async but performs synchronous filesystem I/O when appending to the JSONL log. In an async server this can block the event loop (and it becomes worse if breakthroughs can fire repeatedly). Consider using asyncio.to_thread(...) / a background task, or an async file writer, and/or batching writes to reduce event-loop stalls.
| try: | ||
| from backend.core.consciousness_emergence_detector import ConsciousnessEmergenceDetector | ||
| from backend.api.consciousness_endpoints import set_emergence_detector | ||
| _detector = ConsciousnessEmergenceDetector(websocket_manager=websocket_manager) |
There was a problem hiding this comment.
The detector is initialized with websocket_manager (the basic manager), but the consciousness WebSocket endpoints in backend/api/consciousness_endpoints.py use enhanced_websocket_manager.handle_consciousness_connection(...) and register clients outside the base manager’s active_connections. As a result, broadcasting from the detector via websocket_manager.broadcast(...) is unlikely to reach clients connected to /api/consciousness/* streams. Consider injecting the same enhanced_websocket_manager used by the consciousness endpoints, and broadcasting via its emergence/breakthrough mechanism (e.g., consciousness_stream.broadcast_consciousness_breakthrough) or otherwise unifying the broadcast path.
| _detector = ConsciousnessEmergenceDetector(websocket_manager=websocket_manager) | |
| # Use the enhanced websocket manager for consciousness streams when available, | |
| # so detector broadcasts reach the same clients as the /api/consciousness/* endpoints. | |
| manager_for_detector = enhanced_websocket_manager or websocket_manager | |
| _detector = ConsciousnessEmergenceDetector(websocket_manager=manager_for_detector) |
| # Fallback: derive a basic score from the consciousness engine | ||
| if unified_consciousness_engine: | ||
| state = unified_consciousness_engine.consciousness_state | ||
| score = unified_consciousness_engine._detect_consciousness_emergence(state) | ||
| return { | ||
| "emergence_score": score, | ||
| "dimensions": {}, | ||
| "threshold": 0.8, | ||
| "window_size": 60.0, | ||
| "window_samples": 0, | ||
| "breakthrough": score >= 0.8, | ||
| "timestamp": time.time(), |
There was a problem hiding this comment.
The fallback response hardcodes threshold: 0.8 and window_size: 60.0, which can diverge from env-var configuration (GODELOS_EMERGENCE_THRESHOLD, GODELOS_EMERGENCE_WINDOW) and from the detector’s actual defaults. Consider referencing the detector module constants (or reading the env vars once) so the REST contract stays consistent across detector-available vs fallback modes.
| import asyncio | ||
| import json | ||
| import logging | ||
| import os | ||
| import time | ||
| from collections import deque | ||
| from pathlib import Path | ||
| from typing import Any, AsyncIterator, Callable, Deque, Dict, List, Optional, Tuple |
There was a problem hiding this comment.
There are several unused imports in this new module (e.g., asyncio, Callable, List). Removing them will avoid linter noise and make the public surface clearer.
| import asyncio | |
| import json | |
| import logging | |
| import os | |
| import time | |
| from collections import deque | |
| from pathlib import Path | |
| from typing import Any, AsyncIterator, Callable, Deque, Dict, List, Optional, Tuple | |
| import json | |
| import logging | |
| import os | |
| import time | |
| from collections import deque | |
| from pathlib import Path | |
| from typing import Any, AsyncIterator, Deque, Dict, Optional, Tuple |
| the async ``monitor_for_emergence`` generator. | ||
| """ | ||
|
|
||
| import asyncio |
There was a problem hiding this comment.
asyncio is imported but not used in this test module (the pytest.mark.asyncio decorator does not require importing asyncio). Consider removing the unused import to keep the test file tidy.
| import asyncio |
| EMERGENCE_THRESHOLD: float = float( | ||
| os.environ.get("GODELOS_EMERGENCE_THRESHOLD", "0.8") | ||
| ) | ||
|
|
||
| DEFAULT_WINDOW_SIZE: float = float( | ||
| os.environ.get("GODELOS_EMERGENCE_WINDOW", "60.0") | ||
| ) | ||
|
|
There was a problem hiding this comment.
Module-level parsing of GODELOS_EMERGENCE_THRESHOLD / GODELOS_EMERGENCE_WINDOW uses float(...) directly, which will raise ValueError at import time if the env var is set but not a valid float. That would prevent the detector module from importing (and the server will silently run without the detector). Consider a safe parse with a warning + fallback default.
| EMERGENCE_THRESHOLD: float = float( | |
| os.environ.get("GODELOS_EMERGENCE_THRESHOLD", "0.8") | |
| ) | |
| DEFAULT_WINDOW_SIZE: float = float( | |
| os.environ.get("GODELOS_EMERGENCE_WINDOW", "60.0") | |
| ) | |
| def _get_env_float(name: str, default: float) -> float: | |
| """Safely parse a float from an environment variable with a fallback. | |
| Avoids raising at import time if the value is invalid, and logs a warning | |
| instead before falling back to the provided default. | |
| """ | |
| raw_value = os.environ.get(name) | |
| if raw_value is None: | |
| return default | |
| try: | |
| return float(raw_value) | |
| except (TypeError, ValueError): | |
| logger.warning( | |
| "Invalid value for %s=%r; expected a float. Using default %s.", | |
| name, | |
| raw_value, | |
| default, | |
| ) | |
| return default | |
| EMERGENCE_THRESHOLD: float = _get_env_float("GODELOS_EMERGENCE_THRESHOLD", 0.8) | |
| DEFAULT_WINDOW_SIZE: float = _get_env_float("GODELOS_EMERGENCE_WINDOW", 60.0) |
…orkspace), #118 (EmergenceDetector), #119 (transparency), #120 (ChromaDB) Resolve .gitignore conflict (keep both gitignore entries). unified_consciousness_engine.py auto-merged cleanly: IIT φ calculator coexists with GlobalWorkspace broadcaster. All 51 tests pass (30 IIT + 21 GlobalWorkspace). Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
…#116) * Initial plan * feat(iit): implement bipartition MI approximation for calculate_phi and add unit tests Replace the heuristic-based InformationIntegrationTheory.calculate_phi() with a tractable bipartition mutual-information approximation (Tononi 2004): - Convert subsystem dicts to numeric vectors via recursive flattening - Enumerate all non-trivial bipartitions at subsystem level (63 cuts) - φ = min MI across all cuts, with noise-floor suppression for idle states - Preserve contradiction penalty from self-model validator - Add 'phi' field to WebSocket broadcast payload for acceptance criteria - 27 unit tests: idle→φ=0, active→φ>0, penalty, helpers, performance <50ms Co-authored-by: Steake <530040+Steake@users.noreply.github.com> * address code review: document magic numbers, add division guard, expand test coverage Co-authored-by: Steake <530040+Steake@users.noreply.github.com> * merge: integrate main with PRs #114 (schema contracts), #117 (GlobalWorkspace), #118 (EmergenceDetector), #119 (transparency), #120 (ChromaDB) Resolve .gitignore conflict (keep both gitignore entries). unified_consciousness_engine.py auto-merged cleanly: IIT φ calculator coexists with GlobalWorkspace broadcaster. All 51 tests pass (30 IIT + 21 GlobalWorkspace). Co-authored-by: Steake <530040+Steake@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
Description
Implements the
ConsciousnessEmergenceDetector(Issue #82) — the subsystem that fires when GödelOS first exhibits genuine self-directed behaviour. Previously a stub.Core:
backend/core/consciousness_emergence_detector.pyGODELOS_EMERGENCE_WINDOW)recursive_depth(0.20),phi(0.30),metacognitive_accuracy(0.20),autonomous_goal_count(0.15),creative_novelty(0.15)EMERGENCE_THRESHOLD = 0.8, configurable viaGODELOS_EMERGENCE_THRESHOLDenv varmonitor_for_emergence(stream)— async generator consuming cognitive state stream, yields enriched dicts, fires breakthrough as side-effecthandle_consciousness_breakthrough(score)— appends tologs/breakthroughs.jsonl, broadcasts{"type": "consciousness_breakthrough", ...}on WebSocketUnifiedConsciousnessState-style dictsEndpoint:
GET /api/consciousness/emergenceUnifiedConsciousnessEngine._detect_consciousness_emergence()if detector unavailableWiring:
backend/unified_server.pywebsocket_managerinjectedRelated Issues
#82
Test Evidence
21 tests in
tests/backend/test_consciousness_emergence_detector.pycovering dimension extraction (flat/nested/empty), rolling window mechanics (pruning, averaging, weight invariants), breakthrough threshold detection, JSONL logging, WebSocket broadcast mock, async generator flow, REST status snapshot, and env-var config override via module reload. All pass. Full suite: 1176 passed, 0 regressions. CodeQL: 0 alerts.Checklist
pytest tests/)black .andisort .)Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.