merge: resolve conflicts between main and PR #129 (activate-cognitive-systems)#130
merge: resolve conflicts between main and PR #129 (activate-cognitive-systems)#130
Conversation
…r, CreativeSynthesisEngine, PAT docs Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
…t assertions, timestamp parsing Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
#129) into resolve-merge-conflicts-129 Keep both sets of changes from HEAD and PR branch: - Shutdown: retain dormant ticker cancellation + add observatory/hot-reloader stop - Endpoints: retain /api/system/dormant-modules + add /api/system/knowledge-persistence{,/reload}
…ration Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
🧪 CI — Python 3.11 |
🧪 CI — Python 3.10 |
|
Title: Add missing scripts/preflight.js to fix Playwright global setup error Problem statement: Error: Cannot find module './scripts/preflight.js'
To resolve this, add a basic placeholder preflight.js file exporting an async setup function. This will unblock Playwright test execution while allowing future customization as needed. Example content for svelte-frontend/scripts/preflight.js: // svelte-frontend/scripts/preflight.js
module.exports = async () => {
// Custom setup before Playwright tests run
};Add this file, commit, and I shall re-run the workflow. Proceed. |
…global setup Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
Added |
There was a problem hiding this comment.
Pull request overview
This PR resolves merge conflicts between main (which includes PR #128 — dormant modules and self-modification engine) and PR #129 (activate cognitive systems: autonomous goal engine, consciousness observatory, knowledge persistence). Both sets of changes are retained, with a scoping fix for _hot_reloader (hoisted to module scope with global declaration in lifespan).
Changes:
- Merges PR #129 features (consciousness observatory, autonomous goal engine, breakthrough log, knowledge persistence/hot-reload endpoints, and new dashboard tabs) alongside PR #128 features (dormant module ticker, self-modification engine) in
unified_server.py's lifespan and shutdown blocks. - Adds new backend modules (
autonomous_goal_engine.py,UnifiedConsciousnessObservatoryinconsciousness_emergence_detector.py) and REST endpoints for goals, breakthroughs, observatory, and knowledge persistence. - Extends the Svelte
UnifiedConsciousnessDashboardwith three new tabs (Autonomous Goals, Breakthrough Log, Subsystem Health) and adds PAT documentation toCONTRIBUTING.md.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
backend/unified_server.py |
Hoists _hot_reloader to module scope, adds it to global in lifespan; initializes observatory, goal engine, and hot-reloader at startup; shuts them down cleanly; adds 2 knowledge-persistence endpoints |
backend/core/consciousness_emergence_detector.py |
Adds get_breakthroughs() method to read from JSONL log; adds UnifiedConsciousnessObservatory class with start/stop/record_state/get_report |
backend/core/autonomous_goal_engine.py |
New file with AutonomousGoalGenerator (state-gap monitoring, dedup, cap at 10 active goals) and CreativeSynthesisEngine (concept-pair synthesis with novelty/coherence scoring) |
backend/api/consciousness_endpoints.py |
Adds endpoints for breakthroughs, observatory, goals, goal generation, and creative synthesis; adds setter/getter functions and updates __all__ |
svelte-frontend/src/components/UnifiedConsciousnessDashboard.svelte |
Adds three new tabs with data loading functions, UI templates, and styles for goals, breakthroughs, and subsystem health |
tests/backend/test_autonomous_goal_engine.py |
31 new tests covering AutonomousGoalGenerator, CreativeSynthesisEngine, UnifiedConsciousnessObservatory, and breakthrough log reading |
docs/CONTRIBUTING.md |
Adds PAT setup documentation with required scopes, rotation schedule, and verification instructions |
backend/unified_server.py
Outdated
| import os | ||
| backend = os.environ.get("KNOWLEDGE_STORE_BACKEND", "memory") | ||
| store_path = os.environ.get("KNOWLEDGE_STORE_PATH", "./data/chroma") | ||
| ontology_dir = os.environ.get("GODELOS_ONTOLOGY_DIR", "./ontologies") |
There was a problem hiding this comment.
Inconsistent default for GODELOS_ONTOLOGY_DIR: In lifespan (line 697), the default is "" (empty string), so the hot reloader is not initialized when the env var is unset. But here the default is "./ontologies", which will be displayed to the API consumer even when the env var isn't set and the reloader isn't active. This is misleading — the endpoint shows a directory that nobody is actually watching. Use "" as the default here too (matching the lifespan behaviour), or explicitly show that it's unset.
| ontology_dir = os.environ.get("GODELOS_ONTOLOGY_DIR", "./ontologies") | |
| ontology_dir = os.environ.get("GODELOS_ONTOLOGY_DIR", "") |
| if not self._log_path.exists(): | ||
| return [] | ||
| try: | ||
| lines = self._log_path.read_text(encoding="utf-8").splitlines() |
There was a problem hiding this comment.
read_text() reads the entire breakthroughs.jsonl file into memory before iterating in reverse, even when only a small limit (e.g. 10) is requested. As the log grows over time this will become increasingly expensive. Consider reading the file backwards (e.g. using seek from the end) or capping file size with rotation, so that fetching a small number of recent breakthroughs doesn't require loading the entire history.
backend/unified_server.py
Outdated
| Reads all ``.ttl`` and ``.json-ld`` files in ``GODELOS_ONTOLOGY_DIR``, | ||
| computes the delta against the last snapshot, and applies it to the | ||
| running knowledge graph. Returns the number of triples added/removed. | ||
| """ | ||
| try: | ||
| if _hot_reloader is None: | ||
| raise HTTPException( | ||
| status_code=503, | ||
| detail=( | ||
| "Hot-reloader is not active. " | ||
| "Set GODELOS_ONTOLOGY_DIR and restart the server to enable it." | ||
| ), | ||
| ) | ||
| # OntologyHotReloader.reload() is synchronous — run in executor | ||
| import asyncio | ||
| loop = asyncio.get_event_loop() | ||
| await loop.run_in_executor(None, _hot_reloader.reload) | ||
| return {"status": "reload_triggered", "watch_dir": _hot_reloader.watch_dir} |
There was a problem hiding this comment.
The docstring states "Returns the number of triples added/removed", but the actual response is {"status": "reload_triggered", "watch_dir": ...} which does not include any triple counts. Either update the docstring to match the actual response, or capture the return value from _hot_reloader.reload() and include the counts in the response.
| import time | ||
| import tempfile | ||
| from pathlib import Path | ||
| from unittest.mock import AsyncMock, MagicMock |
There was a problem hiding this comment.
Several unused imports: time, tempfile, Path, AsyncMock, and MagicMock are imported but never used in this test file. Consider removing them to keep the test module clean.
| import time | |
| import tempfile | |
| from pathlib import Path | |
| from unittest.mock import AsyncMock, MagicMock |
| for domain in _DOMAIN_TAGS: | ||
| a_match = any(t in a_lower for t in domain) | ||
| b_match = any(t in b_lower for t in domain) | ||
| if a_match and b_match: | ||
| return 0.8 # same domain → coherent | ||
| if a_match or b_match: | ||
| return 0.5 # partial domain overlap |
There was a problem hiding this comment.
Bug in _score_coherence: The early return on partial match (a_match or b_match) on line 418 prevents checking later domains. If concept a matches in domain 0 but concept b only matches in domain 1 (where both should score 0.8 for that domain), the function returns 0.5 prematurely.
For example, _score_coherence("quantum leap", "cognitive bias") would return 0.5 because "quantum" matches domain 0, but "cognitive" doesn't match domain 0 — so it returns 0.5 before reaching domain 1 where "cognitive" matches. But both concepts could still match domain 1 (cognitive/mind), and should score 0.8 for that domain.
The fix is to first check all domains for a joint match (both a and b), and only then check for partial matches.
| for domain in _DOMAIN_TAGS: | |
| a_match = any(t in a_lower for t in domain) | |
| b_match = any(t in b_lower for t in domain) | |
| if a_match and b_match: | |
| return 0.8 # same domain → coherent | |
| if a_match or b_match: | |
| return 0.5 # partial domain overlap | |
| any_partial = False | |
| for domain in _DOMAIN_TAGS: | |
| a_match = any(t in a_lower for t in domain) | |
| b_match = any(t in b_lower for t in domain) | |
| if a_match and b_match: | |
| return 0.8 # same domain → coherent | |
| if a_match or b_match: | |
| any_partial = True # remember partial domain overlap | |
| if any_partial: | |
| return 0.5 # at least one partial domain overlap |
…s dir Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
…t to avoid tracked file conflict Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
…der-issue fix(playwright): move HTML reporter output folder outside test-results dir
|
@copilot apply changes based on the comments in this thread |
- unified_server.py: GODELOS_ONTOLOGY_DIR default changed from './ontologies' to '' to match lifespan behavior - unified_server.py: fix misleading docstring on knowledge-persistence/reload endpoint - consciousness_emergence_detector.py: get_breakthroughs() now reads only the tail of the file (limit * 2048 bytes) instead of the full log - autonomous_goal_engine.py: fix _score_coherence early-return bug; now checks all domains before returning partial-match score - test_autonomous_goal_engine.py: remove unused imports (time, tempfile, Path, AsyncMock, MagicMock)" Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
Applied all review comments in commit
All 31 tests still pass. |
Description
PR #129 branched before PR #128 (dormant modules) landed on
main, leavingbackend/unified_server.pywith two content conflicts. Both are resolved by retaining all changes from both sides.Conflict 1 — lifespan shutdown block
_dormant_ticker_taskcancellation (from main/PR feat: Implement SelfModificationEngine with REST API (issue #95) #128)Conflict 2 — system API endpoints
GET /api/system/dormant-modules(from main/PR feat: Implement SelfModificationEngine with REST API (issue #95) #128)GET /api/system/knowledge-persistence+POST /api/system/knowledge-persistence/reload(from PR feat: Implement Steps 4-8 of cognitive roadmap (Issues #93, #82, #81, #84, #97) #129)Scoping fix —
_hot_reloaderwas declared afterlifespanwith noglobalstatement, so the knowledge-persistence endpoints always readNone. Fixed by hoisting the declaration abovelifespanand adding it to thegloballist:Playwright CI fix — Added missing
svelte-frontend/scripts/preflight.jsreferenced byplaywright.config.jsasglobalSetup. Its absence caused CI to fail withCannot find module './scripts/preflight.js'. The file exports a no-op async setup function, unblocking Playwright test execution.Review feedback fixes — Applied all issues raised in the automated code review:
GODELOS_ONTOLOGY_DIRdefault in the knowledge-persistence status endpoint changed from"./ontologies"to"", matching the lifespan behaviour so the endpoint does not report a watch directory that is not active.POST /api/system/knowledge-persistence/reload— removed the false claim that the response includes triple counts; the actual response is{"status": "reload_triggered", "watch_dir": ...}.get_breakthroughs()inconsciousness_emergence_detector.pynow reads only the tail of the log file (limit × 2 KiBfrom EOF) instead of loading the entirebreakthroughs.jsonlinto memory, keeping memory usage O(limit) as the log grows._score_coherence(autonomous_goal_engine.py) where an earlyreturn 0.5on a partial domain match prevented later domains from being checked for a full joint match. The partial-match result is now deferred until all domains have been evaluated.time,tempfile,Path,AsyncMock,MagicMock) fromtests/backend/test_autonomous_goal_engine.py.Related Issues
Test Evidence
Checklist
pytest tests/)black .andisort .)💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.