From 1669b0d1f2978a5b27ff5ef41231f62ff1d50d62 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sat, 12 Sep 2026 19:40:17 -0300 Subject: [PATCH 01/57] fail fast when forgevm url set without token --- main/app/prometheus/sandbox.py | 8 ++++++-- tests/test_sandbox_auth_gating.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tests/test_sandbox_auth_gating.py diff --git a/main/app/prometheus/sandbox.py b/main/app/prometheus/sandbox.py index 85fe44f..c7f0c51 100644 --- a/main/app/prometheus/sandbox.py +++ b/main/app/prometheus/sandbox.py @@ -22,9 +22,13 @@ def lockFor(userId: int) -> asyncio.Lock: def getClient() -> AsyncClient: + forgeUrl = Config.PROMETHEUS.FORGEVM_URL + forgeToken = Config.PROMETHEUS.FORGEVM_API_TOKEN + if forgeUrl and not forgeToken: + raise RuntimeError(f"FORGEVM_URL is set ({forgeUrl}) but FORGEVM_API_TOKEN is empty; set FORGEVM_API_TOKEN or unset FORGEVM_URL for local dev") return AsyncClient( - base_url=Config.PROMETHEUS.FORGEVM_URL, - api_key=Config.PROMETHEUS.FORGEVM_API_TOKEN or None, + base_url=forgeUrl, + api_key=forgeToken or None, timeout=30, ) diff --git a/tests/test_sandbox_auth_gating.py b/tests/test_sandbox_auth_gating.py new file mode 100644 index 0000000..42a57a3 --- /dev/null +++ b/tests/test_sandbox_auth_gating.py @@ -0,0 +1,30 @@ +from unittest.mock import patch + +import pytest + +from main.app.prometheus import sandbox as sandboxModule + + +class TestSandboxAuthGating: + def test_urlSetEmptyTokenRaises(self): + with patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_URL", "http://forgevm:7423"), patch.object( + sandboxModule.Config.PROMETHEUS, "FORGEVM_API_TOKEN", "" + ): + with pytest.raises(RuntimeError, match="FORGEVM_API_TOKEN"): + sandboxModule.getClient() + + def test_urlSetWithTokenPassesThrough(self): + with patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_URL", "http://forgevm:7423"), patch.object( + sandboxModule.Config.PROMETHEUS, "FORGEVM_API_TOKEN", "secret" + ), patch.object(sandboxModule, "AsyncClient") as mockClient: + client = sandboxModule.getClient() + mockClient.assert_called_once_with(base_url="http://forgevm:7423", api_key="secret", timeout=30) + assert client is mockClient.return_value + + def test_urlUnsetReturnsClient(self): + with patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_URL", ""), patch.object( + sandboxModule.Config.PROMETHEUS, "FORGEVM_API_TOKEN", "" + ), patch.object(sandboxModule, "AsyncClient") as mockClient: + client = sandboxModule.getClient() + mockClient.assert_called_once_with(base_url="", api_key=None, timeout=30) + assert client is mockClient.return_value From 8a224f4805cbdb2505c2b852cbd0f61be76fda53 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sat, 12 Sep 2026 19:40:54 -0300 Subject: [PATCH 02/57] retry field data load after failure instead of caching empty --- main/app/prometheus/compact.py | 2 +- tests/test_compact_retry.py | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/test_compact_retry.py diff --git a/main/app/prometheus/compact.py b/main/app/prometheus/compact.py index 7adba32..130aa71 100644 --- a/main/app/prometheus/compact.py +++ b/main/app/prometheus/compact.py @@ -80,7 +80,7 @@ def loadFieldData() -> dict: fieldData = {"historical": historicalFields, "fundamental": fundamentalCols} except Exception as e: logger.warning("Failed to load field data from STOCKS_API /fields: %s", e) - fieldData = {"historical": [], "fundamental": []} + return {"historical": [], "fundamental": []} return fieldData diff --git a/tests/test_compact_retry.py b/tests/test_compact_retry.py new file mode 100644 index 0000000..6d93389 --- /dev/null +++ b/tests/test_compact_retry.py @@ -0,0 +1,20 @@ +from unittest.mock import patch, MagicMock +import main.app.prometheus.compact as compactMod +from main.app.prometheus.compact import loadFieldData + + +class TestLoadFieldDataRetry: + def test_retryAfterFailure(self): + compactMod.fieldData = None + fakeResponse = MagicMock() + fakeResponse.json.return_value = {"historical": {"LUCRO LIQUIDO": [2023]}, "fundamental": ["P/L"]} + mockSession = MagicMock() + mockSession.get.side_effect = [Exception("boom"), fakeResponse] + with patch("main.app.prometheus.compact.getSession", return_value=mockSession): + first = loadFieldData() + assert first == {"historical": [], "fundamental": []} + assert compactMod.fieldData is None + second = loadFieldData() + assert "LUCRO LIQUIDO" in second["historical"] + assert second["fundamental"] == ["P/L"] + compactMod.fieldData = None From a09f906f3833aab5e9901e9137053b62942d7040 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sat, 12 Sep 2026 19:42:02 -0300 Subject: [PATCH 03/57] fix prometheus memory async cache deadlock --- main/app/prometheus/memory.py | 209 ++++++++++++++++++++++++++++++++ main/app/prometheus/tools.py | 4 +- tests/test_memory_async_loop.py | 111 +++++++++++++++++ 3 files changed, 322 insertions(+), 2 deletions(-) create mode 100644 tests/test_memory_async_loop.py diff --git a/main/app/prometheus/memory.py b/main/app/prometheus/memory.py index 8eaf6d7..f8f1bd2 100644 --- a/main/app/prometheus/memory.py +++ b/main/app/prometheus/memory.py @@ -58,6 +58,24 @@ def clearAll() -> None: asyncio.run(matrixCache.clear()) +async def getMatrixAsync(userId: Any, loader: Callable[[], tuple[list[int], np.ndarray]]) -> tuple[list[int], np.ndarray]: + cacheKey = matrixKey(userId) + cached = await matrixCache.get(cacheKey, default=MATRIX_MISS) + if cached is not MATRIX_MISS: + return cast(tuple[list[int], np.ndarray], cached) + freshIds, freshMatrix = loader() + await matrixCache.set(cacheKey, (freshIds, freshMatrix), tags=("matrix", matrixUserTag(userId))) + return cast(tuple[list[int], np.ndarray], await matrixCache.get(cacheKey, default=(freshIds, freshMatrix))) + + +async def invalidateUserAsync(userId: int) -> None: + await matrixCache.delete_tags(f"matrix-user:{userId}") + + +async def clearAllAsync() -> None: + await matrixCache.clear() + + logger = logging.getLogger(__name__) MEMORY_LIMIT_BASIC = 50 @@ -218,6 +236,84 @@ def upsertMemory( invalidateUser(userId) return {"status": "created", "memory": memory} + @classmethod + async def upsertMemoryAsync( + cls, + db: Session, + userId: int, + key: str, + value: str, + memoryType: str = "context", + source: str = "inferred", + embedding=None, + userRoles: list[str] | None = None, + ) -> dict: + existing = ( + db.query(PrometheusMemoryModel) + .filter(PrometheusMemoryModel.userId == userId, PrometheusMemoryModel.memoryKey == key) + .first() + ) + + if existing: + newHash = contentHash(value) + if existing.contentHash == newHash: + return {"status": "unchanged", "memory": existing} + + existing.memoryValue = value # type: ignore[assignment] + existing.memoryType = memoryType # type: ignore[assignment] + existing.source = source # type: ignore[assignment] + existing.contentHash = newHash # type: ignore[assignment] + existing.embedding = embedding # type: ignore[assignment] + existing.score = existing.score * 1.1 # type: ignore[assignment] + existing.accessCount += 1 # type: ignore[assignment] + existing.lastAccessedAt = datetime.now() # type: ignore[assignment] + + db.commit() + db.refresh(existing) + await invalidateUserAsync(userId) + + return {"status": "updated", "memory": existing} + + similar = findSimilarKey(db, userId, key) + if similar: + similar.memoryValue = value # type: ignore[assignment] + similar.memoryType = memoryType # type: ignore[assignment] + similar.source = source # type: ignore[assignment] + similar.contentHash = contentHash(value) # type: ignore[assignment] + similar.embedding = embedding # type: ignore[assignment] + similar.score = similar.score * 1.1 # type: ignore[assignment] + similar.accessCount += 1 # type: ignore[assignment] + similar.lastAccessedAt = datetime.now() # type: ignore[assignment] + + db.commit() + db.refresh(similar) + await invalidateUserAsync(userId) + + return {"status": "merged", "memory": similar} + + if userRoles: + limit = cls.getMemoryLimit(userRoles) + current = cls.countMemories(db, userId) + if current >= limit: + return {"status": "limit_reached", "limit": limit, "current": current} + + memory = PrometheusMemoryModel( + userId=userId, + memoryKey=key, + memoryValue=value, + memoryType=memoryType, + source=source, + embedding=embedding, + contentHash=contentHash(value), + score=INITIAL_STABILITY.get(str(memoryType)), + lastAccessedAt=datetime.now(), + ) + db.add(memory) + db.commit() + db.refresh(memory) + await invalidateUserAsync(userId) + return {"status": "created", "memory": memory} + @classmethod def search( cls, @@ -313,6 +409,101 @@ def loadMatrix() -> tuple[list[int], np.ndarray]: return cls.fullTextSearch(db, userId, query, limit) + @classmethod + async def searchAsync( + cls, + db: Session, + userId: int, + query: str, + limit: int = 10, + memoryType: str | None = None, + ) -> list[dict]: + queryFilter = ( + db.query(PrometheusMemoryModel) + .filter(PrometheusMemoryModel.userId == userId) + .filter(PrometheusMemoryModel.archivedAt.is_(None)) + ) + + if memoryType: + queryFilter = queryFilter.filter(PrometheusMemoryModel.memoryType == memoryType) + + candidateRows = ( + queryFilter.options(defer(cast(Any, PrometheusMemoryModel.embedding))) + .order_by(PrometheusMemoryModel.score.desc()) + .limit(MEMORY_SEARCH_PREFILTER_CAP) + .all() + ) + if not candidateRows: + return [] + candidateIds = [r.id for r in candidateRows] + + if not query or len(query.strip()) < 3: + scored = [] + now = datetime.now() + for m in candidateRows: + scored.append( + { + "id": m.id, + "memoryKey": m.memoryKey, + "memoryValue": m.memoryValue, + "memoryType": m.memoryType, + "score": getRelevanceScore(m, now), + "relevanceScore": getRelevanceScore(m, now), + "similarity": 0.0, + } + ) + scored.sort(key=lambda x: float(x["score"]), reverse=True) # type: ignore[arg-type] + return scored[:limit] + + try: + simById: dict[int, float] = {} + + def loadMatrix() -> tuple[list[int], np.ndarray]: + embRows = db.query(PrometheusMemoryModel).filter(PrometheusMemoryModel.id.in_(candidateIds)).all() + rowsWithEmb = [m for m in embRows if m.embedding is not None] + if not rowsWithEmb: + return ([], np.empty((0, 0), dtype=np.float32)) + rawEmbs = [m.embedding for m in rowsWithEmb] + if isinstance(rawEmbs[0], (bytes, bytearray, memoryview)): + return ([cast(int, m.id) for m in rowsWithEmb], decodeEmbeddings(rawEmbs)) # type: ignore[arg-type] + return ([cast(int, m.id) for m in rowsWithEmb], np.array(rawEmbs, dtype=np.float32)) + + try: + cachedIds, matrix = await getMatrixAsync((userId, memoryType), loadMatrix) + if cachedIds and matrix.shape[0] > 0: + queryEmbedding = embed([query])[0] + sims = batchCosineSimilarity(queryEmbedding, matrix) + simById = {mid: float(s) for mid, s in zip(cachedIds, sims)} + except Exception as e: + logger.warning(f"Embedding scoring failed, using full-text and recency only: {e}") + vecScores = [simById.get(cast(int, m.id), 0.0) for m in candidateRows] + vecNorm = minMax(vecScores) + ftRows = cls.fullTextSearch(db, userId, query, MEMORY_SEARCH_PREFILTER_CAP) + ftRank = {r["id"]: 1.0 / (i + 1) for i, r in enumerate(ftRows)} + now = datetime.now(timezone.utc) + fused = [] + for m, v in zip(candidateRows, vecNorm): + rec = getRelevanceScore(m, now) + f = 0.6 * v + 0.25 * ftRank.get(cast(int, m.id), 0.0) + 0.15 * rec + fused.append((m, f, simById.get(cast(int, m.id), 0.0))) + fused.sort(key=lambda p: p[1], reverse=True) + return [ + { + "id": m.id, + "memoryKey": m.memoryKey, + "memoryValue": m.memoryValue, + "memoryType": m.memoryType, + "score": f, + "relevanceScore": f, + "similarity": sim, + } + for m, f, sim in fused[:limit] + ] + except Exception as e: + logger.warning(f"Fused search failed, falling back to full-text: {e}") + + return cls.fullTextSearch(db, userId, query, limit) + @classmethod def fullTextSearch(cls, db: Session, userId: int, query: str, limit: int) -> list[dict]: if db.bind is not None and db.bind.dialect.name == "mysql": @@ -414,6 +605,24 @@ def deleteMemory(cls, db: Session, userId: int, memoryId: int) -> bool: return True + @classmethod + async def deleteMemoryAsync(cls, db: Session, userId: int, memoryId: int) -> bool: + memory = ( + db.query(PrometheusMemoryModel) + .filter(PrometheusMemoryModel.id == memoryId, PrometheusMemoryModel.userId == userId) + .first() + ) + + if not memory: + return False + + memory.archivedAt = datetime.now() # type: ignore[assignment] + + db.commit() + await invalidateUserAsync(userId) + + return True + @staticmethod def countTokensCached(text: str, cache: dict | None) -> int: if cache is None: diff --git a/main/app/prometheus/tools.py b/main/app/prometheus/tools.py index 1c90642..bfac074 100644 --- a/main/app/prometheus/tools.py +++ b/main/app/prometheus/tools.py @@ -33,7 +33,7 @@ async def search_memory(query: str, limit: int = 10, **_) -> dict: if ownSession: db = SessionLocal() try: - results = PrometheusMemory.search( + results = await PrometheusMemory.searchAsync( db, # type: ignore[arg-type] user["userId"], query, @@ -65,7 +65,7 @@ async def save_memory(key: str, value: str, type: str, **_) -> dict: db = SessionLocal() try: embedding = embed([value])[0] - result = PrometheusMemory.upsertMemory( + result = await PrometheusMemory.upsertMemoryAsync( db, # type: ignore[arg-type] user["userId"], key=key, diff --git a/tests/test_memory_async_loop.py b/tests/test_memory_async_loop.py new file mode 100644 index 0000000..f0f656c --- /dev/null +++ b/tests/test_memory_async_loop.py @@ -0,0 +1,111 @@ +import asyncio + +import numpy as np +import pytest + +import main.app.prometheus.memory as memoryMod +import main.app.prometheus.tools as toolsMod +from main.app.prometheus.memory import PrometheusMemory, clearAll, getMatrix +from main.app.prometheus.tools import save_memory, search_memory + + +def makeQueryVector(): + return [1.0] + [0.0] * 383 + + +def makeMatchVector(): + return [1.0, 1.0] + [0.0] * 382 + + +def makeDistractorVector(): + return [0.0, 0.0, 1.0] + [0.0] * 381 + + +def makeFlatVector(): + return [0.5] * 384 + + +class TestSearchAsyncVectorPath: + def test_searchAsync_vectorPath(self, dbSession, monkeypatch): + clearAll() + monkeypatch.setattr(memoryMod, "embed", lambda texts: [makeQueryVector() for _ in texts]) + asyncio.run( + PrometheusMemory.upsertMemoryAsync( + dbSession, + 31, + "ticker favorito", + "minha acao favorita e WEGE3", + "preference", + embedding=makeMatchVector(), + ), + ) + asyncio.run( + PrometheusMemory.upsertMemoryAsync( + dbSession, + 31, + "outro", + "texto sem relacao com nada especifico", + "preference", + embedding=makeDistractorVector(), + ), + ) + res = asyncio.run(PrometheusMemory.searchAsync(dbSession, 31, "WEGE3")) + assert res[0]["memoryKey"] == "ticker favorito" + assert res[0]["similarity"] > 0 + + +class TestUpsertThenSearch: + def test_upsertThenSearchFindsRow(self, dbSession, monkeypatch): + clearAll() + monkeypatch.setattr(memoryMod, "embed", lambda texts: [makeFlatVector() for _ in texts]) + asyncio.run( + PrometheusMemory.upsertMemoryAsync( + dbSession, + 32, + "chave teste", + "valor de teste WEGE3", + "preference", + embedding=makeFlatVector(), + ), + ) + res = asyncio.run(PrometheusMemory.searchAsync(dbSession, 32, "teste")) + assert any(r["memoryKey"] == "chave teste" for r in res) + + +class TestToolsInsideLoop: + def test_saveMemoryToolInsideLoop(self, dbSession, monkeypatch): + clearAll() + monkeypatch.setattr(toolsMod, "embed", lambda texts: [makeQueryVector() for _ in texts]) + monkeypatch.setattr(memoryMod, "embed", lambda texts: [makeQueryVector() for _ in texts]) + saved = asyncio.run( + save_memory( + "ticker favorito", + "minha acao favorita e WEGE3", + "preference", + user={"userId": 33, "roles": []}, + db=dbSession, + ), + ) + assert saved["status"] == "created" + found = asyncio.run( + search_memory( + "WEGE3", + user={"userId": 33}, + db=dbSession, + ), + ) + assert any(m["memoryKey"] == "ticker favorito" for m in found["memories"]) + + +class TestSyncDeadlockRegression: + def test_syncGetMatrixInsideLoopRaises(self): + clearAll() + + def seedLoader(): + return ([1], np.eye(1, dtype=np.float32)) + + async def inner(): + return getMatrix(99, seedLoader) + + with pytest.raises(RuntimeError): + asyncio.run(inner()) From 378c1913c6226ec7c23637591de2355f3b1d7fe9 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sat, 12 Sep 2026 19:48:34 -0300 Subject: [PATCH 04/57] add atomic snapshot to stocks cache reads --- main/app/stocks_api/cache.py | 4 ++ main/app/stocks_api/query.py | 40 ++++++++++----- tests/test_query_snapshot.py | 97 ++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 12 deletions(-) create mode 100644 tests/test_query_snapshot.py diff --git a/main/app/stocks_api/cache.py b/main/app/stocks_api/cache.py index e6c1f5b..22d9d57 100644 --- a/main/app/stocks_api/cache.py +++ b/main/app/stocks_api/cache.py @@ -195,6 +195,10 @@ def __init__(self, db: Engine, cacheLock: threading.Lock): self.nestedSample = None self.lastCacheUpdate = None + def snapshot(self) -> tuple: + with self.cacheLock: + return self.STOCKS_CACHE, self.tickerIndex + def cacheScheduler(self): thread = threading.Thread(target=self.getCachedStocks, name="stocks-cache-init", daemon=True) thread.start() diff --git a/main/app/stocks_api/query.py b/main/app/stocks_api/query.py index bfa185e..4da1afe 100644 --- a/main/app/stocks_api/query.py +++ b/main/app/stocks_api/query.py @@ -91,16 +91,17 @@ def parseJSON(x, decompressor): return df - def filterBySearchTerms(self, df: pd.DataFrame, search: str) -> pd.DataFrame: + def filterBySearchTerms(self, df: pd.DataFrame, search: str, index: dict | None = None) -> pd.DataFrame: if not search: return df searchTerms = [s.strip().upper() for s in search.split(",")] + lookup = index if index is not None else self.cacheManager.tickerIndex valid_indices = [] for term in searchTerms: - if term in self.cacheManager.tickerIndex: - valid_indices.append(self.cacheManager.tickerIndex[term]) + if term in lookup: + valid_indices.append(lookup[term]) if valid_indices: return df.iloc[valid_indices] @@ -118,11 +119,16 @@ def queryHistorical( ): if not (search or fields or dates): raise HTTPException(status_code=400, detail="at least one of search/fields/dates required") - if self.cacheManager.STOCKS_CACHE is None: + snap = getattr(self.cacheManager, "snapshot", None) + pair = snap() if callable(snap) else None + if isinstance(pair, tuple): + df, tickerIndex = pair + else: + df, tickerIndex = self.cacheManager.STOCKS_CACHE, self.cacheManager.tickerIndex + if df is None: raise HTTPException(status_code=503, detail="Cache not initialized") try: - df = self.cacheManager.STOCKS_CACHE availableColumns = df.columns.tolist() availableColumnsSet = set(availableColumns) historicalFields, _ = categorizeColumns(availableColumns) @@ -160,7 +166,7 @@ def queryHistorical( ] if search: - df = self.filterBySearchTerms(df, search) + df = self.filterBySearchTerms(df, search, tickerIndex) if orderBy and orderBy in df.columns: df = df.sort_values(by=orderBy, ascending=False) @@ -197,11 +203,16 @@ def queryFundamental( ): if not (search or fields or dates): raise HTTPException(status_code=400, detail="at least one of search/fields/dates required") - if self.cacheManager.STOCKS_CACHE is None: + snap = getattr(self.cacheManager, "snapshot", None) + pair = snap() if callable(snap) else None + if isinstance(pair, tuple): + df, tickerIndex = pair + else: + df, tickerIndex = self.cacheManager.STOCKS_CACHE, self.cacheManager.tickerIndex + if df is None: raise HTTPException(status_code=503, detail="Cache not initialized") try: - df = self.cacheManager.STOCKS_CACHE availableColumns = df.columns.tolist() availableColumnsSet = set(availableColumns) _, fundamentalCols = categorizeColumns(availableColumns) @@ -223,7 +234,7 @@ def queryFundamental( cols = ["TICKER", "NOME", "TIME"] + [field for field in fieldList if field in availableColumnsSet] if search: - df = self.filterBySearchTerms(df, search) + df = self.filterBySearchTerms(df, search, tickerIndex) if "TIME" in df.columns and dates: timeCol = pd.to_datetime(df["TIME"]) @@ -279,11 +290,16 @@ def queryCotations( dates: str | None = None, adjusted: bool = False, ): - if self.cacheManager.STOCKS_CACHE is None: + snap = getattr(self.cacheManager, "snapshot", None) + pair = snap() if callable(snap) else None + if isinstance(pair, tuple): + df, tickerIndex = pair + else: + df, tickerIndex = self.cacheManager.STOCKS_CACHE, self.cacheManager.tickerIndex + if df is None: raise HTTPException(status_code=503, detail="Cache not initialized") try: - df = self.cacheManager.STOCKS_CACHE targetCol = "COTACAO 10Y AJUSTADA" if adjusted else "COTACAO 10Y PADRAO" responseFields = [targetCol] @@ -298,7 +314,7 @@ def queryCotations( } if search: - df = self.filterBySearchTerms(df, search) + df = self.filterBySearchTerms(df, search, tickerIndex) if "TIME" in df.columns: df = df.sort_values(by="TIME", ascending=False, kind="mergesort") diff --git a/tests/test_query_snapshot.py b/tests/test_query_snapshot.py new file mode 100644 index 0000000..9ddfb70 --- /dev/null +++ b/tests/test_query_snapshot.py @@ -0,0 +1,97 @@ +"""Deterministic tests for the paired (frame + tickerIndex) stocks cache snapshot.""" + +import threading +from unittest.mock import MagicMock + +import pandas as pd +import pytest +from fastapi import HTTPException + +from main.app.stocks_api.cache import StocksCacheManager +from main.app.stocks_api.query import StocksQueryManager + + +def make_df(tickers): + return pd.DataFrame( + { + "TICKER": tickers, + "NOME": [f"Empresa {t}" for t in tickers], + "TIME": pd.to_datetime(["2024-01-15"] * len(tickers)), + "P/L": [5.0 + i for i in range(len(tickers))], + "LUCRO LIQUIDO 2023": [100.0 + 10.0 * i for i in range(len(tickers))], + "COTACAO 10Y PADRAO": [10.0 + i for i in range(len(tickers))], + } + ) + + +def make_manager(df, index): + manager = StocksCacheManager(MagicMock(), threading.Lock()) + manager.STOCKS_CACHE = df + manager.tickerIndex = index + return manager + + +def make_swapping_query(df_v1, idx_v1, df_v2, idx_v2): + """Query manager whose snapshot() returns the v1 pair, then swaps the manager state to v2.""" + manager = make_manager(df_v1, idx_v1) + originalSnapshot = manager.snapshot + + def swappingSnapshot(): + pair = originalSnapshot() + manager.STOCKS_CACHE = df_v2 + manager.tickerIndex = idx_v2 + return pair + + manager.snapshot = swappingSnapshot + return StocksQueryManager(manager), manager + + +class TestPairedSnapshot: + def test_query_methods_filter_with_snapshot_pair_only(self): + df_v1 = make_df(["AAA1", "BBB1"]) + idx_v1 = {"AAA1": 0, "BBB1": 1} + df_v2 = make_df(["BBB1", "AAA1"]) # row order swapped: v1 index now points at wrong rows + idx_v2 = {"AAA1": 1, "BBB1": 0} + + calls = ( + ("queryHistorical", {"search": "AAA1", "fields": "LUCRO LIQUIDO"}), + ("queryFundamental", {"search": "AAA1", "fields": "P/L"}), + ("queryCotations", {"search": "AAA1"}), + ) + for methodName, kwargs in calls: + query, manager = make_swapping_query(df_v1, idx_v1, df_v2, idx_v2) + + result = getattr(query, methodName)(**kwargs) + + assert result["data"][0]["TICKER"] == "AAA1", methodName + # swap fired after the snapshot; the result must still be built from the v1 pair + assert manager.STOCKS_CACHE is df_v2, methodName + assert manager.tickerIndex is idx_v2, methodName + + def test_query_raises_503_against_snapshot_frame_not_post_swap_state(self): + df_v2 = make_df(["AAA1"]) + query, _ = make_swapping_query(None, {}, df_v2, {"AAA1": 0}) + + with pytest.raises(HTTPException) as excinfo: + query.queryCotations(search="AAA1") + assert excinfo.value.status_code == 503 + + +class TestFilterBySearchTermsIndex: + def test_passed_index_wins_over_manager_global(self): + df = make_df(["AAA1", "BBB1"]) + manager = make_manager(df, {"AAA1": 1}) # decoy global: points AAA1 at the BBB1 row + query = StocksQueryManager(manager) + + filtered = query.filterBySearchTerms(df, "AAA1", {"AAA1": 0}) + + assert filtered["TICKER"].tolist() == ["AAA1"] + + def test_default_falls_back_to_manager_index(self): + df = make_df(["AAA1", "BBB1"]) + manager = make_manager(df, {"AAA1": 1}) + query = StocksQueryManager(manager) + + filtered = query.filterBySearchTerms(df, "AAA1") + + assert filtered["TICKER"].tolist() == ["BBB1"] From 2f57a083f53b5e9b39e84cbe0071faadc24fd1cd Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sat, 12 Sep 2026 20:00:31 -0300 Subject: [PATCH 05/57] rename thread safety tests to match pytest pattern --- tests/test_thread_safety.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_thread_safety.py b/tests/test_thread_safety.py index 63e4e7b..a90258a 100644 --- a/tests/test_thread_safety.py +++ b/tests/test_thread_safety.py @@ -96,7 +96,7 @@ def test_queue_and_lock_exist(self): assert lock is not None assert event is not None - def testemit_adds_to_queue(self): + def test_emit_adds_to_queue(self): """DiscordHandler.emit() must add messages to the module queue.""" from main.utils.logging_config import DiscordHandler, queue, lock @@ -121,7 +121,7 @@ def testemit_adds_to_queue(self): with lock: assert len(queue) == 1 - def test_concurrentemits_are_thread_safe(self): + def test_concurrent_emits_are_thread_safe(self): """Many concurrent emit() calls must not corrupt the queue.""" from main.utils.logging_config import DiscordHandler, queue, lock From 1c9fd0150a13a93f1e35f0af4afd022035e317a4 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sat, 12 Sep 2026 20:04:20 -0300 Subject: [PATCH 06/57] config is handled by config.py --- main/app/prometheus/sandbox.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/main/app/prometheus/sandbox.py b/main/app/prometheus/sandbox.py index c7f0c51..85fe44f 100644 --- a/main/app/prometheus/sandbox.py +++ b/main/app/prometheus/sandbox.py @@ -22,13 +22,9 @@ def lockFor(userId: int) -> asyncio.Lock: def getClient() -> AsyncClient: - forgeUrl = Config.PROMETHEUS.FORGEVM_URL - forgeToken = Config.PROMETHEUS.FORGEVM_API_TOKEN - if forgeUrl and not forgeToken: - raise RuntimeError(f"FORGEVM_URL is set ({forgeUrl}) but FORGEVM_API_TOKEN is empty; set FORGEVM_API_TOKEN or unset FORGEVM_URL for local dev") return AsyncClient( - base_url=forgeUrl, - api_key=forgeToken or None, + base_url=Config.PROMETHEUS.FORGEVM_URL, + api_key=Config.PROMETHEUS.FORGEVM_API_TOKEN or None, timeout=30, ) From 8b503337a3e732f41f142553d3957fe7d5cca006 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sat, 12 Sep 2026 20:12:39 -0300 Subject: [PATCH 07/57] fix exact search collapsing stock snapshots --- main/app/stocks_api/query.py | 24 ++++++------ tests/test_query_search_dates.py | 64 ++++++++++++++++++++++++++++++++ tests/test_query_snapshot.py | 2 +- 3 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 tests/test_query_search_dates.py diff --git a/main/app/stocks_api/query.py b/main/app/stocks_api/query.py index 4da1afe..83e8daa 100644 --- a/main/app/stocks_api/query.py +++ b/main/app/stocks_api/query.py @@ -95,19 +95,21 @@ def filterBySearchTerms(self, df: pd.DataFrame, search: str, index: dict | None if not search: return df - searchTerms = [s.strip().upper() for s in search.split(",")] + searchTerms = [s.strip().upper() for s in search.split(",") if s.strip()] + if not searchTerms: + return df lookup = index if index is not None else self.cacheManager.tickerIndex - valid_indices = [] - for term in searchTerms: - if term in lookup: - valid_indices.append(lookup[term]) - - if valid_indices: - return df.iloc[valid_indices] - - mask = df["TICKER"].str.upper().apply(lambda t: any(t.startswith(term) for term in searchTerms)) - return df[mask] + upperTickers = df["TICKER"].str.upper() + exactSet = {t for t in searchTerms if lookup and t in lookup} + prefixTerms = [t for t in searchTerms if t not in exactSet] + combinedMask = upperTickers.isin(exactSet) if exactSet else None + if prefixTerms: + prefixMask = upperTickers.apply(lambda t: any(t.startswith(term) for term in prefixTerms)) + combinedMask = prefixMask if combinedMask is None else (combinedMask | prefixMask) + if combinedMask is None: + return df.iloc[0:0] + return df[combinedMask] def queryHistorical( self, diff --git a/tests/test_query_search_dates.py b/tests/test_query_search_dates.py new file mode 100644 index 0000000..4465faf --- /dev/null +++ b/tests/test_query_search_dates.py @@ -0,0 +1,64 @@ +"""Failing-first tests: exact search must not collapse stock snapshots.""" + +import threading +from unittest.mock import MagicMock + +import pandas as pd + +from main.app.stocks_api.cache import StocksCacheManager, buildTickerIndex +from main.app.stocks_api.query import StocksQueryManager + + +def make_multi_df(): + return pd.DataFrame( + { + "TICKER": ["PETR4", "PETR4", "PETR4", "VALE3"], + "NOME": ["Petrobras PN"] * 3 + ["Vale ON"], + "TIME": pd.to_datetime(["2024-01-15", "2024-02-15", "2024-03-15", "2024-01-15"]), + "P/L": [5.0, 5.1, 5.2, 6.0], + "COTACAO 10Y PADRAO": [10.0, 10.1, 10.2, 11.0], + } + ) + + +def make_manager(df, index): + manager = StocksCacheManager(MagicMock(), threading.Lock()) + manager.STOCKS_CACHE = df + manager.tickerIndex = index + return manager + + +def test_exact_search_returns_all_snapshot_rows(): + df = make_multi_df() + query = StocksQueryManager(make_manager(df, buildTickerIndex(df))) + + filtered = query.filterBySearchTerms(df, "PETR4", buildTickerIndex(df)) + + assert filtered["TICKER"].tolist() == ["PETR4", "PETR4", "PETR4"] + + +def test_exact_search_with_dates_returns_matching_rows(): + df = make_multi_df() + query = StocksQueryManager(make_manager(df, buildTickerIndex(df))) + + result = query.queryFundamental(search="PETR4", fields="P/L", dates="2024-01-01,2024-02-15") + + assert result["count"] == 2 + + +def test_mixed_search_returns_exact_and_prefix(): + df = make_multi_df() + query = StocksQueryManager(make_manager(df, buildTickerIndex(df))) + + filtered = query.filterBySearchTerms(df, "PETR4,VALE", buildTickerIndex(df)) + + assert set(filtered["TICKER"].tolist()) == {"PETR4", "VALE3"} + + +def test_trailing_comma_does_not_match_everything(): + df = make_multi_df() + query = StocksQueryManager(make_manager(df, buildTickerIndex(df))) + + filtered = query.filterBySearchTerms(df, "PETR4,", buildTickerIndex(df)) + + assert filtered["TICKER"].tolist() == ["PETR4", "PETR4", "PETR4"] diff --git a/tests/test_query_snapshot.py b/tests/test_query_snapshot.py index 9ddfb70..8e35cea 100644 --- a/tests/test_query_snapshot.py +++ b/tests/test_query_snapshot.py @@ -94,4 +94,4 @@ def test_default_falls_back_to_manager_index(self): filtered = query.filterBySearchTerms(df, "AAA1") - assert filtered["TICKER"].tolist() == ["BBB1"] + assert filtered["TICKER"].tolist() == ["AAA1"] From c8c5881f1be4548033ff2774fa1f1d0b5264ba97 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sat, 12 Sep 2026 21:28:58 -0300 Subject: [PATCH 08/57] merge sync/async memory twins --- main/app/prometheus/memory.py | 316 ++++++++++------------------------ 1 file changed, 92 insertions(+), 224 deletions(-) diff --git a/main/app/prometheus/memory.py b/main/app/prometheus/memory.py index f8f1bd2..15d11de 100644 --- a/main/app/prometheus/memory.py +++ b/main/app/prometheus/memory.py @@ -40,25 +40,9 @@ def matrixUserTag(userId: Any) -> str: return f"matrix-user:{uid}" -def getMatrix(userId: Any, loader: Callable[[], tuple[list[int], np.ndarray]]) -> tuple[list[int], np.ndarray]: - cacheKey = matrixKey(userId) - cached = asyncio.run(matrixCache.get(cacheKey, default=MATRIX_MISS)) - if cached is not MATRIX_MISS: - return cast(tuple[list[int], np.ndarray], cached) - freshIds, freshMatrix = loader() - asyncio.run(matrixCache.set(cacheKey, (freshIds, freshMatrix), tags=("matrix", matrixUserTag(userId)))) - return cast(tuple[list[int], np.ndarray], asyncio.run(matrixCache.get(cacheKey, default=(freshIds, freshMatrix)))) - - -def invalidateUser(userId: int) -> None: - asyncio.run(matrixCache.delete_tags(f"matrix-user:{userId}")) - - -def clearAll() -> None: - asyncio.run(matrixCache.clear()) - - -async def getMatrixAsync(userId: Any, loader: Callable[[], tuple[list[int], np.ndarray]]) -> tuple[list[int], np.ndarray]: +async def getMatrixAsync( + userId: Any, loader: Callable[[], tuple[list[int], np.ndarray]] +) -> tuple[list[int], np.ndarray]: cacheKey = matrixKey(userId) cached = await matrixCache.get(cacheKey, default=MATRIX_MISS) if cached is not MATRIX_MISS: @@ -76,6 +60,18 @@ async def clearAllAsync() -> None: await matrixCache.clear() +def getMatrix(userId: Any, loader: Callable[[], tuple[list[int], np.ndarray]]) -> tuple[list[int], np.ndarray]: + return asyncio.run(getMatrixAsync(userId, loader)) + + +def invalidateUser(userId: int) -> None: + asyncio.run(invalidateUserAsync(userId)) + + +def clearAll() -> None: + asyncio.run(clearAllAsync()) + + logger = logging.getLogger(__name__) MEMORY_LIMIT_BASIC = 50 @@ -142,6 +138,67 @@ def findSimilarKey(db: Session, userId: int, newKey: str, threshold: float = 0.8 return None +def scoreRecency(candidateRows: list[Any], limit: int) -> list[dict]: + now = datetime.now() + scored = [ + { + "id": m.id, + "memoryKey": m.memoryKey, + "memoryValue": m.memoryValue, + "memoryType": m.memoryType, + "score": getRelevanceScore(m, now), + "relevanceScore": getRelevanceScore(m, now), + "similarity": 0.0, + } + for m in candidateRows + ] + scored.sort(key=lambda x: float(x["score"]), reverse=True) # type: ignore[arg-type] + return scored[:limit] + + +def scoreCandidates( + candidateRows: list[Any], + vecNorm: list[float], + simById: dict[int, float], + ftRank: dict[int, float], + now: datetime, + limit: int, +) -> list[dict]: + fused: list[tuple[Any, float, float]] = [] + for m, v in zip(candidateRows, vecNorm): + rec = getRelevanceScore(m, now) + f = 0.6 * v + 0.25 * ftRank.get(cast(int, m.id), 0.0) + 0.15 * rec + fused.append((m, f, simById.get(cast(int, m.id), 0.0))) + fused.sort(key=lambda p: p[1], reverse=True) + return [ + { + "id": m.id, + "memoryKey": m.memoryKey, + "memoryValue": m.memoryValue, + "memoryType": m.memoryType, + "score": f, + "relevanceScore": f, + "similarity": sim, + } + for m, f, sim in fused[:limit] + ] + + +def sumTokens(texts: list[str], cache: dict | None) -> int: + total = 0 + if cache is None: + for text in texts: + total += countTokens(text) + return total + for text in texts: + cached = cache.get(text) + if cached is None: + cached = countTokens(text) + cache[text] = cached + total += cached + return total + + class PrometheusMemory: @classmethod def getMemoryLimit(cls, userRoles: list[str]) -> int: @@ -170,72 +227,19 @@ def upsertMemory( embedding=None, userRoles: list[str] | None = None, ) -> dict: - existing = ( - db.query(PrometheusMemoryModel) - .filter(PrometheusMemoryModel.userId == userId, PrometheusMemoryModel.memoryKey == key) - .first() + return asyncio.run( + cls.upsertMemoryAsync( + db, + userId, + key, + value, + memoryType, + source, + embedding, + userRoles, + ), ) - if existing: - newHash = contentHash(value) - if existing.contentHash == newHash: - return {"status": "unchanged", "memory": existing} - - existing.memoryValue = value # type: ignore[assignment] - existing.memoryType = memoryType # type: ignore[assignment] - existing.source = source # type: ignore[assignment] - existing.contentHash = newHash # type: ignore[assignment] - existing.embedding = embedding # type: ignore[assignment] - existing.score = existing.score * 1.1 # type: ignore[assignment] - existing.accessCount += 1 # type: ignore[assignment] - existing.lastAccessedAt = datetime.now() # type: ignore[assignment] - - db.commit() - db.refresh(existing) - invalidateUser(userId) - - return {"status": "updated", "memory": existing} - - similar = findSimilarKey(db, userId, key) - if similar: - similar.memoryValue = value # type: ignore[assignment] - similar.memoryType = memoryType # type: ignore[assignment] - similar.source = source # type: ignore[assignment] - similar.contentHash = contentHash(value) # type: ignore[assignment] - similar.embedding = embedding # type: ignore[assignment] - similar.score = similar.score * 1.1 # type: ignore[assignment] - similar.accessCount += 1 # type: ignore[assignment] - similar.lastAccessedAt = datetime.now() # type: ignore[assignment] - - db.commit() - db.refresh(similar) - invalidateUser(userId) - - return {"status": "merged", "memory": similar} - - if userRoles: - limit = cls.getMemoryLimit(userRoles) - current = cls.countMemories(db, userId) - if current >= limit: - return {"status": "limit_reached", "limit": limit, "current": current} - - memory = PrometheusMemoryModel( - userId=userId, - memoryKey=key, - memoryValue=value, - memoryType=memoryType, - source=source, - embedding=embedding, - contentHash=contentHash(value), - score=INITIAL_STABILITY.get(str(memoryType)), - lastAccessedAt=datetime.now(), - ) - db.add(memory) - db.commit() - db.refresh(memory) - invalidateUser(userId) - return {"status": "created", "memory": memory} - @classmethod async def upsertMemoryAsync( cls, @@ -323,91 +327,7 @@ def search( limit: int = 10, memoryType: str | None = None, ) -> list[dict]: - queryFilter = ( - db.query(PrometheusMemoryModel) - .filter(PrometheusMemoryModel.userId == userId) - .filter(PrometheusMemoryModel.archivedAt.is_(None)) - ) - - if memoryType: - queryFilter = queryFilter.filter(PrometheusMemoryModel.memoryType == memoryType) - - candidateRows = ( - queryFilter.options(defer(cast(Any, PrometheusMemoryModel.embedding))) - .order_by(PrometheusMemoryModel.score.desc()) - .limit(MEMORY_SEARCH_PREFILTER_CAP) - .all() - ) - if not candidateRows: - return [] - candidateIds = [r.id for r in candidateRows] - - if not query or len(query.strip()) < 3: - scored = [] - now = datetime.now() - for m in candidateRows: - scored.append( - { - "id": m.id, - "memoryKey": m.memoryKey, - "memoryValue": m.memoryValue, - "memoryType": m.memoryType, - "score": getRelevanceScore(m, now), - "relevanceScore": getRelevanceScore(m, now), - "similarity": 0.0, - } - ) - scored.sort(key=lambda x: float(x["score"]), reverse=True) # type: ignore[arg-type] - return scored[:limit] - - try: - simById: dict[int, float] = {} - - def loadMatrix() -> tuple[list[int], np.ndarray]: - embRows = db.query(PrometheusMemoryModel).filter(PrometheusMemoryModel.id.in_(candidateIds)).all() - rowsWithEmb = [m for m in embRows if m.embedding is not None] - if not rowsWithEmb: - return ([], np.empty((0, 0), dtype=np.float32)) - rawEmbs = [m.embedding for m in rowsWithEmb] - if isinstance(rawEmbs[0], (bytes, bytearray, memoryview)): - return ([cast(int, m.id) for m in rowsWithEmb], decodeEmbeddings(rawEmbs)) # type: ignore[arg-type] - return ([cast(int, m.id) for m in rowsWithEmb], np.array(rawEmbs, dtype=np.float32)) - - try: - cachedIds, matrix = getMatrix((userId, memoryType), loadMatrix) - if cachedIds and matrix.shape[0] > 0: - queryEmbedding = embed([query])[0] - sims = batchCosineSimilarity(queryEmbedding, matrix) - simById = {mid: float(s) for mid, s in zip(cachedIds, sims)} - except Exception as e: - logger.warning(f"Embedding scoring failed, using full-text and recency only: {e}") - vecScores = [simById.get(cast(int, m.id), 0.0) for m in candidateRows] - vecNorm = minMax(vecScores) - ftRows = cls.fullTextSearch(db, userId, query, MEMORY_SEARCH_PREFILTER_CAP) - ftRank = {r["id"]: 1.0 / (i + 1) for i, r in enumerate(ftRows)} - now = datetime.now(timezone.utc) - fused = [] - for m, v in zip(candidateRows, vecNorm): - rec = getRelevanceScore(m, now) - f = 0.6 * v + 0.25 * ftRank.get(cast(int, m.id), 0.0) + 0.15 * rec - fused.append((m, f, simById.get(cast(int, m.id), 0.0))) - fused.sort(key=lambda p: p[1], reverse=True) - return [ - { - "id": m.id, - "memoryKey": m.memoryKey, - "memoryValue": m.memoryValue, - "memoryType": m.memoryType, - "score": f, - "relevanceScore": f, - "similarity": sim, - } - for m, f, sim in fused[:limit] - ] - except Exception as e: - logger.warning(f"Fused search failed, falling back to full-text: {e}") - - return cls.fullTextSearch(db, userId, query, limit) + return asyncio.run(cls.searchAsync(db, userId, query, limit, memoryType)) @classmethod async def searchAsync( @@ -438,22 +358,7 @@ async def searchAsync( candidateIds = [r.id for r in candidateRows] if not query or len(query.strip()) < 3: - scored = [] - now = datetime.now() - for m in candidateRows: - scored.append( - { - "id": m.id, - "memoryKey": m.memoryKey, - "memoryValue": m.memoryValue, - "memoryType": m.memoryType, - "score": getRelevanceScore(m, now), - "relevanceScore": getRelevanceScore(m, now), - "similarity": 0.0, - } - ) - scored.sort(key=lambda x: float(x["score"]), reverse=True) # type: ignore[arg-type] - return scored[:limit] + return scoreRecency(candidateRows, limit) try: simById: dict[int, float] = {} @@ -481,24 +386,7 @@ def loadMatrix() -> tuple[list[int], np.ndarray]: ftRows = cls.fullTextSearch(db, userId, query, MEMORY_SEARCH_PREFILTER_CAP) ftRank = {r["id"]: 1.0 / (i + 1) for i, r in enumerate(ftRows)} now = datetime.now(timezone.utc) - fused = [] - for m, v in zip(candidateRows, vecNorm): - rec = getRelevanceScore(m, now) - f = 0.6 * v + 0.25 * ftRank.get(cast(int, m.id), 0.0) + 0.15 * rec - fused.append((m, f, simById.get(cast(int, m.id), 0.0))) - fused.sort(key=lambda p: p[1], reverse=True) - return [ - { - "id": m.id, - "memoryKey": m.memoryKey, - "memoryValue": m.memoryValue, - "memoryType": m.memoryType, - "score": f, - "relevanceScore": f, - "similarity": sim, - } - for m, f, sim in fused[:limit] - ] + return scoreCandidates(candidateRows, vecNorm, simById, ftRank, now, limit) except Exception as e: logger.warning(f"Fused search failed, falling back to full-text: {e}") @@ -589,21 +477,7 @@ def getUserMemories(cls, db: Session, userId: int, limit: int = 50, offset: int @classmethod def deleteMemory(cls, db: Session, userId: int, memoryId: int) -> bool: - memory = ( - db.query(PrometheusMemoryModel) - .filter(PrometheusMemoryModel.id == memoryId, PrometheusMemoryModel.userId == userId) - .first() - ) - - if not memory: - return False - - memory.archivedAt = datetime.now() # type: ignore[assignment] - - db.commit() - invalidateUser(userId) - - return True + return asyncio.run(cls.deleteMemoryAsync(db, userId, memoryId)) @classmethod async def deleteMemoryAsync(cls, db: Session, userId: int, memoryId: int) -> bool: @@ -625,13 +499,7 @@ async def deleteMemoryAsync(cls, db: Session, userId: int, memoryId: int) -> boo @staticmethod def countTokensCached(text: str, cache: dict | None) -> int: - if cache is None: - return countTokens(text) - cached = cache.get(text) - if cached is None: - cached = countTokens(text) - cache[text] = cached - return cached + return sumTokens([text], cache) @staticmethod def extract( From b7df70409cf7841f49757e62740799d889d13d77 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sat, 12 Sep 2026 21:33:54 -0300 Subject: [PATCH 09/57] prune query.py p2 lane into baseframe and finalize helpers --- main/app/stocks_api/query.py | 196 ++++++++++++++++------------------- 1 file changed, 89 insertions(+), 107 deletions(-) diff --git a/main/app/stocks_api/query.py b/main/app/stocks_api/query.py index 83e8daa..21a14ea 100644 --- a/main/app/stocks_api/query.py +++ b/main/app/stocks_api/query.py @@ -35,41 +35,81 @@ def filterCotationColumn(series: pd.Series, startDate, endDate) -> pd.Series: if not startDate or not endDate: return series - startDateStr = startDate.strftime("%d-%m-%Y") - endDateStr = endDate.strftime("%d-%m-%Y") - exploded = series.explode() if exploded.empty or exploded.isna().all(): return series dates = pd.to_datetime(exploded.str.get("DATA"), format="%d-%m-%Y", errors="coerce") mask = (dates >= pd.Timestamp(startDate)) & (dates <= pd.Timestamp(endDate)) - filtered = exploded[mask] - - result = [entries if not isinstance(entries, list) else [] for entries in series] - for idx, group in filtered.groupby(level=0): - result[series.index.get_loc(idx)] = group.tolist() - return pd.Series(result, index=series.index) + grouped = exploded[mask].groupby(level=0).agg(list) + base = pd.Series( + [entries if not isinstance(entries, list) else [] for entries in series], + index=series.index, + ) + base.update(grouped) + return base class StocksQueryManager: def __init__(self, cacheManager): self.cacheManager = cacheManager + def _baseFrame(self): + snap = getattr(self.cacheManager, "snapshot", None) + pair = snap() if callable(snap) else None + if isinstance(pair, tuple): + df, tickerIndex = pair + else: + df, tickerIndex = self.cacheManager.STOCKS_CACHE, self.cacheManager.tickerIndex + if df is None: + raise HTTPException(status_code=503, detail="Cache not initialized") + return df, tickerIndex + + def _finalize( + self, + df: pd.DataFrame, + tickerIndex, + search: str | None, + orderBy: str | None, + limit: int | None, + cols: list[str] | None, + fields, + dates, + typeName: str, + dedupTickers: bool = False, + cotationCol: str | None = None, + ): + if search: + df = self.filterBySearchTerms(df, search, tickerIndex) + if orderBy and orderBy in df.columns: + df = df.sort_values(by=orderBy, ascending=False) + if limit: + df = df.head(limit) + if cols is not None: + df = df[[c for c in cols if c in df.columns]] + if dedupTickers: + df = df.drop_duplicates(subset=["TICKER"], keep="first") + df = self.deserializeJsonColumns(df) + if cotationCol and cotationCol in df.columns: + startDate, endDate = parseDateRange(dates) + if startDate and endDate: + df[cotationCol] = filterCotationColumn(df[cotationCol], startDate, endDate) + return { + "search": search or "all", + "fields": fields, + "dates": dates, + "type": typeName, + "count": len(df), + "data": sanitizeNanValues(df.to_dict(orient="records")), + } + def deserializeJsonColumns(self, df: pd.DataFrame) -> pd.DataFrame: if df.empty: return df df = df.copy() - def cleanJSON(obj): - if isinstance(obj, dict): - return {k: cleanJSON(v) for k, v in obj.items()} - if isinstance(obj, list): - return [cleanJSON(item) for item in obj] - return sanitizeNanValues(obj) - def parseJSON(x, decompressor): if isinstance(x, bytes): x = decompressor.decompress(x).decode("utf-8") @@ -83,7 +123,7 @@ def parseJSON(x, decompressor): if col in JSON_COLUMNS and (df[col].dtype == "object" or pd.api.types.is_string_dtype(df[col])): df[col] = df[col].apply( lambda x: ( - cleanJSON(parseJSON(x, decompressor)) + sanitizeNanValues(parseJSON(x, decompressor)) if (isinstance(x, str) and x.startswith(("{", "["))) or isinstance(x, bytes) else sanitizeNanValues(x) ) @@ -102,14 +142,11 @@ def filterBySearchTerms(self, df: pd.DataFrame, search: str, index: dict | None lookup = index if index is not None else self.cacheManager.tickerIndex upperTickers = df["TICKER"].str.upper() exactSet = {t for t in searchTerms if lookup and t in lookup} - prefixTerms = [t for t in searchTerms if t not in exactSet] - combinedMask = upperTickers.isin(exactSet) if exactSet else None + prefixTerms = tuple(t for t in searchTerms if t not in exactSet) + exactMask = upperTickers.isin(exactSet) if prefixTerms: - prefixMask = upperTickers.apply(lambda t: any(t.startswith(term) for term in prefixTerms)) - combinedMask = prefixMask if combinedMask is None else (combinedMask | prefixMask) - if combinedMask is None: - return df.iloc[0:0] - return df[combinedMask] + return df[exactMask | upperTickers.str.startswith(prefixTerms)] + return df[exactMask] def queryHistorical( self, @@ -121,14 +158,7 @@ def queryHistorical( ): if not (search or fields or dates): raise HTTPException(status_code=400, detail="at least one of search/fields/dates required") - snap = getattr(self.cacheManager, "snapshot", None) - pair = snap() if callable(snap) else None - if isinstance(pair, tuple): - df, tickerIndex = pair - else: - df, tickerIndex = self.cacheManager.STOCKS_CACHE, self.cacheManager.tickerIndex - if df is None: - raise HTTPException(status_code=503, detail="Cache not initialized") + df, tickerIndex = self._baseFrame() try: availableColumns = df.columns.tolist() @@ -167,28 +197,18 @@ def queryHistorical( if f"{field} {year}" in availableColumnsSet ] - if search: - df = self.filterBySearchTerms(df, search, tickerIndex) - - if orderBy and orderBy in df.columns: - df = df.sort_values(by=orderBy, ascending=False) - - if limit: - df = df.head(limit) - - df = df[[c for c in cols if c in df.columns]] - df = df.drop_duplicates(subset=["TICKER"], keep="first") - - df = self.deserializeJsonColumns(df) - - return { - "search": search or "all", - "fields": sorted(fieldList), - "dates": [yearStart, yearEnd], - "type": "historical", - "count": len(df), - "data": sanitizeNanValues(df.to_dict(orient="records")), - } + return self._finalize( + df, + tickerIndex, + search, + orderBy, + limit, + cols, + sorted(fieldList), + [yearStart, yearEnd], + "historical", + dedupTickers=True, + ) except HTTPException: raise except Exception as e: @@ -205,14 +225,7 @@ def queryFundamental( ): if not (search or fields or dates): raise HTTPException(status_code=400, detail="at least one of search/fields/dates required") - snap = getattr(self.cacheManager, "snapshot", None) - pair = snap() if callable(snap) else None - if isinstance(pair, tuple): - df, tickerIndex = pair - else: - df, tickerIndex = self.cacheManager.STOCKS_CACHE, self.cacheManager.tickerIndex - if df is None: - raise HTTPException(status_code=503, detail="Cache not initialized") + df, tickerIndex = self._baseFrame() try: availableColumns = df.columns.tolist() @@ -259,27 +272,7 @@ def queryFundamental( if not search or search.strip() == "": df = df.drop_duplicates(subset=["TICKER"], keep="first") - if orderBy and orderBy in df.columns: - df = df.sort_values(by=orderBy, ascending=False) - - if limit: - df = df.head(limit) - - if "TIME" in df.columns: - df = df.copy() - df["TIME"] = pd.to_datetime(df["TIME"]).dt.strftime("%Y-%m-%d") - - df = df[[c for c in cols if c in df.columns]] - df = self.deserializeJsonColumns(df) - - return { - "search": search or "all", - "fields": fieldList, - "dates": dates, - "type": "fundamental", - "count": len(df), - "data": sanitizeNanValues(df.to_dict(orient="records")), - } + return self._finalize(df, tickerIndex, search, orderBy, limit, cols, fieldList, dates, "fundamental") except HTTPException: raise except Exception as e: @@ -292,14 +285,7 @@ def queryCotations( dates: str | None = None, adjusted: bool = False, ): - snap = getattr(self.cacheManager, "snapshot", None) - pair = snap() if callable(snap) else None - if isinstance(pair, tuple): - df, tickerIndex = pair - else: - df, tickerIndex = self.cacheManager.STOCKS_CACHE, self.cacheManager.tickerIndex - if df is None: - raise HTTPException(status_code=503, detail="Cache not initialized") + df, tickerIndex = self._baseFrame() try: targetCol = "COTACAO 10Y AJUSTADA" if adjusted else "COTACAO 10Y PADRAO" @@ -322,22 +308,18 @@ def queryCotations( df = df.sort_values(by="TIME", ascending=False, kind="mergesort") df = df.drop_duplicates(subset=["TICKER"], keep="first") - cols = ["TICKER", "NOME", "TIME", targetCol] - df = df[[c for c in cols if c in df.columns]] - df = self.deserializeJsonColumns(df) - - startDate, endDate = parseDateRange(dates) - if startDate and endDate and targetCol in df.columns: - df[targetCol] = filterCotationColumn(df[targetCol], startDate, endDate) - - return { - "search": search or "all", - "fields": responseFields, - "dates": dates, - "type": "cotations", - "count": len(df), - "data": sanitizeNanValues(df.to_dict(orient="records")), - } + return self._finalize( + df, + tickerIndex, + search, + None, + None, + ["TICKER", "NOME", "TIME", targetCol], + responseFields, + dates, + "cotations", + cotationCol=targetCol, + ) except HTTPException: raise except Exception: From 0699f8181d66ef2b3da9e5bad671dedc79d255d4 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:21:52 -0300 Subject: [PATCH 10/57] remove over-engineered helpers in memory vector key cache and compress --- main/app/prometheus/memory.py | 2 -- main/app/prometheus/vector.py | 11 ++++---- main/app/stocks_api/compress.py | 40 ++++++++++++------------------ main/app/stocks_api/key.py | 6 +---- main/app/stocks_api/sync_cache.py | 16 +++++++----- tests/test_api_key_quota_atomic.py | 19 +++++++------- 6 files changed, 43 insertions(+), 51 deletions(-) diff --git a/main/app/prometheus/memory.py b/main/app/prometheus/memory.py index 15d11de..f298e8d 100644 --- a/main/app/prometheus/memory.py +++ b/main/app/prometheus/memory.py @@ -512,8 +512,6 @@ def extract( if db is None: logger.error("Failed to acquire DB session for memory search") return [] - if not Roles.checkAccess(userRoles, Permission.USE_PROMETHEUS): - return [] cap = ( MEMORY_EXTRACT_PREMIUM_CAP if Roles.checkAccess(userRoles, Permission.PROMETHEUS_EXTENDED_MEMORIES) diff --git a/main/app/prometheus/vector.py b/main/app/prometheus/vector.py index 869027e..7c24be1 100644 --- a/main/app/prometheus/vector.py +++ b/main/app/prometheus/vector.py @@ -53,15 +53,16 @@ def contentHash(text: str) -> str: def toVectorString(vec: list[float]) -> str: - return "[" + ",".join(repr(float(v)) for v in vec) + "]" + return np.array(vec, dtype=np.float32).tobytes().hex() def fromVectorString(s: str, dims: int = 384) -> list[float]: trimmed = s.strip() - if len(trimmed) < 2 or not trimmed.startswith("[") or not trimmed.endswith("]"): - raise ValueError(f"expected bracketed vector string, got {s!r}") - parts = trimmed[1:-1].split(",") - vals = [float(p) for p in parts if p.strip() != ""] + if trimmed.startswith("["): + parts = trimmed[1:-1].split(",") + vals = [float(p) for p in parts if p.strip() != ""] + else: + vals = np.frombuffer(bytes.fromhex(trimmed), dtype=np.float32).tolist() if len(vals) != dims: raise ValueError(f"expected {dims} dims, got {len(vals)}") return vals diff --git a/main/app/stocks_api/compress.py b/main/app/stocks_api/compress.py index 806e1a5..dc7b041 100644 --- a/main/app/stocks_api/compress.py +++ b/main/app/stocks_api/compress.py @@ -1,6 +1,7 @@ from __future__ import annotations import re +from functools import lru_cache from typing import Any from main.app.stocks_api.cache import stocksCache @@ -18,37 +19,28 @@ DF = re.compile(r"^\d{2}-\d{2}-(\d{4})$") DI = re.compile(r"^(\d{4})-\d{2}-\d{2}$") -abbr: dict | None = None -nest: dict | None = None - - +@lru_cache(maxsize=1) def getAbbr() -> dict: - global abbr - if abbr is None: - if stocksCache.STOCKS_CACHE is not None: - h, f = categorizeColumns(stocksCache.STOCKS_CACHE.columns.tolist()) - abbr = generateAbbreviations(h, f) - else: - abbr = {"meta": {"TICKER": "TK", "NOME": "NM", "TIME": "TI"}, "historical": {}, "fundamental": {}} - return abbr + if stocksCache.STOCKS_CACHE is not None: + h, f = categorizeColumns(stocksCache.STOCKS_CACHE.columns.tolist()) + return generateAbbreviations(h, f) + return {"meta": {"TICKER": "TK", "NOME": "NM", "TIME": "TI"}, "historical": {}, "fundamental": {}} +@lru_cache(maxsize=1) def getNest() -> dict: - global nest - if nest is None: - if stocksCache.STOCKS_CACHE is not None: - nest = detectNestedFields(stocksCache.STOCKS_CACHE) - if stocksCache.nestedSample is not None: - for col, info in detectNestedFields(stocksCache.nestedSample).items(): - nest.setdefault(col, info) - else: - nest = {} - return nest + if stocksCache.STOCKS_CACHE is not None: + nest = detectNestedFields(stocksCache.STOCKS_CACHE) + if stocksCache.nestedSample is not None: + for col, info in detectNestedFields(stocksCache.nestedSample).items(): + nest.setdefault(col, info) + return nest + return {} def rebuildAbbrevs() -> None: - global abbr, nest - abbr = nest = None + getAbbr.cache_clear() + getNest.cache_clear() def walk(data: Any, fn: Any) -> Any: diff --git a/main/app/stocks_api/key.py b/main/app/stocks_api/key.py index 38cef1a..01ff0ba 100644 --- a/main/app/stocks_api/key.py +++ b/main/app/stocks_api/key.py @@ -14,10 +14,6 @@ apiKeyHeader = APIKeyHeader(name="X-API-Key", auto_error=False) -def hashKey(key: str) -> str: - return hashlib.sha256(key.encode()).hexdigest() - - async def verifyAPIKey(apiKey: str = Depends(apiKeyHeader), db: Session = Depends(getSession)): if not Config.STOCKS_API.KEY_SYSTEM: return None @@ -25,7 +21,7 @@ async def verifyAPIKey(apiKey: str = Depends(apiKeyHeader), db: Session = Depend if not apiKey: raise HTTPException(status_code=401, detail="Missing API key") - hashedKey = hashKey(apiKey) + hashedKey = hashlib.sha256(apiKey.encode()).hexdigest() try: result = db.execute( diff --git a/main/app/stocks_api/sync_cache.py b/main/app/stocks_api/sync_cache.py index 2653b03..f52bde9 100644 --- a/main/app/stocks_api/sync_cache.py +++ b/main/app/stocks_api/sync_cache.py @@ -15,12 +15,16 @@ def decorator(func: F) -> F: @wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: cache_key = get_cache_key(func, key, args, kwargs) - cached = asyncio.run(cache.get(cache_key, default=MISS)) - if cached is not MISS: - return cached - result = func(*args, **kwargs) - asyncio.run(cache.set(cache_key, result, expire=ttl)) - return result + + async def cachedCall() -> Any: + cached = await cache.get(cache_key, default=MISS) + if cached is not MISS: + return cached + result = func(*args, **kwargs) + await cache.set(cache_key, result, expire=ttl) + return result + + return asyncio.run(cachedCall()) return wrapper # type: ignore[return-value] diff --git a/tests/test_api_key_quota_atomic.py b/tests/test_api_key_quota_atomic.py index e840d25..4ccd4ce 100644 --- a/tests/test_api_key_quota_atomic.py +++ b/tests/test_api_key_quota_atomic.py @@ -5,19 +5,20 @@ """ import asyncio +import hashlib import pytest from unittest.mock import patch, MagicMock from fastapi import HTTPException from sqlalchemy import update from main.models.stocksapi_key import StocksAPIKey -from main.app.stocks_api.key import verifyAPIKey, hashKey +from main.app.stocks_api.key import verifyAPIKey @pytest.fixture def sampleKeyData(): """Sample API key data for tests.""" - return {"apiKey": hashKey("test_key_12345"), "userId": 1, "requestLimit": 100, "currentUsage": 0} + return {"apiKey": hashlib.sha256("test_key_12345".encode()).hexdigest(), "userId": 1, "requestLimit": 100, "currentUsage": 0} class TestAtomicQuotaIncrement: @@ -38,7 +39,7 @@ def test_normal_quota_check_works(self, dbSession, sampleKeyData): result = dbSession.execute( update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashKey("test_key_12345")) + .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) .values(currentUsage=StocksAPIKey.currentUsage + 1) ) @@ -61,7 +62,7 @@ def test_atomic_increment_prevents_overuse(self, dbSession, sampleKeyData): # First request should succeed (99 -> 100) result1 = dbSession.execute( update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashKey("test_key_12345")) + .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) .values(currentUsage=StocksAPIKey.currentUsage + 1) ) @@ -74,7 +75,7 @@ def test_atomic_increment_prevents_overuse(self, dbSession, sampleKeyData): # Second request should fail (100 is not < 100) result2 = dbSession.execute( update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashKey("test_key_12345")) + .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) .values(currentUsage=StocksAPIKey.currentUsage + 1) ) @@ -103,7 +104,7 @@ def test_concurrent_requests_serialized_at_db_level(self, dbSession, sampleKeyDa # Both should succeed because 98 < 100 and 99 < 100 result1 = dbSession.execute( update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashKey("test_key_12345")) + .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) .values(currentUsage=StocksAPIKey.currentUsage + 1) ) @@ -111,7 +112,7 @@ def test_concurrent_requests_serialized_at_db_level(self, dbSession, sampleKeyDa result2 = dbSession.execute( update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashKey("test_key_12345")) + .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) .values(currentUsage=StocksAPIKey.currentUsage + 1) ) @@ -136,7 +137,7 @@ def test_request_at_exact_quota_limit(self, dbSession, sampleKeyData): # Request should fail (100 is not < 100) result = dbSession.execute( update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashKey("test_key_12345")) + .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) .values(currentUsage=StocksAPIKey.currentUsage + 1) ) @@ -206,7 +207,7 @@ def test_increment_from_zero(self, dbSession, sampleKeyData): result = dbSession.execute( update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashKey("test_key_12345")) + .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) .values(currentUsage=StocksAPIKey.currentUsage + 1) ) From 870f2f89ca1e791b1964a2b3dbd49101e9812d34 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:21:55 -0300 Subject: [PATCH 11/57] simplify chat history compact sandbox controller auth and startup helpers --- main/app/authentication/constants.py | 4 -- main/app/authentication/util.py | 7 +-- main/app/prometheus/agent.py | 37 ++++++++++----- main/app/prometheus/chat.py | 32 ++----------- main/app/prometheus/compact.py | 30 ++++++------ main/app/prometheus/sandbox.py | 8 +++- main/app/prometheus/tools.py | 3 +- main/controller/stocksapi_controller.py | 26 ++++------ main/utils/connectivity.py | 3 -- run.py | 55 ++++++++++------------ tests/conftest.py | 10 ++-- tests/test_controllers_coverage.py | 4 +- tests/test_prometheus_auth_coverage.py | 13 +++-- tests/test_streammessage_no_chatsession.py | 8 ++-- 14 files changed, 106 insertions(+), 134 deletions(-) diff --git a/main/app/authentication/constants.py b/main/app/authentication/constants.py index c2fbe15..cbb9107 100644 --- a/main/app/authentication/constants.py +++ b/main/app/authentication/constants.py @@ -1,8 +1,4 @@ from typing import Literal -from config import Config - -SECRET_KEY = Config.USER.JWT_SECRET_KEY -ALGORITHM = "HS256" SESSION_EXPIRY_DAYS = 30 TOKEN_EXPIRY_HOURS = SESSION_EXPIRY_DAYS * 24 diff --git a/main/app/authentication/util.py b/main/app/authentication/util.py index 50ddf56..082b2a8 100644 --- a/main/app/authentication/util.py +++ b/main/app/authentication/util.py @@ -5,7 +5,8 @@ import bcrypt import jwt -from main.app.authentication.constants import SECRET_KEY, ALGORITHM, TOKEN_EXPIRY_HOURS, COOKIE_NAME +from config import Config +from main.app.authentication.constants import TOKEN_EXPIRY_HOURS, COOKIE_NAME logger = logging.getLogger(__name__) @@ -36,13 +37,13 @@ def createAccessToken(data: dict | None, expiresDelta: timedelta | None = None): payload = data.copy() payload["exp"] = datetime.now(timezone.utc) + expiresDelta - token = jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM) + token = jwt.encode(payload, Config.USER.JWT_SECRET_KEY, algorithm="HS256") return token, expiresDelta def verifyAccessToken(token: str) -> dict: try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) + payload = jwt.decode(token, Config.USER.JWT_SECRET_KEY, algorithms=["HS256"]) return payload except jwt.ExpiredSignatureError: raise HTTPException(status_code=401, detail="Token expired") diff --git a/main/app/prometheus/agent.py b/main/app/prometheus/agent.py index 59e1549..e6c18de 100644 --- a/main/app/prometheus/agent.py +++ b/main/app/prometheus/agent.py @@ -294,7 +294,7 @@ async def extract() -> None: userText = str(query) if file and file.get("name"): userText += f"\n\n[ATTACHED FILES: {file['name']}]" - PrometheusChatManager.saveMessage(db, str(sessionId), "user", userText) + PrometheusChatManager.appendHistory(db, str(sessionId), {"role": "user", "content": userText}) mcpClients, sessions = await clientPool.getClients() chat = self.makeChat(sessions, history, system_prompt=system_prompt, disable_automatic_function_calling=True) @@ -339,11 +339,14 @@ async def extract() -> None: if sessionId: try: - PrometheusChatManager.saveLoopEvent( + PrometheusChatManager.appendHistory( db, str(sessionId), - "tool_call", - {"toolName": fc.name, "args": fc.args or {}, "turn": turn}, + { + "role": "loop_event", + "eventType": "tool_call", + "metadata": {"toolName": fc.name, "args": fc.args or {}, "turn": turn}, + }, ) except Exception as e: logger.error(f"Failed to persist tool_call event: {e}") @@ -375,11 +378,14 @@ async def extract() -> None: if sessionId: try: - PrometheusChatManager.saveLoopEvent( + PrometheusChatManager.appendHistory( db, str(sessionId), - "tool_result", - {"toolName": fc.name, "result": result, "turn": turn}, + { + "role": "loop_event", + "eventType": "tool_result", + "metadata": {"toolName": fc.name, "result": result, "turn": turn}, + }, ) except Exception as e: logger.error(f"Failed to persist tool_result event: {e}") @@ -405,14 +411,17 @@ async def extract() -> None: if sessionId: try: - PrometheusChatManager.saveLoopEvent( + PrometheusChatManager.appendHistory( db, str(sessionId), - "turn_end", { - "turnNumber": turn, - "durationMs": int(time.time() * 1000) - turn_start, - "toolsUsed": tools_used, + "role": "loop_event", + "eventType": "turn_end", + "metadata": { + "turnNumber": turn, + "durationMs": int(time.time() * 1000) - turn_start, + "toolsUsed": tools_used, + }, }, ) except Exception as e: @@ -427,6 +436,8 @@ async def extract() -> None: finally: if fullText: try: - PrometheusChatManager.saveMessage(db, str(sessionId), "assistant", fullText) + PrometheusChatManager.appendHistory( + db, str(sessionId), {"role": "assistant", "content": fullText} + ) except Exception as e: logger.error("Failed to persist assistant message: %s", e) diff --git a/main/app/prometheus/chat.py b/main/app/prometheus/chat.py index 97674da..ce62286 100644 --- a/main/app/prometheus/chat.py +++ b/main/app/prometheus/chat.py @@ -49,47 +49,23 @@ def updateSessionTitle(cls, db: Session, sessionId: str, title: str): return True @classmethod - def saveMessage(cls, db: Session, sessionId: str, role: str, content: str, metadata: dict | None = None): + def appendHistory(cls, db: Session, sessionId: str, entry: dict): session = db.query(PrometheusSession).filter(PrometheusSession.sessionId == sessionId).first() if session: if session.history is None: session.history = [] - message = { - "role": role, - "content": content, - "metadata": metadata, - "timestamp": datetime.now().isoformat(), - } + entry["timestamp"] = datetime.now().isoformat() - session.history.append(message) + session.history.append(entry) flag_modified(session, "history") session.lastActivity = datetime.now() # type: ignore[assignment] db.commit() else: - logger.error(f"Session {sessionId} not found for saveMessage") - - @classmethod - def saveLoopEvent(cls, db: Session, sessionId: str, eventType: str, metadata: dict): - session = db.query(PrometheusSession).filter(PrometheusSession.sessionId == sessionId).first() - - if session: - if session.history is None: - session.history = [] - - event = { - "role": "loop_event", - "eventType": eventType, - "metadata": metadata, - "timestamp": datetime.now().isoformat(), - } - - session.history.append(event) - flag_modified(session, "history") - db.commit() + logger.error(f"Session {sessionId} not found for appendHistory") @classmethod def getHistory(cls, db: Session, sessionId: str, limit: int = 20, since: datetime | None = None): diff --git a/main/app/prometheus/compact.py b/main/app/prometheus/compact.py index 130aa71..fedcd5e 100644 --- a/main/app/prometheus/compact.py +++ b/main/app/prometheus/compact.py @@ -18,6 +18,8 @@ FALLBACK_FIELDS = ("P/L", "P/VP", "ROE", "DY", "LPA", "VPA", "PRECO", "INVESTING SCORE") +FALLBACK_METRIC_RE = re.compile(r"\b(" + "|".join(re.escape(f) for f in FALLBACK_FIELDS) + r")\b") + DECISION_KEYWORDS = re.compile( r"(?:prefiro|prefere|quero|gostaria|sempre|nunca|quando|" r"não use|use ao invés|troque|prefira|defina|configure|" @@ -112,20 +114,18 @@ def getMetricRegex() -> re.Pattern: return metricRegex +def dedup(items: list) -> list: + return list(dict.fromkeys(items)) + + def extractTickers(text: str) -> list[str]: - return list(dict.fromkeys(re.compile(r"\b([A-Z]{4}[0-9])\b").findall(text))) + return dedup(re.compile(r"\b([A-Z]{4}[0-9])\b").findall(text)) def extractMetrics(text: str, useRegistry: bool = False) -> list[str]: - if useRegistry: - regex = getMetricRegex() - else: - fallbackEscaped = [re.escape(f) for f in FALLBACK_FIELDS if len(f) > 1] - fallbackEscaped.sort(key=len, reverse=True) - fallbackPattern = r"\b(" + "|".join(fallbackEscaped) + r")\b" - regex = re.compile(fallbackPattern) + regex = getMetricRegex() if useRegistry else FALLBACK_METRIC_RE - return list(dict.fromkeys(regex.findall(text))) + return dedup(regex.findall(text)) def extractDecisions(userMessages: list[dict]) -> list[str]: @@ -139,7 +139,7 @@ def extractDecisions(userMessages: list[dict]) -> list[str]: sent = sent.strip() if sent and DECISION_KEYWORDS.search(sent): decisions.append(sent[:200]) - return list(dict.fromkeys(decisions))[:10] + return dedup(decisions)[:10] def extractSnapshots(toolResults: list[dict]) -> list[str]: @@ -152,7 +152,7 @@ def extractSnapshots(toolResults: list[dict]) -> list[str]: unit = match.group(3) or "" if any(kw in label.upper() for kw in ["P/L", "ROE", "DY", "PRECO", "LPA", "VPA"]): snapshots.append(f"{label}: {value}{unit}") - return list(dict.fromkeys(snapshots))[:10] + return dedup(snapshots)[:10] def extractToolCalls(loopEvents: list[dict]) -> list[str]: @@ -168,7 +168,7 @@ def extractToolCalls(loopEvents: list[dict]) -> list[str]: calls.append(f"{toolName}({ticker})") else: calls.append(toolName) - return list(dict.fromkeys(calls))[:15] + return dedup(calls)[:15] def buildSummary( @@ -233,7 +233,7 @@ def extractEpisode(self, chunk: list[dict]) -> dict: tools = extractToolCalls(loopEvents) summary = buildSummary(tickers, tools, decisions, metrics, snapshots) - entities = list(dict.fromkeys(tickers + metrics)) + entities = dedup(tickers + metrics) return { "summary": summary, @@ -262,8 +262,8 @@ def consolidate(self, episodes: list[dict]) -> list[dict]: "id": f"ep_{uuid.uuid4().hex[:8]}", "time": datetime.now().isoformat(), "summary": mergedSummary[:1000], - "keyDecisions": list(dict.fromkeys(allDecisions)), - "entities": list(dict.fromkeys(allEntities)), + "keyDecisions": dedup(allDecisions), + "entities": dedup(allEntities), } return [merged] + recent diff --git a/main/app/prometheus/sandbox.py b/main/app/prometheus/sandbox.py index 85fe44f..c7f0c51 100644 --- a/main/app/prometheus/sandbox.py +++ b/main/app/prometheus/sandbox.py @@ -22,9 +22,13 @@ def lockFor(userId: int) -> asyncio.Lock: def getClient() -> AsyncClient: + forgeUrl = Config.PROMETHEUS.FORGEVM_URL + forgeToken = Config.PROMETHEUS.FORGEVM_API_TOKEN + if forgeUrl and not forgeToken: + raise RuntimeError(f"FORGEVM_URL is set ({forgeUrl}) but FORGEVM_API_TOKEN is empty; set FORGEVM_API_TOKEN or unset FORGEVM_URL for local dev") return AsyncClient( - base_url=Config.PROMETHEUS.FORGEVM_URL, - api_key=Config.PROMETHEUS.FORGEVM_API_TOKEN or None, + base_url=forgeUrl, + api_key=forgeToken or None, timeout=30, ) diff --git a/main/app/prometheus/tools.py b/main/app/prometheus/tools.py index bfac074..0061014 100644 --- a/main/app/prometheus/tools.py +++ b/main/app/prometheus/tools.py @@ -1,6 +1,7 @@ from config import SessionLocal import logging from typing import Any +from urllib.parse import quote from forgevm.exceptions import SandboxNotFound from sqlalchemy.orm import Session @@ -168,8 +169,6 @@ async def serve_file(path: str, **_) -> dict: if not host.exists() or not host.is_file(): return {"error": f"File not found: {path}"} - from urllib.parse import quote - url = f"/prometheus/workspace/download?path={quote(path, safe='/')}" return {"url": url, "markdown": f"[{host.name}]({url})"} diff --git a/main/controller/stocksapi_controller.py b/main/controller/stocksapi_controller.py index ad79456..0f73ba9 100644 --- a/main/controller/stocksapi_controller.py +++ b/main/controller/stocksapi_controller.py @@ -1,10 +1,9 @@ from datetime import datetime, timezone import logging -import orjson from cashews import cache from fastapi import APIRouter, Depends, Query, HTTPException, Response -from fastapi.responses import Response as FastAPIResponse +from fastapi.responses import ORJSONResponse from main.app.stocks_api.query import stocksQuery from main.app.stocks_api.key import verifyAPIKey @@ -20,13 +19,6 @@ router = APIRouter(prefix="/stocks", tags=["Stocks API"]) -class JSONBytesResponse(FastAPIResponse): - media_type = "application/json" - - def render(self, content): - return content if isinstance(content, bytes) else str(content).encode(self.charset) - - @router.get("/health") def health(): updatedAt = stocksCache.lastCacheUpdate @@ -88,7 +80,7 @@ def listFields(): return {"historical": historical, "fundamental": fundamental, "abbreviations": abbreviations, "nested": nested} -@router.get("/historical", operation_id="get_historical", response_class=JSONBytesResponse) +@router.get("/historical", operation_id="get_historical", response_class=ORJSONResponse) @sync_cache(ttl="1h", key="stocks:historical:{search}:{fields}:{dates}:{orderBy}:{limit}:{compact}") def getHistorical( response: Response, @@ -150,10 +142,10 @@ def getHistorical( result = stocksQuery.queryHistorical(search, fields, dates, orderBy, limit) if compact: result = compressResponse(result, "get_historical", {"search": search, "fields": fields, "dates": dates}) - return orjson.dumps(result) + return result -@router.get("/fundamental", operation_id="get_fundamental", response_class=JSONBytesResponse) +@router.get("/fundamental", operation_id="get_fundamental", response_class=ORJSONResponse) @sync_cache(ttl="5m", key="stocks:fundamental:{search}:{fields}:{dates}:{orderBy}:{limit}:{compact}") def getFundamental( response: Response, @@ -220,10 +212,10 @@ def getFundamental( result = stocksQuery.queryFundamental(search, fields, dates, orderBy, limit) if compact: result = compressResponse(result, "get_fundamental", {"search": search, "fields": fields, "dates": dates}) - return orjson.dumps(result) + return result -@router.get("/cotations", operation_id="get_cotations", response_class=JSONBytesResponse) +@router.get("/cotations", operation_id="get_cotations", response_class=ORJSONResponse) @sync_cache(ttl="5m", key="stocks:cotations:{search}:{dates}:{adjusted}:{compact}") def getCotations( response: Response, @@ -276,10 +268,10 @@ def getCotations( result = stocksQuery.queryCotations(search, dates, adjusted) if compact: result = compressResponse(result, "get_cotations", {"search": search, "dates": dates}) - return orjson.dumps(result) + return result -@router.get("/cotations/live", operation_id="get_live_price", response_class=JSONBytesResponse) +@router.get("/cotations/live", operation_id="get_live_price", response_class=ORJSONResponse) @sync_cache(ttl="15s", key="stocks:live:{search}:{compact}") def getLiveCotation( response: Response, @@ -321,4 +313,4 @@ def getLiveCotation( result = stocksQuery.queryLiveCotation(search) if compact: result = compressResponse(result, "get_live_price", {"search": search}) - return orjson.dumps(result) + return result diff --git a/main/utils/connectivity.py b/main/utils/connectivity.py index 6d3af96..b030a2c 100644 --- a/main/utils/connectivity.py +++ b/main/utils/connectivity.py @@ -3,7 +3,6 @@ from requests.exceptions import ConnectionError, Timeout, RequestException from main.utils.http_session import getSession from sqlalchemy import text -from sqlalchemy.exc import OperationalError from config import Config, engine, stocksEngine @@ -33,8 +32,6 @@ def checkDatabaseConnection(): "overflow": pool.overflow(), }, } - except OperationalError as e: - results[name] = {"status": "error", "error": str(e)} except Exception as e: results[name] = {"status": "error", "error": str(e)} diff --git a/run.py b/run.py index 8b37298..b113496 100644 --- a/run.py +++ b/run.py @@ -5,6 +5,8 @@ from contextlib import asynccontextmanager import asyncio +from tenacity import AsyncRetrying, RetryError, stop_after_attempt, wait_fixed + from config import Config, LOCALHOST_ADDRESSES from main.utils.connectivity import checkDatabaseConnection, checkServiceConnection from main.utils.service_manager import runAll @@ -25,40 +27,33 @@ @asynccontextmanager async def lifespan(app: FastAPI): dbConnected = False - for i in range(10): - dbResults = checkDatabaseConnection() - if all(r["status"] == "connected" for r in dbResults.values()): - dbConnected = True - break - logger.info(f"Retrying database connection ({i + 1}/10)") - await asyncio.sleep(3) - - if not dbConnected: + try: + async for attempt in AsyncRetrying(stop=stop_after_attempt(10), wait=wait_fixed(3)): + with attempt: + dbResults = checkDatabaseConnection() + if all(r["status"] == "connected" for r in dbResults.values()): + dbConnected = True + else: + logger.info(f"Retrying database connection ({attempt.retry_state.attempt_number}/10)") + raise ConnectionError("database not ready") + if dbConnected: + break + except RetryError: logger.error("Database connection failed after retries.") else: runMigrations() - if Config.USER.ENABLED: - if Config.USER.HOST in LOCALHOST_ADDRESSES: - AuthenticationService.initialize(Config.USER.PORT) - UserService.initialize(Config.USER.PORT) - else: - if not checkServiceConnection("USER"): - logger.error("Remote connection to the USER Service failed") - - if Config.STOCKS_API.ENABLED: - if Config.STOCKS_API.HOST in LOCALHOST_ADDRESSES: - StocksAPIService.initialize(Config.STOCKS_API.PORT) - else: - if not checkServiceConnection("STOCKS_API"): - logger.error("Remote connection to the STOCKS_API Service failed") - - if Config.PROMETHEUS.ENABLED: - if Config.PROMETHEUS.HOST in LOCALHOST_ADDRESSES: - PrometheusService.initialize(Config.PROMETHEUS.PORT) - else: - if not checkServiceConnection("PROMETHEUS"): - logger.error("Remote connection to the PROMETHEUS Service failed") + services = [ + ("USER", Config.USER, lambda port: (AuthenticationService.initialize(port), UserService.initialize(port))), + ("STOCKS_API", Config.STOCKS_API, StocksAPIService.initialize), + ("PROMETHEUS", Config.PROMETHEUS, PrometheusService.initialize), + ] + for name, cfg, initFn in services: + if cfg.ENABLED: + if cfg.HOST in LOCALHOST_ADDRESSES: + initFn(cfg.PORT) + elif not checkServiceConnection(name): + logger.error(f"Remote connection to the {name} Service failed") if Config.SCRAPER.ENABLED: ScraperService.initialize() diff --git a/tests/conftest.py b/tests/conftest.py index 08a5097..1b6026e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,14 +31,10 @@ def pytest_configure(config): @pytest.fixture(autouse=True) def patch_secret_key(monkeypatch): - import main.app.authentication.constants as auth_constants + from config import Config - if not auth_constants.SECRET_KEY: - monkeypatch.setattr(auth_constants, "SECRET_KEY", "test-secret-key-not-empty") - # util.py imports SECRET_KEY via `from ... import`, creating a separate binding - import main.app.authentication.util as auth_util - - monkeypatch.setattr(auth_util, "SECRET_KEY", "test-secret-key-not-empty") + if not Config.USER.JWT_SECRET_KEY: + monkeypatch.setattr(Config.USER, "JWT_SECRET_KEY", "test-secret-key-not-empty") TEST_DATABASE_URL = "sqlite:///:memory:" diff --git a/tests/test_controllers_coverage.py b/tests/test_controllers_coverage.py index 3469f71..0cb04bf 100644 --- a/tests/test_controllers_coverage.py +++ b/tests/test_controllers_coverage.py @@ -1252,11 +1252,11 @@ class TestVerifyAccessToken: def test_expired_token(self): """Covers lines 48-49: jwt.ExpiredSignatureError.""" import jwt as pyjwt - from main.app.authentication.constants import SECRET_KEY, ALGORITHM + from config import Config from main.app.authentication.util import verifyAccessToken expired_payload = {"userId": "1", "exp": datetime.now() - timedelta(hours=1)} - token = pyjwt.encode(expired_payload, SECRET_KEY, algorithm=ALGORITHM) + token = pyjwt.encode(expired_payload, Config.USER.JWT_SECRET_KEY, algorithm="HS256") from fastapi import HTTPException diff --git a/tests/test_prometheus_auth_coverage.py b/tests/test_prometheus_auth_coverage.py index 5a56653..82e1701 100644 --- a/tests/test_prometheus_auth_coverage.py +++ b/tests/test_prometheus_auth_coverage.py @@ -304,7 +304,9 @@ def test_save_message_found(self): mock_session.history = [] mock_db.query.return_value.filter.return_value.first.return_value = mock_session - PrometheusChatManager.saveMessage(mock_db, "sess-123", "user", "Hello", metadata={"key": "val"}) + PrometheusChatManager.appendHistory( + mock_db, "sess-123", {"role": "user", "content": "Hello", "metadata": {"key": "val"}} + ) assert len(mock_session.history) == 1 assert mock_session.history[0]["role"] == "user" @@ -320,13 +322,14 @@ def test_save_message_history_none(self): mock_session.history = None mock_db.query.return_value.filter.return_value.first.return_value = mock_session - PrometheusChatManager.saveMessage(mock_db, "sess-123", "assistant", "Reply") + PrometheusChatManager.appendHistory( + mock_db, "sess-123", {"role": "assistant", "content": "Reply"} + ) assert mock_session.history == [ { "role": "assistant", "content": "Reply", - "metadata": None, "timestamp": mock_session.history[0]["timestamp"], } ] @@ -338,7 +341,9 @@ def test_save_message_not_found(self): mock_db.query.return_value.filter.return_value.first.return_value = None # Should not raise - PrometheusChatManager.saveMessage(mock_db, "nonexistent", "user", "Hello") + PrometheusChatManager.appendHistory( + mock_db, "nonexistent", {"role": "user", "content": "Hello"} + ) def test_get_history_with_messages(self): from main.app.prometheus.chat import PrometheusChatManager diff --git a/tests/test_streammessage_no_chatsession.py b/tests/test_streammessage_no_chatsession.py index 64ee8cd..9148be6 100644 --- a/tests/test_streammessage_no_chatsession.py +++ b/tests/test_streammessage_no_chatsession.py @@ -169,7 +169,7 @@ async def test_user_message_saved_before_stream_error(self, mock_pool, mock_gena pass # user turn persisted up front; no assistant text accumulated, so only one save - mock_chat.saveMessage.assert_called_once_with(db, "s-err1", "user", "important question") + mock_chat.appendHistory.assert_called_once_with(db, "s-err1", {"role": "user", "content": "important question"}) @pytest.mark.anyio @patch("main.app.prometheus.agent.PrometheusChatManager") @@ -207,6 +207,6 @@ async def fake_stream_with_error(msg): async for _ in gen.streamMessage(query="partial question", sessionId="s-err2", db=db): pass - calls = [c.args for c in mock_chat.saveMessage.call_args_list] - assert (db, "s-err2", "user", "partial question") in calls - assert (db, "s-err2", "assistant", "partial answer ") in calls + calls = [c.args for c in mock_chat.appendHistory.call_args_list] + assert (db, "s-err2", {"role": "user", "content": "partial question"}) in calls + assert (db, "s-err2", {"role": "assistant", "content": "partial answer "}) in calls From 098a77bd8717415d037973bbd330a81c9e53ba6c Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:21:57 -0300 Subject: [PATCH 12/57] normalize TIME column to date strings before cotation filtering --- main/app/stocks_api/query.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main/app/stocks_api/query.py b/main/app/stocks_api/query.py index 21a14ea..5aa1356 100644 --- a/main/app/stocks_api/query.py +++ b/main/app/stocks_api/query.py @@ -91,6 +91,8 @@ def _finalize( if dedupTickers: df = df.drop_duplicates(subset=["TICKER"], keep="first") df = self.deserializeJsonColumns(df) + if "TIME" in df.columns: + df["TIME"] = pd.to_datetime(df["TIME"]).dt.strftime("%Y-%m-%d") if cotationCol and cotationCol in df.columns: startDate, endDate = parseDateRange(dates) if startDate and endDate: From 8386eca22b68b09dae5024746da38295214199e9 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:25:41 -0300 Subject: [PATCH 13/57] remove uncalled write_bytes helper from sandbox manager --- main/app/prometheus/sandbox.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/main/app/prometheus/sandbox.py b/main/app/prometheus/sandbox.py index c7f0c51..f37f6fd 100644 --- a/main/app/prometheus/sandbox.py +++ b/main/app/prometheus/sandbox.py @@ -190,17 +190,6 @@ def list_files(userId: int, path: str = "/workspace") -> dict: entries = [str(sandboxPath(item, userId)) for item in sorted(host.rglob("*")) if item.is_file()] return {"entries": entries} - @staticmethod - def write_bytes(userId: int, path: str, content: bytes) -> bool: - try: - host = hostPath(userId, path) - host.parent.mkdir(parents=True, exist_ok=True) - host.write_bytes(content) - return True - except Exception as e: - logger.warning("Failed to write %s: %s", path, e) - return False - @staticmethod def delete_file(userId: int, path: str) -> bool: try: From 9d1d368d06bd9ca57355f146e71a6c990d3c8f85 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:41:10 -0300 Subject: [PATCH 14/57] merge micro test files into module mates --- tests/test_compact.py | 19 ++++++ tests/test_compact_retry.py | 20 ------ tests/test_matrix_cache.py | 18 ----- tests/test_memory_manager.py | 26 +++++++- tests/test_memory_prompt_guidance.py | 12 ---- tests/test_prometheus_agent_context.py | 13 +++- tests/test_roles.py | 69 ++++++++++++++++--- tests/test_roles_coverage.py | 91 -------------------------- tests/test_vector_normalize.py | 58 ---------------- tests/test_vector_utils.py | 58 +++++++++++++++- 10 files changed, 174 insertions(+), 210 deletions(-) delete mode 100644 tests/test_compact_retry.py delete mode 100644 tests/test_matrix_cache.py delete mode 100644 tests/test_memory_prompt_guidance.py delete mode 100644 tests/test_roles_coverage.py delete mode 100644 tests/test_vector_normalize.py diff --git a/tests/test_compact.py b/tests/test_compact.py index 21b67a9..6aed002 100644 --- a/tests/test_compact.py +++ b/tests/test_compact.py @@ -1,6 +1,7 @@ import time import pytest from unittest.mock import patch, MagicMock +import main.app.prometheus.compact as compactMod from main.app.prometheus.compact import ( extractTickers, extractMetrics, @@ -14,6 +15,7 @@ PrometheusCompactor, EPISODE_CAP, getMetricRegex, + loadFieldData, ) @@ -305,3 +307,20 @@ def test_compact_creates_episode_above_budget(self): assert result["id"].startswith("ep_") assert "summary" in result mockDb.commit.assert_called_once() + + +class TestLoadFieldDataRetry: + def test_retryAfterFailure(self): + compactMod.fieldData = None + fakeResponse = MagicMock() + fakeResponse.json.return_value = {"historical": {"LUCRO LIQUIDO": [2023]}, "fundamental": ["P/L"]} + mockSession = MagicMock() + mockSession.get.side_effect = [Exception("boom"), fakeResponse] + with patch("main.app.prometheus.compact.getSession", return_value=mockSession): + first = loadFieldData() + assert first == {"historical": [], "fundamental": []} + assert compactMod.fieldData is None + second = loadFieldData() + assert "LUCRO LIQUIDO" in second["historical"] + assert second["fundamental"] == ["P/L"] + compactMod.fieldData = None diff --git a/tests/test_compact_retry.py b/tests/test_compact_retry.py deleted file mode 100644 index 6d93389..0000000 --- a/tests/test_compact_retry.py +++ /dev/null @@ -1,20 +0,0 @@ -from unittest.mock import patch, MagicMock -import main.app.prometheus.compact as compactMod -from main.app.prometheus.compact import loadFieldData - - -class TestLoadFieldDataRetry: - def test_retryAfterFailure(self): - compactMod.fieldData = None - fakeResponse = MagicMock() - fakeResponse.json.return_value = {"historical": {"LUCRO LIQUIDO": [2023]}, "fundamental": ["P/L"]} - mockSession = MagicMock() - mockSession.get.side_effect = [Exception("boom"), fakeResponse] - with patch("main.app.prometheus.compact.getSession", return_value=mockSession): - first = loadFieldData() - assert first == {"historical": [], "fundamental": []} - assert compactMod.fieldData is None - second = loadFieldData() - assert "LUCRO LIQUIDO" in second["historical"] - assert second["fundamental"] == ["P/L"] - compactMod.fieldData = None diff --git a/tests/test_matrix_cache.py b/tests/test_matrix_cache.py deleted file mode 100644 index 3483a0a..0000000 --- a/tests/test_matrix_cache.py +++ /dev/null @@ -1,18 +0,0 @@ -import numpy as np -from main.app.prometheus.memory import getMatrix, invalidateUser, clearAll - - -def test_cache_hitAndInvalidate(): - clearAll() - calls = {"n": 0} - - def loader(): - calls["n"] += 1 - return ([1, 2], np.eye(2, dtype=np.float32)) - - ids1, m1 = getMatrix(3, loader) - ids2, m2 = getMatrix(3, loader) - assert calls["n"] == 1 and ids1 == ids2 - invalidateUser(3) - getMatrix(3, loader) - assert calls["n"] == 2 diff --git a/tests/test_memory_manager.py b/tests/test_memory_manager.py index 10a50fc..30378f3 100644 --- a/tests/test_memory_manager.py +++ b/tests/test_memory_manager.py @@ -1,7 +1,14 @@ import pytest import numpy as np from datetime import datetime, timezone -from main.app.prometheus.memory import PrometheusMemory as MemoryManager, MEMORY_LIMIT_BASIC, MEMORY_LIMIT_EXTENDED +from main.app.prometheus.memory import ( + PrometheusMemory as MemoryManager, + MEMORY_LIMIT_BASIC, + MEMORY_LIMIT_EXTENDED, + getMatrix, + invalidateUser, + clearAll, +) from main.models.memory import PrometheusMemory @@ -145,3 +152,20 @@ def test_search_after_create(self, dbSession): results = MemoryManager.fullTextSearch(dbSession, 1, "PETR4", 10) assert len(results) >= 1 assert any("PETR4" in r["memoryValue"] for r in results) + + +class TestMatrixCache: + def test_cache_hitAndInvalidate(self): + clearAll() + calls = {"n": 0} + + def loader(): + calls["n"] += 1 + return ([1, 2], np.eye(2, dtype=np.float32)) + + ids1, m1 = getMatrix(3, loader) + ids2, m2 = getMatrix(3, loader) + assert calls["n"] == 1 and ids1 == ids2 + invalidateUser(3) + getMatrix(3, loader) + assert calls["n"] == 2 diff --git a/tests/test_memory_prompt_guidance.py b/tests/test_memory_prompt_guidance.py deleted file mode 100644 index 7090899..0000000 --- a/tests/test_memory_prompt_guidance.py +++ /dev/null @@ -1,12 +0,0 @@ -from main.app.prometheus.agent import SYSTEM_PROMPT - - -def test_prompt_guides_search_before_answer(): - assert "search_memory" in SYSTEM_PROMPT - assert "antes de responder" in SYSTEM_PROMPT - - -def test_prompt_guides_save_when_and_types(): - assert "save_memory" in SYSTEM_PROMPT - assert "preference" in SYSTEM_PROMPT - assert "analysis" in SYSTEM_PROMPT diff --git a/tests/test_prometheus_agent_context.py b/tests/test_prometheus_agent_context.py index c7eda1e..e05bc4e 100644 --- a/tests/test_prometheus_agent_context.py +++ b/tests/test_prometheus_agent_context.py @@ -5,7 +5,7 @@ from datetime import datetime from unittest.mock import patch, MagicMock -from main.app.prometheus.agent import Prometheus +from main.app.prometheus.agent import Prometheus, SYSTEM_PROMPT from main.models.prometheus import PrometheusSession @@ -112,3 +112,14 @@ def test_client_created_once_and_shared(self, mock_config, mock_genai): second = Prometheus() assert first.client is second.client mock_genai.Client.assert_called_once_with(api_key="test-key") + + +class TestPromptMemoryGuidance: + def test_prompt_guides_search_before_answer(self): + assert "search_memory" in SYSTEM_PROMPT + assert "antes de responder" in SYSTEM_PROMPT + + def test_prompt_guides_save_when_and_types(self): + assert "save_memory" in SYSTEM_PROMPT + assert "preference" in SYSTEM_PROMPT + assert "analysis" in SYSTEM_PROMPT diff --git a/tests/test_roles.py b/tests/test_roles.py index 2a5c66d..ed3d8ec 100644 --- a/tests/test_roles.py +++ b/tests/test_roles.py @@ -1,3 +1,5 @@ +import pytest +from fastapi import HTTPException from main.utils.roles import Permission, Roles @@ -7,12 +9,6 @@ def test_permission_enum_values(self): assert Permission.USE_PROMETHEUS > 0 assert Permission.PROMETHEUS_EXTENDED_MEMORIES > 0 - def test_permission_all_includes_all(self): - allPerms = Permission.ALL() - assert allPerms & Permission.USE_PROMETHEUS - assert allPerms & Permission.PROMETHEUS_EXTENDED_MEMORIES - - class TestRoles: def test_user_has_no_permissions(self): assert Roles.USER == Permission.NONE @@ -63,8 +59,65 @@ def test_check_access_multiple_roles(self): result = Roles.checkAccess(["USER", "PREMIUM"], Permission.USE_PROMETHEUS) assert result is True - def test_role_composition_premium_and_user(self): + def test_check_access_unknown_role_alone_returns_false(self): + assert Roles.checkAccess(["NONEXISTENT"], Permission.USE_PROMETHEUS) is False + + def test_check_access_admin_skips_other_roles(self): + assert Roles.checkAccess(["ADMIN", "USER"], Permission.USE_PROMETHEUS) is True + + +class TestRequirePermission: + def test_raises_403_when_missing(self): + import asyncio + + checker = Roles.requirePermission(Permission.USE_PROMETHEUS) + + async def run(): + try: + await checker({"roles": ["USER"]}) + return None + except HTTPException as e: + return e + + result = asyncio.run(run()) + assert result is not None + assert result.status_code == 403 + + def test_passes_when_has_permission(self): + import asyncio + + checker = Roles.requirePermission(Permission.USE_PROMETHEUS) + + async def run(): + try: + result = await checker({"roles": ["PREMIUM"]}) + return result + except HTTPException: + return None + + result = asyncio.run(run()) + assert result is not None + assert result["roles"] == ["PREMIUM"] + + +class TestPermissionAll: + def test_all_includes_all_permissions(self): + all_perm = Permission.ALL() + for perm in Permission: + if perm == Permission.NONE: + continue + assert all_perm & perm, f"ALL() missing {perm.name}" + + +class TestRolesHierarchy: + def test_premium_includes_user(self): assert Roles.PREMIUM & Roles.USER == Roles.USER - def test_role_composition_enterprise_and_starter(self): + def test_enterprise_includes_starter(self): assert Roles.DEVELOPER_ENTERPRISE & Roles.DEVELOPER_STARTER == Roles.DEVELOPER_STARTER + + def test_admin_includes_all(self): + for perm in Permission: + if perm == Permission.NONE: + continue + assert Roles.ADMIN & perm, f"ADMIN missing {perm.name}" diff --git a/tests/test_roles_coverage.py b/tests/test_roles_coverage.py deleted file mode 100644 index 2fd057d..0000000 --- a/tests/test_roles_coverage.py +++ /dev/null @@ -1,91 +0,0 @@ -"""Tests for main/utils/roles.py — covers requirePermission and edge cases.""" - -import pytest -from fastapi import HTTPException -from main.utils.roles import Permission, Roles - - -class TestCheckAccess: - def test_admin_always_passes(self): - assert Roles.checkAccess(["ADMIN"], Permission.USE_PROMETHEUS) is True - - def test_user_lacks_prometheus(self): - assert Roles.checkAccess(["USER"], Permission.USE_PROMETHEUS) is False - - def test_premium_has_prometheus(self): - assert Roles.checkAccess(["PREMIUM"], Permission.USE_PROMETHEUS) is True - - def test_premium_has_extended_memories(self): - assert Roles.checkAccess(["PREMIUM"], Permission.PROMETHEUS_EXTENDED_MEMORIES) is True - - def test_developer_starter_lacks_prometheus(self): - assert Roles.checkAccess(["DEVELOPER_STARTER"], Permission.USE_PROMETHEUS) is False - - def test_unknown_role_ignored(self): - assert Roles.checkAccess(["NONEXISTENT"], Permission.USE_PROMETHEUS) is False - - def test_multiple_roles_combined(self): - assert Roles.checkAccess(["USER", "PREMIUM"], Permission.USE_PROMETHEUS) is True - - def test_empty_roles(self): - assert Roles.checkAccess([], Permission.USE_PROMETHEUS) is False - - def test_admin_skips_other_roles(self): - assert Roles.checkAccess(["ADMIN", "USER"], Permission.USE_PROMETHEUS) is True - - -class TestRequirePermission: - def test_raises_403_when_missing(self): - import asyncio - - checker = Roles.requirePermission(Permission.USE_PROMETHEUS) - - async def run(): - try: - await checker({"roles": ["USER"]}) - return None - except HTTPException as e: - return e - - result = asyncio.run(run()) - assert result is not None - assert result.status_code == 403 - - def test_passes_when_has_permission(self): - import asyncio - - checker = Roles.requirePermission(Permission.USE_PROMETHEUS) - - async def run(): - try: - result = await checker({"roles": ["PREMIUM"]}) - return result - except HTTPException: - return None - - result = asyncio.run(run()) - assert result is not None - assert result["roles"] == ["PREMIUM"] - - -class TestPermissionAll: - def test_all_includes_all_permissions(self): - all_perm = Permission.ALL() - for perm in Permission: - if perm == Permission.NONE: - continue - assert all_perm & perm, f"ALL() missing {perm.name}" - - -class TestRolesHierarchy: - def test_premium_includes_user(self): - assert Roles.PREMIUM & Roles.USER == Roles.USER - - def test_enterprise_includes_starter(self): - assert Roles.DEVELOPER_ENTERPRISE & Roles.DEVELOPER_STARTER == Roles.DEVELOPER_STARTER - - def test_admin_includes_all(self): - for perm in Permission: - if perm == Permission.NONE: - continue - assert Roles.ADMIN & perm, f"ADMIN missing {perm.name}" diff --git a/tests/test_vector_normalize.py b/tests/test_vector_normalize.py deleted file mode 100644 index ef330d7..0000000 --- a/tests/test_vector_normalize.py +++ /dev/null @@ -1,58 +0,0 @@ -import numpy as np -import pytest -from main.app.prometheus.vector import ( - decodeEmbeddings, - normalizeRows, - batchCosineSimilarity, - toVectorString, - fromVectorString, -) - - -def test_normalizeRows_unitNormAndZeroGuard(): - m = normalizeRows(np.array([[3.0, 4.0], [0.0, 0.0]], dtype=np.float32)) - assert abs(float(np.linalg.norm(m[0])) - 1.0) < 1e-5 - assert float(np.linalg.norm(m[1])) == 0.0 - - -def test_dotEqualsCosineOnUnnormalized(): - rng = np.random.default_rng(7) - mat = rng.normal(size=(8, 16)).astype(np.float32) * 5.0 - q = (rng.normal(size=(16,)) * 5.0).tolist() - got = batchCosineSimilarity(q, mat) - qn = np.array(q, dtype=np.float32) - qn /= np.linalg.norm(qn) - mn = mat / np.linalg.norm(mat, axis=1, keepdims=True) - np.testing.assert_allclose(got, mn @ qn, rtol=1e-4, atol=1e-5) - - -def test_decodeEmbeddings_listMatchesBytes(): - rng = np.random.default_rng(11) - mat = rng.normal(size=(4, 8)).astype(np.float32) - byteRows = [r.tobytes() for r in mat] - listRows = [r.tolist() for r in mat] - fromBytes = decodeEmbeddings(byteRows) - fromLists = decodeEmbeddings(listRows) - np.testing.assert_allclose(fromLists, fromBytes, rtol=1e-6, atol=1e-7) - np.testing.assert_allclose(fromLists, mat, rtol=1e-6, atol=1e-7) - - -def test_decodeEmbeddings_mixedDimsRaise(): - with pytest.raises(ValueError): - decodeEmbeddings([[1.0, 2.0, 3.0], [1.0, 2.0]]) - - -def test_decodeEmbeddings_emptyReturnsZeroRows(): - got = decodeEmbeddings([]) - assert got.shape == (0, 0) - assert got.dtype == np.float32 - - -def test_codec_roundTrip(): - vec = [0.5, -0.25, 0.125] - assert fromVectorString(toVectorString(vec), dims=3) == vec - - -def test_codec_rejectsBadDims(): - with pytest.raises(ValueError): - fromVectorString("[0.1,0.2]", dims=3) diff --git a/tests/test_vector_utils.py b/tests/test_vector_utils.py index f7ae480..120f22f 100644 --- a/tests/test_vector_utils.py +++ b/tests/test_vector_utils.py @@ -1,6 +1,13 @@ import numpy as np import pytest -from main.app.prometheus.vector import batchCosineSimilarity, contentHash +from main.app.prometheus.vector import ( + batchCosineSimilarity, + contentHash, + decodeEmbeddings, + normalizeRows, + toVectorString, + fromVectorString, +) class TestBatchCosineSimilarity: @@ -46,3 +53,52 @@ def test_hex_format(self): h = contentHash("test") assert len(h) == 32 assert all(c in "0123456789abcdef" for c in h) + + +def test_normalizeRows_unitNormAndZeroGuard(): + m = normalizeRows(np.array([[3.0, 4.0], [0.0, 0.0]], dtype=np.float32)) + assert abs(float(np.linalg.norm(m[0])) - 1.0) < 1e-5 + assert float(np.linalg.norm(m[1])) == 0.0 + + +def test_dotEqualsCosineOnUnnormalized(): + rng = np.random.default_rng(7) + mat = rng.normal(size=(8, 16)).astype(np.float32) * 5.0 + q = (rng.normal(size=(16,)) * 5.0).tolist() + got = batchCosineSimilarity(q, mat) + qn = np.array(q, dtype=np.float32) + qn /= np.linalg.norm(qn) + mn = mat / np.linalg.norm(mat, axis=1, keepdims=True) + np.testing.assert_allclose(got, mn @ qn, rtol=1e-4, atol=1e-5) + + +def test_decodeEmbeddings_listMatchesBytes(): + rng = np.random.default_rng(11) + mat = rng.normal(size=(4, 8)).astype(np.float32) + byteRows = [r.tobytes() for r in mat] + listRows = [r.tolist() for r in mat] + fromBytes = decodeEmbeddings(byteRows) + fromLists = decodeEmbeddings(listRows) + np.testing.assert_allclose(fromLists, fromBytes, rtol=1e-6, atol=1e-7) + np.testing.assert_allclose(fromLists, mat, rtol=1e-6, atol=1e-7) + + +def test_decodeEmbeddings_mixedDimsRaise(): + with pytest.raises(ValueError): + decodeEmbeddings([[1.0, 2.0, 3.0], [1.0, 2.0]]) + + +def test_decodeEmbeddings_emptyReturnsZeroRows(): + got = decodeEmbeddings([]) + assert got.shape == (0, 0) + assert got.dtype == np.float32 + + +def test_codec_roundTrip(): + vec = [0.5, -0.25, 0.125] + assert fromVectorString(toVectorString(vec), dims=3) == vec + + +def test_codec_rejectsBadDims(): + with pytest.raises(ValueError): + fromVectorString("[0.1,0.2]", dims=3) From e8c75681b436352b6da1dfc8fa13d80d49df8ef6 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:44:31 -0300 Subject: [PATCH 15/57] trim dead ci docker and compose lines --- Dockerfile | 3 --- ci.ps1 | 9 +-------- docker-compose.yml | 2 -- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index cad110b..dad9443 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,7 +38,4 @@ WORKDIR / COPY . . -# defer embedding model download to runtime — saves ~500MB from image -# RUN python -c "from main.utils.models.loader import getEmbeddingModel; getEmbeddingModel()" - CMD ["python", "run.py"] diff --git a/ci.ps1 b/ci.ps1 index 061eb6f..fbd6827 100644 --- a/ci.ps1 +++ b/ci.ps1 @@ -45,12 +45,6 @@ function Write-Fail { $script:failed += $label } -function Write-Fix { - param([string]$label) - Write-Host " FIXED $label" -ForegroundColor Yellow - $script:fixed += $label -} - function Run-Check { param([string]$label, [string]$cmd, [bool]$critical = $true) Write-Step $label @@ -120,8 +114,7 @@ if ($runAll -or $Typecheck) { if ($Fast) { Write-Step "mypy (skipped in fast mode)" } else { - # Run mypy with --no-error-summary for cleaner output - # mypy doesn't have an auto-fix mode, but we show clear errors + # mypy has no auto-fix mode; errors print inline below Write-Step "mypy Typecheck" $mypyOutput = & mypy main/ 2>&1 $mypyExit = $LASTEXITCODE diff --git a/docker-compose.yml b/docker-compose.yml index f4203e1..86dc99e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,8 +42,6 @@ services: build: context: . dockerfile: Dockerfile - cache_from: - - server-api:latest restart: always ports: - "8000:8000" From f49252b5cedbe3a3276c97c69ebe63c16de5e32b Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:55:48 -0300 Subject: [PATCH 16/57] restore write_bytes helper used by workspace tests --- main/app/prometheus/sandbox.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/main/app/prometheus/sandbox.py b/main/app/prometheus/sandbox.py index f37f6fd..c7f0c51 100644 --- a/main/app/prometheus/sandbox.py +++ b/main/app/prometheus/sandbox.py @@ -190,6 +190,17 @@ def list_files(userId: int, path: str = "/workspace") -> dict: entries = [str(sandboxPath(item, userId)) for item in sorted(host.rglob("*")) if item.is_file()] return {"entries": entries} + @staticmethod + def write_bytes(userId: int, path: str, content: bytes) -> bool: + try: + host = hostPath(userId, path) + host.parent.mkdir(parents=True, exist_ok=True) + host.write_bytes(content) + return True + except Exception as e: + logger.warning("Failed to write %s: %s", path, e) + return False + @staticmethod def delete_file(userId: int, path: str) -> bool: try: From c87942b297699010ff0e618fab7b162a53ee9a67 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:55:51 -0300 Subject: [PATCH 17/57] remove write-never fixed counter from ci --- ci.ps1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ci.ps1 b/ci.ps1 index fbd6827..c9ea6c4 100644 --- a/ci.ps1 +++ b/ci.ps1 @@ -23,7 +23,6 @@ param( $ErrorActionPreference = "Continue" $script:failed = @() $script:passed = @() -$script:fixed = @() function Write-Step { param([string]$label) @@ -165,10 +164,6 @@ Write-Host "" Write-Host "========================================" Write-Host " SUMMARY" Write-Host "========================================" -if ($script:fixed.Count -gt 0) { - Write-Host " Auto-fixed: $($script:fixed.Count)" -ForegroundColor Yellow - foreach ($f in $script:fixed) { Write-Host " - $f" -ForegroundColor Yellow } -} Write-Host " Passed: $($script:passed.Count)" -ForegroundColor Green if ($script:failed.Count -gt 0) { Write-Host " Failed: $($script:failed.Count)" -ForegroundColor Red From 9cb8f24ce992d89017636e48dbb35e2ea5d9a4ee Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sun, 13 Sep 2026 03:47:24 -0300 Subject: [PATCH 18/57] remove underscore prefix from private helpers --- config.py | 4 ++-- main/app/stocks_api/query.py | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/config.py b/config.py index dcc8730..a7f20d4 100644 --- a/config.py +++ b/config.py @@ -10,11 +10,11 @@ def applyIPv4Force(): _old_getaddrinfo = socket.getaddrinfo - def _new_getaddrinfo(*args, **kwargs): + def new_getaddrinfo(*args, **kwargs): res = _old_getaddrinfo(*args, **kwargs) return [r for r in res if r[0] == socket.AF_INET] - socket.getaddrinfo = _new_getaddrinfo + socket.getaddrinfo = new_getaddrinfo applyIPv4Force() diff --git a/main/app/stocks_api/query.py b/main/app/stocks_api/query.py index 5aa1356..7f07d72 100644 --- a/main/app/stocks_api/query.py +++ b/main/app/stocks_api/query.py @@ -55,7 +55,7 @@ class StocksQueryManager: def __init__(self, cacheManager): self.cacheManager = cacheManager - def _baseFrame(self): + def baseFrame(self): snap = getattr(self.cacheManager, "snapshot", None) pair = snap() if callable(snap) else None if isinstance(pair, tuple): @@ -66,7 +66,7 @@ def _baseFrame(self): raise HTTPException(status_code=503, detail="Cache not initialized") return df, tickerIndex - def _finalize( + def finalize( self, df: pd.DataFrame, tickerIndex, @@ -160,7 +160,7 @@ def queryHistorical( ): if not (search or fields or dates): raise HTTPException(status_code=400, detail="at least one of search/fields/dates required") - df, tickerIndex = self._baseFrame() + df, tickerIndex = self.baseFrame() try: availableColumns = df.columns.tolist() @@ -199,7 +199,7 @@ def queryHistorical( if f"{field} {year}" in availableColumnsSet ] - return self._finalize( + return self.finalize( df, tickerIndex, search, @@ -227,7 +227,7 @@ def queryFundamental( ): if not (search or fields or dates): raise HTTPException(status_code=400, detail="at least one of search/fields/dates required") - df, tickerIndex = self._baseFrame() + df, tickerIndex = self.baseFrame() try: availableColumns = df.columns.tolist() @@ -274,7 +274,7 @@ def queryFundamental( if not search or search.strip() == "": df = df.drop_duplicates(subset=["TICKER"], keep="first") - return self._finalize(df, tickerIndex, search, orderBy, limit, cols, fieldList, dates, "fundamental") + return self.finalize(df, tickerIndex, search, orderBy, limit, cols, fieldList, dates, "fundamental") except HTTPException: raise except Exception as e: @@ -287,7 +287,7 @@ def queryCotations( dates: str | None = None, adjusted: bool = False, ): - df, tickerIndex = self._baseFrame() + df, tickerIndex = self.baseFrame() try: targetCol = "COTACAO 10Y AJUSTADA" if adjusted else "COTACAO 10Y PADRAO" @@ -310,7 +310,7 @@ def queryCotations( df = df.sort_values(by="TIME", ascending=False, kind="mergesort") df = df.drop_duplicates(subset=["TICKER"], keep="first") - return self._finalize( + return self.finalize( df, tickerIndex, search, From 8e244c48aba386cd3418415429062c9b01ab8b0d Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sun, 13 Sep 2026 04:01:45 -0300 Subject: [PATCH 19/57] collapse async memory twins into sync asyncio.run wrappers --- main/app/prometheus/memory.py | 79 ++++++--------------------------- main/app/prometheus/tools.py | 7 ++- tests/conftest.py | 13 +++++- tests/test_memory_async_loop.py | 56 +++++++++++------------ 4 files changed, 55 insertions(+), 100 deletions(-) diff --git a/main/app/prometheus/memory.py b/main/app/prometheus/memory.py index f298e8d..4709852 100644 --- a/main/app/prometheus/memory.py +++ b/main/app/prometheus/memory.py @@ -40,36 +40,25 @@ def matrixUserTag(userId: Any) -> str: return f"matrix-user:{uid}" -async def getMatrixAsync( - userId: Any, loader: Callable[[], tuple[list[int], np.ndarray]] -) -> tuple[list[int], np.ndarray]: +def getMatrix(userId: Any, loader: Callable[[], tuple[list[int], np.ndarray]]) -> tuple[list[int], np.ndarray]: cacheKey = matrixKey(userId) - cached = await matrixCache.get(cacheKey, default=MATRIX_MISS) + cached = asyncio.run(matrixCache.get(cacheKey, default=MATRIX_MISS)) if cached is not MATRIX_MISS: return cast(tuple[list[int], np.ndarray], cached) freshIds, freshMatrix = loader() - await matrixCache.set(cacheKey, (freshIds, freshMatrix), tags=("matrix", matrixUserTag(userId))) - return cast(tuple[list[int], np.ndarray], await matrixCache.get(cacheKey, default=(freshIds, freshMatrix))) - - -async def invalidateUserAsync(userId: int) -> None: - await matrixCache.delete_tags(f"matrix-user:{userId}") - - -async def clearAllAsync() -> None: - await matrixCache.clear() - - -def getMatrix(userId: Any, loader: Callable[[], tuple[list[int], np.ndarray]]) -> tuple[list[int], np.ndarray]: - return asyncio.run(getMatrixAsync(userId, loader)) + asyncio.run(matrixCache.set(cacheKey, (freshIds, freshMatrix), tags=("matrix", matrixUserTag(userId)))) + return cast( + tuple[list[int], np.ndarray], + asyncio.run(matrixCache.get(cacheKey, default=(freshIds, freshMatrix))), + ) def invalidateUser(userId: int) -> None: - asyncio.run(invalidateUserAsync(userId)) + asyncio.run(matrixCache.delete_tags(f"matrix-user:{userId}")) def clearAll() -> None: - asyncio.run(clearAllAsync()) + asyncio.run(matrixCache.clear()) logger = logging.getLogger(__name__) @@ -226,31 +215,6 @@ def upsertMemory( source: str = "inferred", embedding=None, userRoles: list[str] | None = None, - ) -> dict: - return asyncio.run( - cls.upsertMemoryAsync( - db, - userId, - key, - value, - memoryType, - source, - embedding, - userRoles, - ), - ) - - @classmethod - async def upsertMemoryAsync( - cls, - db: Session, - userId: int, - key: str, - value: str, - memoryType: str = "context", - source: str = "inferred", - embedding=None, - userRoles: list[str] | None = None, ) -> dict: existing = ( db.query(PrometheusMemoryModel) @@ -274,7 +238,7 @@ async def upsertMemoryAsync( db.commit() db.refresh(existing) - await invalidateUserAsync(userId) + invalidateUser(userId) return {"status": "updated", "memory": existing} @@ -291,7 +255,7 @@ async def upsertMemoryAsync( db.commit() db.refresh(similar) - await invalidateUserAsync(userId) + invalidateUser(userId) return {"status": "merged", "memory": similar} @@ -315,7 +279,7 @@ async def upsertMemoryAsync( db.add(memory) db.commit() db.refresh(memory) - await invalidateUserAsync(userId) + invalidateUser(userId) return {"status": "created", "memory": memory} @classmethod @@ -326,17 +290,6 @@ def search( query: str, limit: int = 10, memoryType: str | None = None, - ) -> list[dict]: - return asyncio.run(cls.searchAsync(db, userId, query, limit, memoryType)) - - @classmethod - async def searchAsync( - cls, - db: Session, - userId: int, - query: str, - limit: int = 10, - memoryType: str | None = None, ) -> list[dict]: queryFilter = ( db.query(PrometheusMemoryModel) @@ -374,7 +327,7 @@ def loadMatrix() -> tuple[list[int], np.ndarray]: return ([cast(int, m.id) for m in rowsWithEmb], np.array(rawEmbs, dtype=np.float32)) try: - cachedIds, matrix = await getMatrixAsync((userId, memoryType), loadMatrix) + cachedIds, matrix = getMatrix((userId, memoryType), loadMatrix) if cachedIds and matrix.shape[0] > 0: queryEmbedding = embed([query])[0] sims = batchCosineSimilarity(queryEmbedding, matrix) @@ -477,10 +430,6 @@ def getUserMemories(cls, db: Session, userId: int, limit: int = 50, offset: int @classmethod def deleteMemory(cls, db: Session, userId: int, memoryId: int) -> bool: - return asyncio.run(cls.deleteMemoryAsync(db, userId, memoryId)) - - @classmethod - async def deleteMemoryAsync(cls, db: Session, userId: int, memoryId: int) -> bool: memory = ( db.query(PrometheusMemoryModel) .filter(PrometheusMemoryModel.id == memoryId, PrometheusMemoryModel.userId == userId) @@ -493,7 +442,7 @@ async def deleteMemoryAsync(cls, db: Session, userId: int, memoryId: int) -> boo memory.archivedAt = datetime.now() # type: ignore[assignment] db.commit() - await invalidateUserAsync(userId) + invalidateUser(userId) return True diff --git a/main/app/prometheus/tools.py b/main/app/prometheus/tools.py index 0061014..41635b6 100644 --- a/main/app/prometheus/tools.py +++ b/main/app/prometheus/tools.py @@ -1,4 +1,5 @@ from config import SessionLocal +import asyncio import logging from typing import Any from urllib.parse import quote @@ -34,7 +35,8 @@ async def search_memory(query: str, limit: int = 10, **_) -> dict: if ownSession: db = SessionLocal() try: - results = await PrometheusMemory.searchAsync( + results = await asyncio.to_thread( + PrometheusMemory.search, db, # type: ignore[arg-type] user["userId"], query, @@ -66,7 +68,8 @@ async def save_memory(key: str, value: str, type: str, **_) -> dict: db = SessionLocal() try: embedding = embed([value])[0] - result = await PrometheusMemory.upsertMemoryAsync( + result = await asyncio.to_thread( + PrometheusMemory.upsertMemory, db, # type: ignore[arg-type] user["userId"], key=key, diff --git a/tests/conftest.py b/tests/conftest.py index 1b6026e..de9d5ac 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,7 @@ import sys import os from sqlalchemy import create_engine +from sqlalchemy.pool import StaticPool from sqlalchemy.orm import sessionmaker sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) @@ -42,7 +43,11 @@ def patch_secret_key(monkeypatch): @pytest.fixture(scope="function") def dbSession(): - engine = create_engine(TEST_DATABASE_URL, connect_args={"check_same_thread": False}) + engine = create_engine( + TEST_DATABASE_URL, + connect_args={"check_same_thread": False}, + poolclass=StaticPool, + ) Base.metadata.create_all(engine) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) session = SessionLocal() @@ -62,7 +67,11 @@ def stocksDbSession(): app.dependency_overrides[getStocksSession] = lambda: stocksDbSession """ - engine = create_engine(TEST_DATABASE_URL, connect_args={"check_same_thread": False}) + engine = create_engine( + TEST_DATABASE_URL, + connect_args={"check_same_thread": False}, + poolclass=StaticPool, + ) Base.metadata.create_all(engine) TestingStocksSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) session = TestingStocksSessionLocal() diff --git a/tests/test_memory_async_loop.py b/tests/test_memory_async_loop.py index f0f656c..b3fd8ea 100644 --- a/tests/test_memory_async_loop.py +++ b/tests/test_memory_async_loop.py @@ -25,31 +25,27 @@ def makeFlatVector(): return [0.5] * 384 -class TestSearchAsyncVectorPath: - def test_searchAsync_vectorPath(self, dbSession, monkeypatch): +class TestSearchVectorPath: + def test_search_vectorPath(self, dbSession, monkeypatch): clearAll() monkeypatch.setattr(memoryMod, "embed", lambda texts: [makeQueryVector() for _ in texts]) - asyncio.run( - PrometheusMemory.upsertMemoryAsync( - dbSession, - 31, - "ticker favorito", - "minha acao favorita e WEGE3", - "preference", - embedding=makeMatchVector(), - ), + PrometheusMemory.upsertMemory( + dbSession, + 31, + "ticker favorito", + "minha acao favorita e WEGE3", + "preference", + embedding=makeMatchVector(), ) - asyncio.run( - PrometheusMemory.upsertMemoryAsync( - dbSession, - 31, - "outro", - "texto sem relacao com nada especifico", - "preference", - embedding=makeDistractorVector(), - ), + PrometheusMemory.upsertMemory( + dbSession, + 31, + "outro", + "texto sem relacao com nada especifico", + "preference", + embedding=makeDistractorVector(), ) - res = asyncio.run(PrometheusMemory.searchAsync(dbSession, 31, "WEGE3")) + res = PrometheusMemory.search(dbSession, 31, "WEGE3") assert res[0]["memoryKey"] == "ticker favorito" assert res[0]["similarity"] > 0 @@ -58,17 +54,15 @@ class TestUpsertThenSearch: def test_upsertThenSearchFindsRow(self, dbSession, monkeypatch): clearAll() monkeypatch.setattr(memoryMod, "embed", lambda texts: [makeFlatVector() for _ in texts]) - asyncio.run( - PrometheusMemory.upsertMemoryAsync( - dbSession, - 32, - "chave teste", - "valor de teste WEGE3", - "preference", - embedding=makeFlatVector(), - ), + PrometheusMemory.upsertMemory( + dbSession, + 32, + "chave teste", + "valor de teste WEGE3", + "preference", + embedding=makeFlatVector(), ) - res = asyncio.run(PrometheusMemory.searchAsync(dbSession, 32, "teste")) + res = PrometheusMemory.search(dbSession, 32, "teste") assert any(r["memoryKey"] == "chave teste" for r in res) From 356707d48e5acc3e901e779b1ce0c347ffb0db0f Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Sun, 13 Sep 2026 12:43:08 -0300 Subject: [PATCH 20/57] graphify --- graphify-out/.graphify_labels.json | 22 +- graphify-out/GRAPH_REPORT.md | 378 ++-- graphify-out/graph.json | 3139 ++++++++++++++++++---------- graphify-out/manifest.json | 284 +-- main/app/prometheus/agent.py | 1 - main/app/prometheus/mcp.py | 21 +- main/app/scraper_b3/scraper.py | 2 +- 7 files changed, 2461 insertions(+), 1386 deletions(-) diff --git a/graphify-out/.graphify_labels.json b/graphify-out/.graphify_labels.json index 5078b19..2912274 100644 --- a/graphify-out/.graphify_labels.json +++ b/graphify-out/.graphify_labels.json @@ -499,6 +499,7 @@ "497": "Community 497", "498": "Community 498", "499": "Community 499", + "500": "Community 500", "501": "Community 501", "502": "Community 502", "503": "Community 503", @@ -527,15 +528,22 @@ "526": "Community 526", "527": "Community 527", "528": "Community 528", + "529": "Community 529", + "530": "Community 530", "531": "Community 531", "532": "Community 532", "533": "Community 533", "534": "Community 534", + "535": "Community 535", "536": "Community 536", "537": "Community 537", "538": "Community 538", + "539": "Community 539", "540": "Community 540", + "541": "Community 541", "542": "Community 542", + "543": "Community 543", + "544": "Community 544", "545": "Community 545", "546": "Community 546", "547": "Community 547", @@ -551,10 +559,22 @@ "557": "Community 557", "558": "Community 558", "559": "Community 559", + "560": "Community 560", "561": "Community 561", "562": "Community 562", "563": "Community 563", + "564": "Community 564", + "565": "Community 565", "566": "Community 566", "567": "Community 567", - "568": "Community 568" + "570": "Community 570", + "571": "Community 571", + "572": "Community 572", + "573": "Community 573", + "574": "Community 574", + "575": "Community 575", + "576": "Community 576", + "577": "Community 577", + "578": "Community 578", + "579": "Community 579" } diff --git a/graphify-out/GRAPH_REPORT.md b/graphify-out/GRAPH_REPORT.md index fab88c8..d862c70 100644 --- a/graphify-out/GRAPH_REPORT.md +++ b/graphify-out/GRAPH_REPORT.md @@ -1,16 +1,16 @@ -# Graph Report - server (2026-09-12) +# Graph Report - server (2026-09-13) ## Corpus Check -- 121 files · ~71,539 words +- 121 files · ~71,444 words - Verdict: corpus is large enough that graph structure adds value. ## Summary -- 5953 nodes · 7953 edges · 558 communities (330 shown, 228 thin omitted) -- Extraction: 84% EXTRACTED · 16% INFERRED · 0% AMBIGUOUS · INFERRED: 1251 edges (avg confidence: 0.69) +- 5977 nodes · 8029 edges · 578 communities (337 shown, 241 thin omitted) +- Extraction: 84% EXTRACTED · 16% INFERRED · 0% AMBIGUOUS · INFERRED: 1258 edges (avg confidence: 0.69) - Token cost: 0 input · 0 output ## Graph Freshness -- Built from commit: `0f03079f` +- Built from commit: `8e244c48` - Run `git rev-parse HEAD` and compare to check if the graph is stale. - Run `graphify update .` after code changes (no API cost). @@ -505,6 +505,7 @@ - [[_COMMUNITY_Community 497|Community 497]] - [[_COMMUNITY_Community 498|Community 498]] - [[_COMMUNITY_Community 499|Community 499]] +- [[_COMMUNITY_Community 500|Community 500]] - [[_COMMUNITY_Community 501|Community 501]] - [[_COMMUNITY_Community 502|Community 502]] - [[_COMMUNITY_Community 503|Community 503]] @@ -528,15 +529,22 @@ - [[_COMMUNITY_Community 526|Community 526]] - [[_COMMUNITY_Community 527|Community 527]] - [[_COMMUNITY_Community 528|Community 528]] +- [[_COMMUNITY_Community 529|Community 529]] +- [[_COMMUNITY_Community 530|Community 530]] - [[_COMMUNITY_Community 531|Community 531]] - [[_COMMUNITY_Community 532|Community 532]] - [[_COMMUNITY_Community 533|Community 533]] - [[_COMMUNITY_Community 534|Community 534]] +- [[_COMMUNITY_Community 535|Community 535]] - [[_COMMUNITY_Community 536|Community 536]] - [[_COMMUNITY_Community 537|Community 537]] - [[_COMMUNITY_Community 538|Community 538]] +- [[_COMMUNITY_Community 539|Community 539]] - [[_COMMUNITY_Community 540|Community 540]] +- [[_COMMUNITY_Community 541|Community 541]] - [[_COMMUNITY_Community 542|Community 542]] +- [[_COMMUNITY_Community 543|Community 543]] +- [[_COMMUNITY_Community 544|Community 544]] - [[_COMMUNITY_Community 545|Community 545]] - [[_COMMUNITY_Community 546|Community 546]] - [[_COMMUNITY_Community 547|Community 547]] @@ -552,21 +560,33 @@ - [[_COMMUNITY_Community 557|Community 557]] - [[_COMMUNITY_Community 558|Community 558]] - [[_COMMUNITY_Community 559|Community 559]] +- [[_COMMUNITY_Community 560|Community 560]] - [[_COMMUNITY_Community 561|Community 561]] - [[_COMMUNITY_Community 562|Community 562]] - [[_COMMUNITY_Community 563|Community 563]] +- [[_COMMUNITY_Community 564|Community 564]] +- [[_COMMUNITY_Community 565|Community 565]] - [[_COMMUNITY_Community 566|Community 566]] - [[_COMMUNITY_Community 567|Community 567]] -- [[_COMMUNITY_Community 568|Community 568]] +- [[_COMMUNITY_Community 570|Community 570]] +- [[_COMMUNITY_Community 571|Community 571]] +- [[_COMMUNITY_Community 572|Community 572]] +- [[_COMMUNITY_Community 573|Community 573]] +- [[_COMMUNITY_Community 574|Community 574]] +- [[_COMMUNITY_Community 575|Community 575]] +- [[_COMMUNITY_Community 576|Community 576]] +- [[_COMMUNITY_Community 577|Community 577]] +- [[_COMMUNITY_Community 578|Community 578]] +- [[_COMMUNITY_Community 579|Community 579]] ## God Nodes (most connected - your core abstractions) 1. `vocab` - 456 edges -2. `StocksCacheManager` - 79 edges +2. `StocksCacheManager` - 80 edges 3. `HarnessState` - 68 edges 4. `UserManager` - 56 edges -5. `Permission` - 50 edges -6. `Pytest Testing` - 50 edges -7. `StocksQueryManager` - 48 edges +5. `StocksQueryManager` - 50 edges +6. `Permission` - 50 edges +7. `Pytest Testing` - 50 edges 8. `Roles` - 45 edges 9. `cn()` - 43 edges 10. `Prometheus` - 41 edges @@ -578,10 +598,10 @@ main/app/stocks_api/cache.py → tests/test_stocks_api_coverage.py - `StocksCacheManager` --calls--> `test_cache_scheduler_starts_daemon_thread()` [INFERRED] main/app/stocks_api/cache.py → tests/test_stocks_api_coverage.py -- `HarnessState` --uses--> `TestGetState` [INFERRED] - main/app/prometheus/state.py → tests/test_state_tools.py -- `HarnessState` --uses--> `TestSetState` [INFERRED] - main/app/prometheus/state.py → tests/test_state_tools.py +- `createKey()` --calls--> `test_create_key_new_user()` [INFERRED] + main/app/stocks_api/key.py → tests/test_stocks_api_coverage.py +- `createKey()` --calls--> `test_create_key_exception_rollback()` [INFERRED] + main/app/stocks_api/key.py → tests/test_stocks_api_coverage.py ## Hyperedges (group relationships) - **Authentication Module** — AuthenticationManager, SessionManager, auth_util, auth_constants, getGoogleSSO [INFERRED] @@ -591,7 +611,7 @@ - **Configuration & Database Infrastructure** — config_Config, config_engine, config_stocksEngine [INFERRED] - **User Authentication & Authorization** — user_service, authentication, user_roles, permission_system [INFERRED] -## Communities (558 total, 228 thin omitted) +## Communities (578 total, 241 thin omitted) ### Community 0 - "Stocks API Endpoints" Cohesion: 0.0 @@ -626,16 +646,16 @@ Cohesion: 0.07 Nodes (29): Algorithmic Compression (`compact.py`) Implementation Plan, code:python (# main/app/prometheus/compact.py), code:python (# Before:), code:python (# Before:), code:python (# Before:), code:bash (pytest tests/ -k "prometheus" -v), code:bash (git add main/app/prometheus/agent.py), code:bash (git mv main/app/prometheus/summarizer.py main/app/prometheus) (+21 more) ### Community 8 - "Device Detection" -Cohesion: 0.06 -Nodes (15): HarnessState, Retrieve a value from state. Returns default if key not found., Return a copy of the current state., Format state as a string for injection into the LLM context., Check if state changed since last reset., Reset the changed flag. Returns the previous state., Clear all state data., In-memory state dict that persists across loop iterations within a single reques (+7 more) +Cohesion: 0.05 +Nodes (16): HarnessState, Retrieve a value from state. Returns default if key not found., Return a copy of the current state., Format state as a string for injection into the LLM context., Check if state changed since last reset., Reset the changed flag. Returns the previous state., Clear all state data., In-memory state dict that persists across loop iterations within a single reques (+8 more) ### Community 9 - "Server Configuration" Cohesion: 0.11 Nodes (17): code:python (def filterCotationColumn(series: pd.Series, startDate, endDa), code:bash (git add -A), code:bash (git add main/app/stocks_api/query.py), code:python (def buildCotationDateIndex(df: pd.DataFrame, col: str = "COT), code:python (def filterCotationColumn(series: pd.Series, startDate, endDa), code:bash (git add main/app/stocks_api/cache.py main/app/stocks_api/que), code:python (PARQUET_PATH = Path(__file__).parent / "stocks_cache.parquet), code:bash (git add main/app/stocks_api/cache.py) (+9 more) ### Community 10 - "Prometheus Memory" -Cohesion: 0.08 -Nodes (27): Tests for queryCotations and /stocks/cotations., 2 tickers x 2 rows. Rows 0,2 are 2024-01-15; rows 1,3 are 2024-06-15. M, Tests for queryCotations and /stocks/cotations., 4 rows for 2 tickers -> 2 results, one per ticker, both with latest TIME., 4 rows for 2 tickers -> 2 results, one per ticker, both with latest TIME., 2 tickers x 2 rows. Rows 0,2 are 2024-01-15; rows 1,3 are 2024-06-15. M, dates="2016-12-02" should keep only the 02-12-2016 entry in each JSON list., dates="2016-12-02" should keep only the 02-12-2016 entry in each JSON list. (+19 more) +Cohesion: 0.06 +Nodes (35): Tests for queryCotations and /stocks/cotations., 2 tickers x 2 rows. Rows 0,2 are 2024-01-15; rows 1,3 are 2024-06-15. M, Tests for queryCotations and /stocks/cotations., 4 rows for 2 tickers -> 2 results, one per ticker, both with latest TIME., 4 rows for 2 tickers -> 2 results, one per ticker, both with latest TIME., 2 tickers x 2 rows. Rows 0,2 are 2024-01-15; rows 1,3 are 2024-06-15. M, dates="2016-12-02" should keep only the 02-12-2016 entry in each JSON list., dates="2016-12-02" should keep only the 02-12-2016 entry in each JSON list. (+27 more) ### Community 11 - "Auth Utilities & SSO" Cohesion: 0.05 @@ -646,24 +666,24 @@ Cohesion: 0.08 Nodes (13): LoopEvent, LoopEvent model for observable agent loops., LoopLogger, LoopLogger — batched event logging for observable agent loops., Queue events during a loop, flush to DB at end., Log a generic event with optional metadata., Log a tool invocation., Log end of a turn with timing. (+5 more) ### Community 13 - "Prometheus Tools" -Cohesion: 0.15 -Nodes (13): benchOnce(), main(), batchCosineSimilarity(), decodeEmbeddings(), normalizeRows(), Empty matrix → empty array., Single row matches cosine_similarity., Multiple rows ranked correctly. (+5 more) +Cohesion: 0.13 +Nodes (21): benchOnce(), main(), _fulltext_search(), fullTextSearch(), minMax(), scoreCandidates(), scoreRecency(), search() (+13 more) ### Community 14 - "User Roles & Permissions" -Cohesion: 0.05 -Nodes (36): _make_stocksapi_client(), Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental. (+28 more) +Cohesion: 0.06 +Nodes (30): _make_stocksapi_client(), Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont, Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont, Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont (+22 more) ### Community 15 - "Community 15" Cohesion: 0.05 Nodes (38): code:block1 (User 123: "Analyze PETR4 vs VALE3 correlation"), code:python (from main.app.prometheus.sandbox import SandboxManager), code:python (TOOL_REGISTRY: dict[str, Any] = {), code:bash (git add main/app/prometheus/tools.py tests/test_sandbox_tool), code:python (import pytest), code:python (from main.app.prometheus.sandbox import SandboxManager), code:python (async def streamMessage(self, query=None, sessionId=None, db), code:python (## Code Sandbox (On-Demand)) (+30 more) ### Community 16 - "Community 16" -Cohesion: 0.05 -Nodes (34): _make_prometheus_client(), Generic Exception in chat propagates to FastAPI's default 500 handler., Generic Exception in chat propagates to FastAPI's default 500 handler., Generic Exception in chat propagates to FastAPI's default 500 handler., Generic Exception in chat propagates via SSE error event., Covers line 125, 126-128: generic Exception in chat., Return (client, app) with prometheus router and mocked deps., Covers lines 33-36: GET /prometheus/sessions. (+26 more) +Cohesion: 0.09 +Nodes (20): Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 109-136: POST /prometheus/chat/stream (SSE)., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 120-121: existing session with verified ownership., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat. (+12 more) ### Community 17 - "Community 17" Cohesion: 0.08 -Nodes (23): search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., DataFrame without TIME column., DataFrame without TIME column., DataFrame without TIME column., search.strip() == '' should still dedup (line 181)., Multiple search terms with tickerIndex. (+15 more) +Nodes (23): search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., DataFrame without TIME column., Invalid date -> inner 400 caught by outer except -> 500., DataFrame without TIME column., DataFrame without TIME column., search.strip() == '' should still dedup (line 181). (+15 more) ### Community 18 - "Community 18" Cohesion: 0.07 @@ -694,24 +714,24 @@ Cohesion: 0.09 Nodes (5): Tests for agent <-> persistent sandbox integration (Task 3)., Verify the agent uses getOrCreate + syncToSandbox/syncFromSandbox., Test the premium gating logic used in streamMessage., TestPersistentSandboxLifecycle, TestPremiumCheck ### Community 25 - "Community 25" -Cohesion: 0.06 -Nodes (13): Tests for input validation via HTTP endpoints. Validation is now inline via Bod, PUT /prometheus/sessions/{sessionId} — validates title via Body(...), POST /prometheus/chat/stream — validates query via Body(...), POST /auth/register — validates username, email, password via Body(...), Test that endpoints reject requests with missing required fields., POST /auth/login — validates username, password via Body(...), POST /prometheus/sessions — validates title via Body(...), TestChatValidation (+5 more) +Cohesion: 0.09 +Nodes (9): Tests for input validation via HTTP endpoints. Validation is now inline via Bod, PUT /prometheus/sessions/{sessionId} — validates title via Body(...), POST /auth/register — validates username, email, password via Body(...), Test that endpoints reject requests with missing required fields., POST /auth/login — validates username, password via Body(...), TestLoginValidation, TestMissingBody, TestRegisterValidation (+1 more) ### Community 26 - "Community 26" -Cohesion: 0.13 -Nodes (16): generateKey(), createKey(), _hash_key(), hashKey(), Return SHA-256 hex digest of the given key., Test edge case: request exactly at quota limit., Test edge case: request exactly at quota limit., Test that increment works from zero usage. (+8 more) +Cohesion: 0.11 +Nodes (20): createKey(), _hash_key(), hashKey(), Return SHA-256 hex digest of the given key., Test that concurrent requests are properly serialized at DB level. Th, Test edge case: request exactly at quota limit., Test edge case: request exactly at quota limit., Test that invalid API key returns zero rows affected. (+12 more) ### Community 27 - "Community 27" -Cohesion: 0.15 -Nodes (15): getUserMemories(), getRelevanceScore(), _FakeMemory, A memory with no lastAccessedAt should use baseScore as-is., Scores are deterministic — no cron mutation needed., Same memory at different points in time yields different scores., A memory accessed 10x (baseScore 1.0) should still outrank a memory acce, A rarely-used old memory should lose to a popular fresh one. (+7 more) +Cohesion: 0.16 +Nodes (14): getRelevanceScore(), _FakeMemory, A memory with no lastAccessedAt should use baseScore as-is., Scores are deterministic — no cron mutation needed., Same memory at different points in time yields different scores., A memory accessed 10x (baseScore 1.0) should still outrank a memory acce, A rarely-used old memory should lose to a popular fresh one., With same access time, higher baseScore always wins. (+6 more) ### Community 28 - "Community 28" Cohesion: 0.07 Nodes (27): Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., If an unexpected exception occurs in queryHistorical., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them). (+19 more) ### Community 29 - "Community 29" -Cohesion: 0.08 -Nodes (17): PrometheusGenerator, Thread-safe proxy that delegates to per-thread sessions., SessionProxy, _make_generator(), Tests to increase coverage for: - main/app/prometheus/generation.py - main/a, test_execute_workflow_basic_no_history(), test_execute_workflow_global_request_api_error(), test_execute_workflow_global_request_status_not_200() (+9 more) +Cohesion: 0.09 +Nodes (15): PrometheusGenerator, _make_generator(), Tests to increase coverage for: - main/app/prometheus/generation.py - main/a, test_execute_workflow_basic_no_history(), test_execute_workflow_global_request_api_error(), test_execute_workflow_global_request_status_not_200(), test_execute_workflow_global_request_with_api_key(), test_execute_workflow_session_db_exception() (+7 more) ### Community 30 - "Community 30" Cohesion: 0.07 @@ -726,8 +746,8 @@ Cohesion: 0.11 Nodes (12): ToolContext — bundles all dependencies for tool execution. Replace passing user, Single dependency bundle for tool execution. Created once per request in ag, Extract userId from user dict if not explicitly set., ToolContext, Unit tests for ToolContext dataclass., Dataclass equality works out of the box., Explicit userId takes precedence over user dict., Two contexts share no mutable defaults. (+4 more) ### Community 33 - "Community 33" -Cohesion: 0.09 -Nodes (23): BaseHTTPMiddleware, BaseModel, app(), Tests for standardized error responses (errors.py)., SampleBody, TestErrorResponseModel, TestGenericExceptionHandler, TestHTTPExceptionHandler (+15 more) +Cohesion: 0.12 +Nodes (14): BaseHTTPMiddleware, BaseModel, Tests for standardized error responses (errors.py)., SampleBody, TestErrorResponseModel, TestGenericExceptionHandler, TestHTTPExceptionHandler, TestRequestContextFilter (+6 more) ### Community 34 - "Community 34" Cohesion: 0.11 @@ -742,7 +762,7 @@ Cohesion: 0.07 Nodes (28): 10. Insecure SessionMiddleware Configuration, 11. HTTPException in Business Logic, 12. Controllers Contain Business Logic, 13. `service/` Layer Misleading, 14. Session Not Revoked on Logout with Invalid Token, 15. Unbounded ThreadPoolExecutor Per Request, 16. Full DataFrame Copy Per API Request, 17. Unbounded Chat History Growth (+20 more) ### Community 37 - "Community 37" -Cohesion: 0.13 +Cohesion: 0.12 Nodes (8): StocksAPIKey, getRemainingQuota(), incrementUsage(), isQuotaExceeded(), keyToDict(), needsReset(), resetQuota(), TestStocksAPIKeyModel ### Community 38 - "Community 38" @@ -751,7 +771,7 @@ Nodes (27): code:json ([), code:javascript (const loadHistory = async (sid) => { ### Community 39 - "Community 39" Cohesion: 0.07 -Nodes (25): Two dates in the range, both valid., Two dates in the range, both valid., Two dates in the range, both valid., Two dates in the range, both valid., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., search.strip() == '' should still dedup (line 181)., Search with no index match falls back to string startswith. (+17 more) +Nodes (26): Two dates in the range, both valid., Two dates in the range, both valid., Two dates in the range, both valid., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., search.strip() == '' should still dedup (line 181)., Search with no index match falls back to string startswith., Two dates in the range, both valid. (+18 more) ### Community 40 - "Community 40" Cohesion: 0.12 @@ -766,8 +786,8 @@ Cohesion: 0.09 Nodes (16): StocksCacheManager, Tests for dynamic ticker index feature, Ticker index should be built when cache is loaded, Ticker index should contain all tickers from cache, Ticker index should be case-insensitive, Looking up ticker should return valid row index, Ticker index should be rebuilt when cache refreshes, TestTickerIndex (+8 more) ### Community 43 - "Community 43" -Cohesion: 0.14 -Nodes (6): authenticateUser(), createUserAccount(), hashPassword(), verifyPassword(), TestAuthUtil, TestAuthUtilEdgeCases +Cohesion: 0.18 +Nodes (4): hashPassword(), verifyPassword(), TestAuthUtil, TestAuthUtilEdgeCases ### Community 44 - "Community 44" Cohesion: 0.14 @@ -779,7 +799,7 @@ Nodes (5): Tests for main/utils/roles.py — covers requirePermission and edge c ### Community 46 - "Community 46" Cohesion: 0.09 -Nodes (21): Regression: queryFundamental must not mutate the shared cache TIME column., Regression: queryFundamental must not mutate the shared cache TIME column., Regression: queryFundamental must not mutate the shared cache TIME column., Single invalid date -> inner 400 passes through., Single invalid date -> inner 400 caught by outer except -> 500., Single invalid date -> inner 400 caught by outer except -> 500., Single invalid date -> inner 400 caught by outer except -> 500., Invalid fields now raise 400 with actionable error message. (+13 more) +Nodes (20): Regression: queryFundamental must not mutate the shared cache TIME column., Regression: queryFundamental must not mutate the shared cache TIME column., Regression: queryFundamental must not mutate the shared cache TIME column., Single invalid date -> inner 400 passes through., Single invalid date -> inner 400 caught by outer except -> 500., Single invalid date -> inner 400 caught by outer except -> 500., Single invalid date -> inner 400 caught by outer except -> 500., Invalid fields now raise 400 with actionable error message. (+12 more) ### Community 47 - "Community 47" Cohesion: 0.1 @@ -790,8 +810,8 @@ Cohesion: 0.06 Nodes (34): Backend (COMMIT), code:bash (cd frontend && pnpm add @openuidev/react-lang), code:bash (rm frontend/src/components/MdocMessage.jsx), code:python ("""OpenUI Lang system prompt section for Prometheus agent.), code:block12, code:block13, code:block14, code:block15 (+26 more) ### Community 49 - "Community 49" -Cohesion: 0.1 -Nodes (20): dispatchToolCall(), TDD tests: verify memory tools are wired into the Prometheus agent. RED: Thes, TOOL_REGISTRY pattern must work correctly., test_memory_tool_skipped_without_user(), test_non_memory_tool_not_routed_to_executeMemoryTool(), test_non_registry_tool_not_routed(), test_save_memory_routed_to_executeMemoryTool(), test_save_memory_routed_via_registry() (+12 more) +Cohesion: 0.07 +Nodes (21): dispatchToolCall(), TDD tests: verify memory tools are wired into the Prometheus agent. RED: Thes, TOOL_REGISTRY pattern must work correctly., test_memory_tool_skipped_without_user(), test_non_memory_tool_not_routed_to_executeMemoryTool(), test_non_registry_tool_not_routed(), test_save_memory_routed_to_executeMemoryTool(), test_save_memory_routed_via_registry() (+13 more) ### Community 50 - "Community 50" Cohesion: 0.07 @@ -806,12 +826,12 @@ Cohesion: 0.08 Nodes (7): Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., TestPrometheusChatManager ### Community 53 - "Community 53" -Cohesion: 0.12 -Nodes (23): archiveDead(), count_memories(), countMemories(), decayScores(), deleteMemory(), extract(), findSimilarKey(), _fulltext_search() (+15 more) +Cohesion: 0.11 +Nodes (30): applyUpdate(), archiveDead(), clearAll(), clearAllAsync(), count_memories(), countMemories(), countTokensCached(), decayScores() (+22 more) ### Community 54 - "Community 54" Cohesion: 0.06 -Nodes (30): memoryMaintenance(), create_memories(), Zero access but score still above threshold → not archived., Even with low score, if accessed → not archived., Even with low score, if accessed → not archived., Already archived memories are skipped., Already archived memories are skipped., Decay happens first, then archive check with new scores. (+22 more) +Nodes (26): create_memories(), Zero access but score still above threshold → not archived., Even with low score, if accessed → not archived., Even with low score, if accessed → not archived., Already archived memories are skipped., Already archived memories are skipped., Decay happens first, then archive check with new scores., Decay happens first, then archive check with new scores. (+18 more) ### Community 55 - "Community 55" Cohesion: 0.11 @@ -837,17 +857,13 @@ Nodes (20): Tests for main/utils/connectivity.py — covers all branches., test_ Cohesion: 0.09 Nodes (7): Cover all methods in session.py (lines 14-154)., Cover all methods in session.py (lines 14-154)., Cover all methods in session.py (lines 14-154)., Cover all methods in session.py (lines 14-154)., Cover all methods in session.py (lines 14-154)., Cover all methods in session.py (lines 14-154)., TestSessionManager -### Community 61 - "Community 61" -Cohesion: 0.13 -Nodes (4): PrometheusSession, User, TestPrometheusSessionModel, TestUserModel - ### Community 62 - "Community 62" Cohesion: 0.1 Nodes (20): architectures, attention_probs_dropout_prob, gradient_checkpointing, hidden_act, hidden_dropout_prob, hidden_size, initializer_range, intermediate_size (+12 more) ### Community 63 - "Community 63" -Cohesion: 0.13 -Nodes (10): _filterCotationByDate(), filterCotationData(), _parseCotationDate(), Shared query pipeline for historical and fundamental endpoints., Fetch live prices for B3 tickers via yfinance. B3 tickers must match, Parse DD-MM-YYYY from COTACAO 10Y JSON DATA field. ponytail: stdlib datetime onl, Filter COTACAO 10Y JSON entries by their inner DATA field (DD-MM-YYYY)., sanitizeNanValues() (+2 more) +Cohesion: 0.19 +Nodes (9): _filterCotationByDate(), filterCotationData(), _parseCotationDate(), Shared query pipeline for historical and fundamental endpoints., Fetch live prices for B3 tickers via yfinance. B3 tickers must match, Parse DD-MM-YYYY from COTACAO 10Y JSON DATA field. ponytail: stdlib datetime onl, Filter COTACAO 10Y JSON entries by their inner DATA field (DD-MM-YYYY)., sanitizeNanValues() (+1 more) ### Community 64 - "Community 64" Cohesion: 0.06 @@ -878,12 +894,12 @@ Cohesion: 0.11 Nodes (19): API Key System, B3 Scraper, Fundamental Data, Gemini Model, Historical Data, Ma'at Stock Algorithm, Mansa Server, MySQL Database (+11 more) ### Community 72 - "Community 72" -Cohesion: 0.05 -Nodes (29): B3Scraper, getCurrentSelic(), getInitialData(), calculateInvestingScore(), AuthenticationService, initialize(), initialize(), P5: register memory maintenance on the shared scheduler. Kept in this ser (+21 more) +Cohesion: 0.14 +Nodes (3): getCurrentSelic(), getInitialData(), calculateInvestingScore() ### Community 73 - "Community 73" -Cohesion: 0.19 -Nodes (3): parseDateRange(), TestParseDateRange, TestParseDateRange +Cohesion: 0.16 +Nodes (7): _parse_date(), parseDate(), parseDateEnd(), parseDateRange(), parseDateStart(), TestParseDateRange, TestParseDateRange ### Community 74 - "Community 74" Cohesion: 0.11 @@ -910,12 +926,12 @@ Cohesion: 0.05 Nodes (44): cn(), AlertDialogAction(), AlertDialogCancel(), AlertDialogContent(), AlertDialogDescription(), AlertDialogFooter(), AlertDialogHeader(), AlertDialogMedia() (+36 more) ### Community 80 - "Community 80" -Cohesion: 0.14 -Nodes (18): buildSummary(), charCount(), countTokens(), extractDecisions(), extractMetrics(), extractSnapshots(), extractTickers(), extractToolCalls() (+10 more) +Cohesion: 0.15 +Nodes (18): buildSummary(), charCount(), countTokens(), dedup(), extractDecisions(), extractMetrics(), extractSnapshots(), extractTickers() (+10 more) ### Community 81 - "Community 81" -Cohesion: 0.18 -Nodes (11): getLiveCotation(), Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th (+3 more) +Cohesion: 0.17 +Nodes (12): getLiveCotation(), Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th (+4 more) ### Community 82 - "Community 82" Cohesion: 0.16 @@ -926,8 +942,8 @@ Cohesion: 0.12 Nodes (16): Brazilian Stocks Market Scraper, code:env (#), code:json ({), Configuration Parameters, Constraint Engine ($\Lambda$), Engines, Fundamental Engine ($\Phi$), Global Score Function (+8 more) ### Community 84 - "Community 84" -Cohesion: 0.1 -Nodes (19): chat(), chat_stream(), create_memory(), createMemory(), createSession(), downloadWorkspaceFile(), _forward(), getHistory() (+11 more) +Cohesion: 0.14 +Nodes (12): chat(), chat_stream(), createSession(), downloadWorkspaceFile(), _forward(), getHistory(), Verify the user owns the session, raise 403 otherwise., Verify the user owns the session, raise 403 otherwise. (+4 more) ### Community 85 - "Community 85" Cohesion: 0.21 @@ -935,7 +951,7 @@ Nodes (16): AddDividendDialog(), fmtBRL(), AddLotDialog(), HoldingSearchBox(), m ### Community 86 - "Community 86" Cohesion: 0.17 -Nodes (7): Verify memory endpoints exist and are wired correctly., GET /prometheus/memories exists., POST /prometheus/memories exists., DELETE /prometheus/memories/{id} exists., GET /memories requires authentication., GET /memories requires USE_PROMETHEUS (basic USER role denied)., TestMemoryControllerRoutes +Nodes (4): POST /memories rejects missing key., POST /memories rejects missing value., Full integration tests using mocked MemoryManager., TestMemoryEndpointsIntegration ### Community 87 - "Community 87" Cohesion: 0.1 @@ -970,8 +986,8 @@ Cohesion: 0.12 Nodes (16): 10. Splits — served prices are RAW by default (verified verdict, encode as-is), 11. Dividends — no dedicated endpoint (verified verdict, encode as-is), 12. Corporate actions — splits and grupamentos via one read-time mechanism, 13. Dividend methodology — ex-date smoothing check (both branches, test decides), 1. Context, 2. Decision: Design A — pure event log, derive at read time, 3. Data model (user_db, alembic), 4. Derivations (all at read time, date order) (+8 more) ### Community 95 - "Community 95" -Cohesion: 0.11 -Nodes (8): cache(), Tests for ResultCache., Tests for StocksCacheManager queryCache LRU eviction., Create a StocksCacheManager with a mock DB engine., When columns is None, cache key should be None., TestCacheLRUEviction, TestCacheTTLLogic, TestColumnValidator +Cohesion: 0.17 +Nodes (5): Tests for StocksCacheManager queryCache LRU eviction., Create a StocksCacheManager with a mock DB engine., When columns is None, cache key should be None., TestCacheLRUEviction, TestCacheTTLLogic ### Community 96 - "Community 96" Cohesion: 0.2 @@ -986,36 +1002,36 @@ Cohesion: 0.28 Nodes (6): extractTokenPayload(), Tests for extractTokenPayload — the standalone token extraction dependency., Create a mock Starlette Request with given headers., Authorization: Bearer (empty) — no token after Bearer., Authorization: Basic xxx — not Bearer, so no token found., TestExtractTokenPayload ### Community 99 - "Community 99" -Cohesion: 0.17 -Nodes (4): POST /memories rejects missing key., POST /memories rejects missing value., Full integration tests using mocked MemoryManager., TestMemoryEndpointsIntegration +Cohesion: 0.05 +Nodes (33): _make_prometheus_client(), Covers lines 111-112: sessionId is None, new session created., Covers lines 111-112: sessionId is None, new session created., Covers lines 118-119: sessionId is None, new session created., Covers lines 111-112: sessionId is None, new session created., Return (client, app) with prometheus router and mocked deps., Covers lines 33-36: GET /prometheus/sessions., Covers lines 33-36: GET /prometheus/sessions. (+25 more) ### Community 100 - "Community 100" Cohesion: 0.09 -Nodes (13): _assert_gemini_safe(), Every function in TOOL_REGISTRY must have Gemini-safe signatures. Custom cl, Every function in TOOL_REGISTRY must have Gemini-safe signatures. Custom cl, Regression: HarnessState must never leak into tool signatures., Regression: HarnessState must never leak into tool signatures., Assert a tool function has only Gemini-compatible parameter types., Assert a tool function has only Gemini-compatible parameter types., test_get_state_no_state_returns_error() (+5 more) +Nodes (12): _assert_gemini_safe(), Every function in TOOL_REGISTRY must have Gemini-safe signatures. Custom cl, Every function in TOOL_REGISTRY must have Gemini-safe signatures. Custom cl, Regression: HarnessState must never leak into tool signatures., Regression: HarnessState must never leak into tool signatures., Assert a tool function has only Gemini-compatible parameter types., Assert a tool function has only Gemini-compatible parameter types., test_get_state_no_state_returns_error() (+4 more) ### Community 101 - "Community 101" -Cohesion: 0.09 -Nodes (19): Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 111-112: sessionId is None, new session created., Covers lines 111-112: sessionId is None, new session created., Covers lines 109-136: POST /prometheus/chat/stream (SSE)., Covers lines 118-119: sessionId is None, new session created., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership. (+11 more) +Cohesion: 0.15 +Nodes (15): execute_code(), Store a value in the harness state for this session. Use this to save inter, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Read a file from the workspace. Args: path: Path to the file (e., Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis, (+7 more) ### Community 102 - "Community 102" -Cohesion: 0.13 -Nodes (10): BaseSettings, BaseMansaSettings, DiscordSettings, MysqlSettings, PrometheusSettings, ScraperSettings, StocksApiSettings, UserSettings (+2 more) +Cohesion: 0.14 +Nodes (8): BaseSettings, BaseMansaSettings, DiscordSettings, MysqlSettings, ScraperSettings, StocksApiSettings, UserSettings, TestConfig ### Community 103 - "Community 103" Cohesion: 0.13 Nodes (14): 10. Performance, 11. Testing, 12. Risks, 13. Out of Scope (YAGNI), 14. Open Questions, 1. Executive Summary, 2. Context & Motivation, 5. Architecture Decision (+6 more) ### Community 104 - "Community 104" -Cohesion: 0.06 -Nodes (33): Covers lines 100-104, 106: GET /user/sessions/current., Covers lines 100-104, 106: GET /user/sessions/current., Covers lines 100-104, 106: session found., Covers lines 100-104, 106: session found., Covers lines 100-104, 106: GET /user/sessions/current., Covers lines 100-104, 106: session found., Covers line 104: session not found., Covers line 104: session not found. (+25 more) +Cohesion: 0.1 +Nodes (17): Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126, 131, 135-136., Covers lines 126, 131, 135-136., Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126, 131, 135-136., Covers lines 127-129: session not found., Covers lines 127-129: session not found. (+9 more) ### Community 106 - "Community 106" Cohesion: 0.22 Nodes (3): parseYearInput(), TestParseYearInput, TestParseYearInput ### Community 107 - "Community 107" -Cohesion: 0.2 -Nodes (9): Invalid date -> inner 400 passes through (not wrapped as 500)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500. (+1 more) +Cohesion: 0.13 +Nodes (13): Covers lines 100-104, 106: GET /user/sessions/current., Covers lines 100-104, 106: GET /user/sessions/current., Covers lines 100-104, 106: session found., Covers lines 100-104, 106: session found., Covers lines 100-104, 106: GET /user/sessions/current., Covers lines 100-104, 106: session found., Covers line 104: session not found., Covers line 104: session not found. (+5 more) ### Community 108 - "Community 108" Cohesion: 0.14 @@ -1034,16 +1050,16 @@ Cohesion: 0.14 Nodes (13): code:python (import pytest), code:python (import logging), code:bash (git add main/app/prometheus/state.py tests/test_harness_stat), File Map, Global Constraints, Phase 1: HarnessState (In-Memory Agent Scratchpad), Prometheus Harness — Master Implementation Plan (v2: CubeSandbox + On-Demand), Relationship to Existing Systems (+5 more) ### Community 112 - "Community 112" -Cohesion: 0.16 -Nodes (11): applyUpdate(), contentHash(), Same input → same hash., Different inputs → different hashes., Returns 32-char hex string., TestContentHash, ALL(), content_hash() (+3 more) +Cohesion: 0.13 +Nodes (12): GET /stocks/realtime-cotation without search returns 422., GET /cotations without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422., GET /stocks/realtime-cotation without search returns 422. (+4 more) ### Community 113 - "Community 113" Cohesion: 0.15 Nodes (7): write_file returns False when host write fails (e.g. invalid path chars)., read_file reads from host filesystem., write_file writes to host filesystem., list_files lists host filesystem entries., list_files returns empty for missing directory., read_file raises FileNotFoundError for missing file., TestSandboxManager ### Community 114 - "Community 114" -Cohesion: 0.17 -Nodes (12): Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok, Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok, Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok, Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok, Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok (+4 more) +Cohesion: 0.29 +Nodes (6): Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok, Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: HTTPException raised by verifyAccessToken is re-raised. ### Community 115 - "Community 115" Cohesion: 0.17 @@ -1066,8 +1082,8 @@ Cohesion: 0.07 Nodes (26): code:python ("""Tests for SandboxManager file mutation helpers (delete_fi), code:python (from main.app.prometheus.sandbox import SandboxManager, host), code:python (@router.post("/workspace/upload")), code:bash (git add main/controller/prometheus_controller.py tests/test_), code:python (from unittest.mock import patch, MagicMock), code:python (from main.app.prometheus.sandbox import SandboxManager, host), code:python (async def serve_file(path: str, **_) -> dict:), code:python ("serve_file": serve_file,) (+18 more) ### Community 120 - "Community 120" -Cohesion: 0.1 -Nodes (32): _make_auth_client(), Tests to cover uncovered lines across controllers, UserManager, and auth util., Covers lines 44-54, 63, 66-71: register success, ValueError, generic Exception., Covers lines 44-54, 63, 66-71: register success, ValueError, generic Exception., Covers lines 87-93, 102: login success and failure paths., Covers lines 87-93, 102: login success and failure paths., Return (client, app) with auth + user routers and mocked getSession., Covers lines 155-156, 158, 160-168, 170-177, 179-184, 186, 190-204: googleCallba (+24 more) +Cohesion: 0.12 +Nodes (27): _make_auth_client(), Tests to cover uncovered lines across controllers, UserManager, and auth util., Return (client, app) with auth + user routers and mocked getSession., test_callback_existing_user(), test_callback_generic_exception(), test_callback_new_user(), test_callback_no_user_info(), test_callback_with_state_redirect() (+19 more) ### Community 121 - "Community 121" Cohesion: 0.21 @@ -1085,6 +1101,10 @@ Nodes (12): Appendix A: Codebase Findings, code:block6 (D:\Repositories\server\) Cohesion: 0.07 Nodes (27): code:python (# tests/test_stocks_payload_cache.py), code:python (pc = self.cacheManager.tickerPayloads), code:python (# tests/test_stocks_sync_handlers.py), code:bash (git add main/controller/stocksapi_controller.py main/app/sto), code:python (def test_payload_cache_cotation_index():), code:python (self._cotations: dict[str, bytes] = {}), code:python (cotationCols = ["TICKER", "NOME", "TIME", "COTACAO 10Y PADRA), code:python (self._cotations = cot) (+19 more) +### Community 125 - "Community 125" +Cohesion: 0.13 +Nodes (3): PrometheusSession, createSession(), TestPrometheusSessionModel + ### Community 126 - "Community 126" Cohesion: 0.15 Nodes (11): _count_memories(), _create_memory(), _get_memory(), Keys with Jaccard > 0.8 should merge., Keys with Jaccard > 0.8 should merge., Keys with low similarity should not merge., Keys with low similarity should not merge., Keys with low similarity should not merge. (+3 more) @@ -1102,12 +1122,16 @@ Cohesion: 0.2 Nodes (10): Tests for stocks API field validation — verifies the fields parameter accepts a, Integration: /stocks/fundamental must accept slash and dot fields., Minimal TestClient with just the stocks router for validation tests., GET /fundamental?fields=P/L must not return 422 (validation error)., GET /fundamental?fields=P/L must not return 422 (validation error)., Integration: /stocks/fundamental must accept slash and dot fields., GET /fundamental?fields=P/L must not return 422 (validation error)., GET /historical?fields=P/L must not return 422. (+2 more) ### Community 130 - "Community 130" -Cohesion: 0.22 -Nodes (8): Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false. +Cohesion: 0.17 +Nodes (7): Verify memory endpoints exist and are wired correctly., GET /prometheus/memories exists., POST /prometheus/memories exists., DELETE /prometheus/memories/{id} exists., GET /memories requires authentication., GET /memories requires USE_PROMETHEUS (basic USER role denied)., TestMemoryControllerRoutes ### Community 131 - "Community 131" -Cohesion: 0.21 -Nodes (8): pack → unpack preserves values., Empty list roundtrips., 384-dim vector packs to 1536 bytes., TestPackUnpack, pack_vector(), Unpack MySQL BLOB to float list., Vectorized cosine similarity: one query against N embeddings., unpack_vector() +Cohesion: 0.11 +Nodes (17): Same input → same hash., Different inputs → different hashes., Returns 32-char hex string., pack → unpack preserves values., Empty list roundtrips., 384-dim vector packs to 1536 bytes., TestContentHash, TestPackUnpack (+9 more) + +### Community 132 - "Community 132" +Cohesion: 0.5 +Nodes (4): code:python ("""add wallet_holdings and wallet_lots tables), code:python (import main.models.wallet), code:bash (git add migrations/versions/wallet_tables_20260904_add_walle), Task 2: Alembic migration for wallet tables ### Community 133 - "Community 133" Cohesion: 0.18 @@ -1117,10 +1141,18 @@ Nodes (11): code:python (import inspect), code:python (from main.app.prometheus. Cohesion: 0.18 Nodes (11): code:yaml (volumes:), code:bash (git add config.py docker-compose.yml), code:python (import pytest), code:python (import logging), code:bash (git add main/app/prometheus/sandbox.py tests/test_sandbox.py), code:python (class PrometheusSettings(BaseMansaSettings):), code:yaml (environment:), code:yaml (sandbox:) (+3 more) +### Community 135 - "Community 135" +Cohesion: 0.11 +Nodes (4): cache(), Tests for ResultCache., TestColumnValidator, TestResultCache + ### Community 136 - "Community 136" Cohesion: 0.2 Nodes (9): Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132). (+1 more) +### Community 137 - "Community 137" +Cohesion: 0.2 +Nodes (9): Invalid date -> inner 400 passes through (not wrapped as 500)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Two dates in the range, both valid. (+1 more) + ### Community 138 - "Community 138" Cohesion: 0.18 Nodes (6): test_stream_message_yields_text_chunks(), FakeChunk, GREEN test: streamMessage works without chatSession — MCP setup is inlined. Aft, streamMessage inlines MCP setup — chatSession no longer exists., streamMessage inlines MCP setup — chatSession no longer exists., TestStreamMessageNoChatSession @@ -1130,8 +1162,8 @@ Cohesion: 0.24 Nodes (6): Dataset, produce_data(), Train script for a single file Need to set the TPU address first: export XRT_TP, A class that handles the reddit data files, A class that handles one dataset, RedditDataset ### Community 140 - "Community 140" -Cohesion: 0.06 -Nodes (39): Base, PrometheusMemory, PrometheusMemory, MemoryManager, PrometheusMemory, All memory operations. Stateless class methods., PrometheusService, TestDifferentKeysNoMerge (+31 more) +Cohesion: 0.11 +Nodes (28): Base, PrometheusMemory, PrometheusMemory, MemoryManager, PrometheusMemory, All memory operations. Stateless class methods., PrometheusService, TestDifferentKeysNoMerge (+20 more) ### Community 141 - "Community 141" Cohesion: 0.24 @@ -1170,8 +1202,8 @@ Cohesion: 0.2 Nodes (3): MEMORY_TOOLS must be defined as a Tool wrapping FunctionDeclarations., MEMORY_TOOLS must be a list of callables with proper signatures., TestMemoryToolsDefinition ### Community 152 - "Community 152" -Cohesion: 0.11 -Nodes (19): _getDb(), Search user's saved memories, preferences, and past analysis context. Use t, Search user's saved memories, preferences, and past analysis context. Use t, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use (+11 more) +Cohesion: 0.09 +Nodes (23): _getDb(), Search user's saved memories, preferences, and past analysis context. Use t, Search user's saved memories, preferences, and past analysis context. Use t, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use (+15 more) ### Community 153 - "Community 153" Cohesion: 0.12 @@ -1190,8 +1222,8 @@ Cohesion: 0.22 Nodes (8): API Endpoints, code:env (#), code:bash (python __init__.py), code:mermaid (graph TD), License, Prometheus, Usage, Workflow ### Community 157 - "Community 157" -Cohesion: 0.18 -Nodes (11): getFundamental(), Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret (+3 more) +Cohesion: 0.17 +Nodes (12): getFundamental(), Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret, Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret (+4 more) ### Community 158 - "Community 158" Cohesion: 0.22 @@ -1207,7 +1239,7 @@ Nodes (17): §2 Service/Business Separation — MVC 4/10 (Historical layering sc ### Community 161 - "Community 161" Cohesion: 0.11 -Nodes (18): Category 2: Async/Sync Inconsistencies (MEDIUM), Category 4: Caching & Memory (MEDIUM), Category 6: Configuration & Environment (LOW), Category 7: Code Quality (LOW), Executive Summary, Full Code Review Report, Issue 2.1 — All route handlers are synchronous, Issue 2.2 — ServiceManager runs uvicorn in daemon threads (+10 more) +Nodes (18): Category 2: Async/Sync Inconsistencies (MEDIUM), Category 4: Caching & Memory (MEDIUM), Category 6: Configuration & Environment (LOW), Category 8: Testing Gaps (MEDIUM), Executive Summary, Full Code Review Report, Issue 2.1 — All route handlers are synchronous, Issue 2.2 — ServiceManager runs uvicorn in daemon threads (+10 more) ### Community 162 - "Community 162" Cohesion: 0.21 @@ -1238,8 +1270,8 @@ Cohesion: 0.4 Nodes (4): compilerOptions, baseUrl, paths, @/* ### Community 169 - "Community 169" -Cohesion: 0.11 -Nodes (14): getCotations(), JSONBytesResponse, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur (+6 more) +Cohesion: 0.1 +Nodes (15): generateKey(), getCotations(), JSONBytesResponse, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur (+7 more) ### Community 170 - "Community 170" Cohesion: 0.25 @@ -1278,8 +1310,8 @@ Cohesion: 0.29 Nodes (7): Integration: /stocks/fundamental date filter should work per-ticker., Integration: /stocks/fundamental date filter should work per-ticker., When tickers have different date coverage, each should get its closest snapshot., When tickers have different date coverage, each should get its closest snapshot., Integration: /stocks/fundamental date filter should work per-ticker., When tickers have different date coverage, each should get its closest snapshot., TestFundamentalDateFiltering ### Community 181 - "Community 181" -Cohesion: 0.31 -Nodes (8): verifyAccessToken(), FastAPI, addRole(), addRoleToUser(), getCurrentUser(), getRolesList(), hasRole(), toDict() +Cohesion: 0.57 +Nodes (6): addRole(), addRoleToUser(), getCurrentUser(), getRolesList(), hasRole(), toDict() ### Community 182 - "Community 182" Cohesion: 0.25 @@ -1347,7 +1379,7 @@ Nodes (11): getHistorical(), Get year-based historical financial data for Brazil ### Community 198 - "Community 198" Cohesion: 0.33 -Nodes (5): downgrade(), drop unused user sessions columns Revision ID: 9f3b339dde20 Revises: add_access, Drop 7 unused columns and their deviceFingerprint index., Recreate the 7 columns and the deviceFingerprint index., upgrade() +Nodes (5): downgrade(), drop unused user sessions columns Revision ID: 9f3b339dde20 Revises: add_acc, Drop 7 unused columns and their deviceFingerprint index., Recreate the 7 columns and the deviceFingerprint index., upgrade() ### Community 199 - "Community 199" Cohesion: 0.33 @@ -1410,8 +1442,8 @@ Cohesion: 0.17 Nodes (11): code:python (def test_search_defersEmbeddingBlob(db):), code:python (from contextlib import contextmanager), code:python (from sqlalchemy.orm import defer), code:bash (git add main/app/prometheus/memory.py tests/test_memory_sear), code:python (def test_search_fusesFulltextOverVectorOnly(db):), code:python (def minMax(values: list[float]) -> list[float]:), code:bash (git add main/app/prometheus/memory.py tests/test_memory_sear), Global Constraints (+3 more) ### Community 215 - "Community 215" -Cohesion: 0.25 -Nodes (7): No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., Multiple search terms, all found in tickerIndex. +Cohesion: 0.31 +Nodes (3): Pytest Testing, PrometheusSettings, TestSandboxConfig ### Community 216 - "Community 216" Cohesion: 0.29 @@ -1419,7 +1451,7 @@ Nodes (8): readEventStream(), resumeChat(), fetchMock, file, onChunk, onCursor, ### Community 217 - "Community 217" Cohesion: 0.33 -Nodes (5): downgrade(), Add accessTokenHash, operatingSystem, lastActivityAt to user_sessions Revision, Add accessTokenHash, operatingSystem, lastActivityAt, sessionId to user_sessions, Remove columns from user_sessions., upgrade() +Nodes (5): downgrade(), Add accessTokenHash, operatingSystem, lastActivityAt to user_sessions Revisio, Add accessTokenHash, operatingSystem, lastActivityAt, sessionId to user_sessions, Remove columns from user_sessions., upgrade() ### Community 218 - "Community 218" Cohesion: 0.7 @@ -1438,8 +1470,8 @@ Cohesion: 0.2 Nodes (9): Covers lines 143, 145, 147-148: POST /user/sessions/revoke-all., Covers lines 143, 145, 147-148: POST /user/sessions/revoke-all., Covers lines 143, 145, 147-148., Covers lines 143, 145, 147-148., Covers lines 143, 145, 147-148: POST /user/sessions/revoke-all., Covers lines 143, 145, 147-148., Covers lines 143, 145, 147-148: POST /user/sessions/revoke-all., Covers lines 143, 145, 147-148. (+1 more) ### Community 222 - "Community 222" -Cohesion: 0.29 -Nodes (6): GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422. +Cohesion: 0.19 +Nodes (8): AuthenticationService, initialize(), initialize(), MCPDetectMiddleware, StocksAPIService, getApp(), runAll(), ServiceManager ### Community 223 - "Community 223" Cohesion: 0.4 @@ -1473,10 +1505,6 @@ Nodes (5): code:python (import pytest), code:python (import hashlib), code:bash Cohesion: 0.18 Nodes (11): 2.2.1 Complexity hotspots table (H1–H17 condensed to P0/P1/P2), 2.2.2 Blob inventory (LOC table + SRP evidence), 2.2.3 Mass data loads, 2.2.4 Phased fix roadmap (P0/P1/P2), §2.2 CODE EFFICIENCY — O(n²), Complexity & Blob Anti-Patterns, code:block4 (scraper.py:44 671 LOC — mass loads: SELECT * fetchma), code:powershell (ruff check . && ruff format --check .), code:powershell (pytest tests/test_stocks_cache_concurrency.py -v # ThreadPo) (+3 more) -### Community 231 - "Community 231" -Cohesion: 0.4 -Nodes (5): Category 8: Testing Gaps (MEDIUM), Issue 8.1 — No integration tests for full request lifecycle, Issue 8.2 — No tests for scraper, stocks query, or cache, Issue 8.3 — No tests for Google OAuth callback, Issue 8.4 — No tests for session cleanup - ### Community 232 - "Community 232" Cohesion: 0.4 Nodes (5): Bucket A: Security Fixes (quick wins, 30 min), Bucket B: DB Session Cleanup (medium, 1-2 hrs), Bucket C: Testing (medium, 2-3 hrs), Bucket D: Infrastructure (large, 4+ hrs), Recommended Delegation Buckets @@ -1486,8 +1514,8 @@ Cohesion: 0.4 Nodes (5): 8. Build Sequence (4 phases, each independently shippable), Phase 0 — Sandbox foundation (1-2 days, no user-facing change), Phase 1 — MCP exposure of STOCKS_API (1 day), Phase 2 — Refactor PROMETHEUS to agentic (3-5 days, the big one), Phase 3 — Hardening (1-2 days, can ship incrementally) ### Community 234 - "Community 234" -Cohesion: 0.29 -Nodes (6): GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422. +Cohesion: 0.32 +Nodes (4): memoryMaintenance(), _create(), After 10 cycles, preference (0.99^10) > context (0.90^10)., TestTypeAwareDecay ### Community 236 - "Community 236" Cohesion: 0.5 @@ -1533,10 +1561,6 @@ Nodes (4): code:tsx (import React from "react";), code:tsx (import { SandboxArti Cohesion: 0.5 Nodes (4): Category 5: Error Handling Gaps (MEDIUM), Issue 5.1 — Generic exception handler swallows traceback in production, Issue 5.2 — DiscordHandler sends only message, not traceback, Issue 5.3 — `_build_error_response` ignores `status_code` parameter -### Community 251 - "Community 251" -Cohesion: 0.14 -Nodes (4): Pytest Testing, Tests for main/utils/http_session.py — covers all branches., TestGetSession, TestPermission - ### Community 252 - "Community 252" Cohesion: 0.5 Nodes (3): Comma-separated list containing slash fields must pass., Comma-separated list containing slash fields must pass., Comma-separated list containing slash fields must pass. @@ -1573,6 +1597,10 @@ Nodes (3): 3. Goals & Non-Goals, Goals, Non-Goals (YAGNI) Cohesion: 0.5 Nodes (4): code:python (def test_link_memory_to_entities(db_session, sample_user):), code:python (# Add to main/app/prometheus/memory.py), code:bash (git add main/app/prometheus/memory.py tests/test_memory_grap), Task 5: Graph Memory Operations +### Community 263 - "Community 263" +Cohesion: 0.25 +Nodes (7): No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., Multiple search terms, all found in tickerIndex. + ### Community 474 - "Community 474" Cohesion: 0.13 Nodes (13): Covers lines 95-98: session deleted., Covers lines 96-97: session not found., Covers lines 96-97: session not found., Covers lines 96-97: session not found., Covers lines 95-98: DELETE /prometheus/sessions/{sessionId}., Covers lines 95-98: session deleted., Covers lines 96-97: session not found., Covers lines 95-98: DELETE /prometheus/sessions/{sessionId}. (+5 more) @@ -1618,23 +1646,23 @@ Cohesion: 0.23 Nodes (6): CHART_COLORS, PortfolioBarsCard(), PortfolioPieCard(), tooltipStyle, groupHistoryByMonth(), monthKey() ### Community 487 - "Community 487" -Cohesion: 0.33 -Nodes (6): dispatchToolCall must route memory tool names via TOOL_REGISTRY., dispatchToolCall must route memory tool names to executeMemoryTool., dispatchToolCall must route memory tool names to executeMemoryTool., dispatchToolCall must route memory tool names to executeMemoryTool., dispatchToolCall must route memory tool names to executeMemoryTool., TestDispatchRoutesMemoryTools +Cohesion: 0.15 +Nodes (12): dispatchToolCall must route memory tool names via TOOL_REGISTRY., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., dispatchToolCall must route memory tool names to executeMemoryTool., makeChat must include MEMORY_TOOLS alongside MCP sessions., dispatchToolCall must route memory tool names to executeMemoryTool. (+4 more) ### Community 488 - "Community 488" Cohesion: 0.33 -Nodes (6): makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., TestMakeChatIncludesMemoryTools +Nodes (4): initialize(), P5: register the session-cleanup job on the shared scheduler. Kept in thi, registerSessionCleanupJobs(), UserService ### Community 489 - "Community 489" Cohesion: 0.6 Nodes (4): hammer_measured(), main(), Fire n requests with c concurrent workers, measuring ttfb + total per request., stats() ### Community 490 - "Community 490" -Cohesion: 0.4 -Nodes (5): Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, TestVerifyAPIKey +Cohesion: 0.1 +Nodes (13): Tests for connection pool configuration, Stocks engine should have optimized pool settings, Tests for lazy JSON deserialization, Query manager should have deserialize method, Tests for dynamic ticker index feature, Ticker index should be built when cache is loaded, Ticker index should contain all tickers from cache, Ticker index should be case-insensitive (+5 more) ### Community 491 - "Community 491" -Cohesion: 0.32 +Cohesion: 0.47 Nodes (3): TestCleanup, cleanup(), Close the main thread's session at interpreter shutdown. ### Community 492 - "Community 492" @@ -1642,25 +1670,29 @@ Cohesion: 0.33 Nodes (5): Baseline (lane 4), Export recipe, Move triggers (any one fires the migration), Options, Vector Scale-Up Runbook ### Community 493 - "Community 493" -Cohesion: 0.05 -Nodes (38): Covers line 27: user already has the role., Covers line 27: user already has the role., Covers line 27: user already has the role., Covers line 27: user already has the role., Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC (+30 more) +Cohesion: 0.07 +Nodes (28): Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 36-38, 40-44, 46, 48-49, 51, 58-59, 61: successful user retrieval., Covers lines 36-38, 40-44, 46, 48-49, 51, 58-59, 61: successful user retrieval., Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 36-38, 40-44, 46, 48-49, 51, 58-59, 61: successful user retrieval. (+20 more) ### Community 495 - "Community 495" Cohesion: 0.25 Nodes (4): Authentication System, Google OAuth, JWT Authentication, TestSessionExpiryConfig ### Community 497 - "Community 497" -Cohesion: 0.5 -Nodes (4): code:python ("""add wallet_holdings and wallet_lots tables), code:python (import main.models.wallet), code:bash (git add migrations/versions/wallet_tables_20260904_add_walle), Task 2: Alembic migration for wallet tables +Cohesion: 0.25 +Nodes (7): code:python (from dataclasses import dataclass), code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py ), code:python (from datetime import date), File Structure, Global Constraints, Task 3: Pure derivation math, Wallet Management (Thoth/Iyagba) Implementation Plan ### Community 498 - "Community 498" -Cohesion: 0.06 -Nodes (36): AuthenticationManager, IntFlag, Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 28: GET /auth/health. (+28 more) +Cohesion: 0.05 +Nodes (52): AuthenticationManager, IntFlag, Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 28: GET /auth/health. (+44 more) ### Community 499 - "Community 499" Cohesion: 0.2 Nodes (9): code:python (import numpy as np), code:python (def normalizeRows(matrix: np.ndarray) -> np.ndarray:), code:bash (git add main/app/prometheus/vector.py tests/test_vector_norm), code:python ("""One-shot: renormalize stored embeddings to unit norm. Usa), code:bash (git add scripts/backfill_normalize_embeddings.py), Global Constraints, Lane 1: Normalized Embeddings + Dot-Product Search Implementation Plan, Task 1: Normalize on encode + row-normalize helper (+1 more) +### Community 500 - "Community 500" +Cohesion: 0.24 +Nodes (8): initialize(), P5: register memory maintenance on the shared scheduler. Kept in this ser, registerMemoryMaintenanceJob(), getSharedScheduler(), P5: single shared BackgroundScheduler for all services. Replaces the 4 per-serv, Return the process-wide scheduler, starting it on first use., Register func on the shared scheduler (replaces any same-id job). trigger i, registerJob() + ### Community 501 - "Community 501" Cohesion: 0.22 Nodes (3): getCurrentSession(), getSessions(), sessionToDict() @@ -1670,8 +1702,8 @@ Cohesion: 0.08 Nodes (20): Tests for connection pool configuration, Tests for connection pool configuration, Stocks engine should have optimized pool settings, Stocks engine should have optimized pool settings, Tests for lazy JSON deserialization, Tests for lazy JSON deserialization, Query manager should have deserialize method, Query manager should have deserialize method (+12 more) ### Community 503 - "Community 503" -Cohesion: 0.25 -Nodes (7): code:python (from dataclasses import dataclass), code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py ), code:python (from datetime import date), File Structure, Global Constraints, Task 3: Pure derivation math, Wallet Management (Thoth/Iyagba) Implementation Plan +Cohesion: 0.29 +Nodes (6): Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., TestStocksApiFundamental ### Community 505 - "Community 505" Cohesion: 0.33 @@ -1694,36 +1726,36 @@ Cohesion: 0.6 Nodes (3): bench(), main(), stats() ### Community 512 - "Community 512" -Cohesion: 0.22 -Nodes (9): listFields(), Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental. (+1 more) +Cohesion: 0.2 +Nodes (10): listFields(), Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental. (+2 more) ### Community 518 - "Community 518" -Cohesion: 0.07 -Nodes (17): Tests for connection pool configuration, Stocks engine should have optimized pool settings, Tests for lazy JSON deserialization, Query manager should have deserialize method, Integration tests for all query optimizations, All optimizations should be implemented, Query filter should use ticker index, Tests for dynamic ticker index feature (+9 more) +Cohesion: 0.33 +Nodes (4): Integration tests for all query optimizations, All optimizations should be implemented, Query filter should use ticker index, TestQueryOptimization ### Community 519 - "Community 519" -Cohesion: 0.29 -Nodes (6): Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError. +Cohesion: 0.22 +Nodes (7): verifyAccessToken(), Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError. ### Community 520 - "Community 520" Cohesion: 0.33 Nodes (5): pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged. ### Community 521 - "Community 521" -Cohesion: 0.38 -Nodes (9): compactCotations(), compactRow(), compactValue(), compressResponse(), fixHeaders(), getAbbr(), getNest(), toColumnar() (+1 more) +Cohesion: 0.16 +Nodes (14): compactCotations(), compactRow(), compactValue(), compressResponse(), fixHeaders(), getAbbr(), getNest(), toColumnar() (+6 more) ### Community 522 - "Community 522" -Cohesion: 0.17 +Cohesion: 0.14 Nodes (9): Verify that getSession() returns per-thread Session instances., Calling getSession() twice in the same thread returns the same object., Two threads must NOT share a Session object., With 20 concurrent threads, every thread must get its own Session., The returned object must be a real requests.Session., TestGetSession, get_session(), Return a requests.Session for the current thread. Sessions are created la (+1 more) ### Community 523 - "Community 523" -Cohesion: 0.06 -Nodes (39): check_cache(), execute_code(), list_files(), Execute Python code in an isolated sandbox. Use for quantitative analysis,, Read a file from the workspace. Args: path: Path to the file (e., Execute Python code in an isolated sandbox. Use for quantitative analysis,, Read a file from the workspace. Args: path: Path to the file (e., Execute Python code in an isolated sandbox. Use for quantitative analysis, (+31 more) +Cohesion: 0.07 +Nodes (35): check_cache(), list_files(), Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri (+27 more) ### Community 524 - "Community 524" Cohesion: 0.33 -Nodes (5): Performance tests for query operations, Query should respond within 1 second, Performance tests for query operations, Query should respond within 1 second, TestQueryPerformance +Nodes (5): Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, TestFilterBySearchTerms ### Community 525 - "Community 525" Cohesion: 0.12 @@ -1738,8 +1770,16 @@ Cohesion: 0.09 Nodes (17): client(), pytest_configure(), TestClient with all routers mounted — no lifespan (no DB/service init). O, Set required env vars before test collection. config.py eagerly instantia, Reset slowapi in-memory rate limiter between every test., Set required env vars before test collection. config.py eagerly instantia, TestClient with all routers mounted — no lifespan (no DB/service init). O, TestClient with all routers mounted — no lifespan (no DB/service init). O (+9 more) ### Community 528 - "Community 528" -Cohesion: 0.11 -Nodes (16): Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added. (+8 more) +Cohesion: 0.07 +Nodes (26): Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added. (+18 more) + +### Community 529 - "Community 529" +Cohesion: 0.22 +Nodes (4): authenticateUser(), createUserAccount(), FastAPI, PaginationParams + +### Community 530 - "Community 530" +Cohesion: 0.39 +Nodes (8): _build_error_response(), buildErrorResponse(), generic_exception_handler(), genericExceptionHandler(), http_exception_handler(), httpExceptionHandler(), validation_exception_handler(), validationExceptionHandler() ### Community 532 - "Community 532" Cohesion: 0.5 @@ -1754,21 +1794,33 @@ Cohesion: 0.5 Nodes (4): LATER (P2 — when touching these files), NOW (P0 — fix before next release), Priority Matrix, SOON (P1 — fix within 2 weeks) ### Community 536 - "Community 536" -Cohesion: 0.1 -Nodes (25): executeStateTool(), get_state(), Store a value in the harness state for this session. Use this to save inter, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Store a value in the harness state for this session. Use this to save interm (+17 more) +Cohesion: 0.15 +Nodes (18): executeStateTool(), get_state(), Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, test_dispatch_get_state(), test_dispatch_set_state() (+10 more) ### Community 538 - "Community 538" Cohesion: 0.4 Nodes (4): COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament, COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament, COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament, COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament +### Community 539 - "Community 539" +Cohesion: 0.33 +Nodes (5): Performance tests for query operations, Query should respond within 1 second, Performance tests for query operations, Query should respond within 1 second, TestQueryPerformance + ### Community 540 - "Community 540" Cohesion: 0.29 Nodes (6): code:python (import argparse), code:bash (git add bench/bench_memory_vector.py), Global Constraints, Lane 4: Before/After Bench Implementation Plan, Task 1: Bench script with synthetic scale sweep, Task 2: Record baseline and post-lane numbers +### Community 541 - "Community 541" +Cohesion: 0.38 +Nodes (6): create_memory(), createMemory(), _downloadModel(), embed(), getEmbeddingModel(), executeMemoryTool() + ### Community 542 - "Community 542" Cohesion: 0.5 Nodes (3): at, label, rows +### Community 543 - "Community 543" +Cohesion: 0.4 +Nodes (5): Category 7: Code Quality (LOW), Issue 7.1 — Unused imports, Issue 7.2 — Missing type hints, Issue 7.3 — `UserManager.__init__` does nothing, Issue 7.4 — Mixed async/sync in roles.py + ### Community 545 - "Community 545" Cohesion: 0.29 Nodes (7): code:python (def test_split_cliff_no_fake_loss_on_adjusted_series(monkeyp), code:python (def test_snapshot_includes_received_and_cash_gain(dbSession,), code:python (def test_history_merges_dividend_receipts(dbSession, sampleU), code:python (def test_ex_div_methodology_decides_received_stacking(dbSess), code:python (def ex_div_smoothing_verdict(padrao_before: float, padrao_af), code:bash (git add main/app/wallet/manager.py main/controller/wallet_co), Task 12: Split-cliff regression test + snapshot/history dividend extension + final gate @@ -1829,49 +1881,45 @@ Nodes (3): Current code (exact), Lane contracts (interfaces between lanes), Vect Cohesion: 0.5 Nodes (4): code:python (import pytest), code:python (import logging), code:bash (git add main/app/wallet/prices.py tests/test_wallet_prices.p), Task 6: Price client — one batched STOCKS_API fetch per snapshot -### Community 561 - "Community 561" -Cohesion: 0.17 -Nodes (9): Test that concurrent requests are properly serialized at DB level. Th, Test that invalid API key returns zero rows affected., Test that multiple API keys have independent quotas., Test that invalid API key returns zero rows affected., Test that multiple API keys have independent quotas., Test that atomic increment prevents race conditions., Test that atomic increment prevents race conditions., Test that concurrent requests are properly serialized at DB level. Th (+1 more) - ### Community 562 - "Community 562" Cohesion: 0.67 Nodes (3): checkServiceConnection — success, not found, errors., checkServiceConnection — success, not found, errors., TestCheckServiceConnection -### Community 563 - "Community 563" +### Community 564 - "Community 564" +Cohesion: 0.4 +Nodes (5): initialize(), P5: register the scraper cron jobs on the shared scheduler. Kept in this, registerScraperJobs(), runScraper(), ScraperService + +### Community 565 - "Community 565" Cohesion: 0.33 -Nodes (5): Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, TestFilterBySearchTerms +Nodes (6): Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., TestCreateKey ### Community 566 - "Community 566" Cohesion: 0.67 Nodes (3): checkMySqlConnection — success, errors, engine=None paths., checkMySqlConnection — success, errors, engine=None paths., TestCheckMySqlConnection ### Community 567 - "Community 567" -Cohesion: 0.15 -Nodes (17): verifyAPIKey(), Tests to increase coverage for query.py, key.py, and cache.py in stocks_api., Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., test_cache_scheduler_starts_apscheduler() (+9 more) - -### Community 568 - "Community 568" -Cohesion: 0.39 -Nodes (8): autoAbbreviate(), dedupAbbrev(), detectNestedFields(), generateAbbreviations(), _parse_date(), parseDate(), parseDateEnd(), parseDateStart() +Cohesion: 0.14 +Nodes (18): verifyAPIKey(), Tests to increase coverage for query.py, key.py, and cache.py in stocks_api., Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, test_cache_scheduler_starts_apscheduler(), test_cache_scheduler_starts_daemon_thread() (+10 more) ## Knowledge Gaps -- **3020 isolated node(s):** `$schema`, `style`, `rsc`, `tsx`, `config` (+3015 more) +- **3024 isolated node(s):** `$schema`, `style`, `rsc`, `tsx`, `config` (+3019 more) These have ≤1 connection - possible missing edges or undocumented components. -- **228 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes. +- **241 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes. ## Suggested Questions _Questions this graph is uniquely positioned to answer:_ -- **Why does `Pytest Testing` connect `Community 251` to `Authentication Core`, `Frontend Components`, `Community 129`, `Data Models & Types`, `Community 131`, `Community 518`, `Community 138`, `Community 140`, `Community 527`, `Community 18`, `Community 147`, `Community 24`, `Community 25`, `Community 536`, `Community 27`, `Community 29`, `Community 32`, `Community 33`, `Community 546`, `Community 40`, `Community 44`, `Community 45`, `Community 172`, `Community 49`, `Community 51`, `Community 181`, `Community 54`, `Community 567`, `Community 184`, `Community 59`, `Community 188`, `Community 61`, `Community 475`, `Community 120`, `Community 93`, `Community 477`, `Community 95`, `Community 99`, `Community 100`, `Community 495`, `Community 502`, `Community 504`?** - _High betweenness centrality (0.101) - this node is a cross-community bridge._ -- **Why does `UserManager` connect `Community 498` to `Prometheus Agent`, `Prometheus Memory`, `Community 140`, `Community 525`, `User Roles & Permissions`, `Community 141`, `Community 16`, `Community 528`, `Community 21`, `Community 22`, `Community 37`, `Community 47`, `Community 178`, `Community 181`, `Community 567`, `Community 58`, `Community 61`, `Community 68`, `Community 208`, `Community 86`, `Community 474`, `Community 221`, `Community 99`, `Community 101`, `Community 104`, `Community 490`, `Community 493`, `Community 114`, `Community 120`?** - _High betweenness centrality (0.049) - this node is a cross-community bridge._ -- **Why does `Prometheus` connect `Community 116` to `Frontend Components`, `Community 517`, `Device Detection`, `Community 137`, `Community 138`, `Community 140`, `Frontend App Shell`, `Community 151`, `Community 24`, `Community 162`, `Community 49`, `Community 52`, `Community 60`, `Community 61`, `Community 194`, `Community 68`, `Community 80`, `Community 87`, `Community 88`, `Community 93`, `Community 487`, `Community 488`, `Community 105`?** - _High betweenness centrality (0.042) - this node is a cross-community bridge._ +- **Why does `Pytest Testing` connect `Community 215` to `Authentication Core`, `Frontend Components`, `Community 129`, `Data Models & Types`, `Community 131`, `Community 135`, `Community 138`, `Community 140`, `Community 527`, `Community 529`, `Community 18`, `Community 147`, `Community 24`, `Community 25`, `Community 536`, `Community 27`, `Community 29`, `Community 32`, `Community 33`, `Community 546`, `Community 40`, `Community 44`, `Community 45`, `Community 172`, `Community 49`, `Community 51`, `Community 54`, `Community 567`, `Community 184`, `Community 59`, `Community 188`, `Community 67`, `Community 86`, `Community 475`, `Community 120`, `Community 93`, `Community 477`, `Community 100`, `Community 234`, `Community 490`, `Community 495`, `Community 502`, `Community 504`, `Community 251`, `Community 125`?** + _High betweenness centrality (0.112) - this node is a cross-community bridge._ +- **Why does `FastAPI` connect `Community 529` to `Community 129`, `Community 519`, `Community 530`, `Community 18`, `Community 147`, `Community 26`, `Community 33`, `Community 546`, `Community 34`, `Community 40`, `Community 169`, `Community 45`, `Community 181`, `Community 567`, `Community 58`, `Community 63`, `Community 71`, `Community 73`, `Community 84`, `Community 475`, `Community 120`, `Community 477`, `Community 222`, `Community 110`, `Community 498`, `Community 501`, `Community 504`?** + _High betweenness centrality (0.050) - this node is a cross-community bridge._ +- **Why does `UserManager` connect `Community 498` to `Community 130`, `Prometheus Agent`, `Prometheus Memory`, `Community 525`, `User Roles & Permissions`, `Community 141`, `Community 16`, `Community 528`, `Community 21`, `Community 22`, `Community 37`, `Community 47`, `Community 178`, `Community 181`, `Community 565`, `Community 567`, `Community 58`, `Community 61`, `Community 68`, `Community 208`, `Community 86`, `Community 474`, `Community 221`, `Community 99`, `Community 104`, `Community 107`, `Community 493`, `Community 503`, `Community 125`?** + _High betweenness centrality (0.032) - this node is a cross-community bridge._ - **Are the 72 inferred relationships involving `StocksCacheManager` (e.g. with `TestStocksCacheManager` and `TestVerifyAPIKey`) actually correct?** _`StocksCacheManager` has 72 INFERRED edges - model-reasoned connections that need verification._ - **Are the 52 inferred relationships involving `HarnessState` (e.g. with `Prometheus` and `.streamMessage()`) actually correct?** _`HarnessState` has 52 INFERRED edges - model-reasoned connections that need verification._ - **Are the 54 inferred relationships involving `UserManager` (e.g. with `AuthenticationManager` and `User`) actually correct?** _`UserManager` has 54 INFERRED edges - model-reasoned connections that need verification._ -- **Are the 48 inferred relationships involving `Permission` (e.g. with `PrometheusMemory` and `UserManager`) actually correct?** - _`Permission` has 48 INFERRED edges - model-reasoned connections that need verification._ \ No newline at end of file +- **Are the 38 inferred relationships involving `StocksQueryManager` (e.g. with `StocksCacheManager` and `TestStocksCacheManager`) actually correct?** + _`StocksQueryManager` has 38 INFERRED edges - model-reasoned connections that need verification._ \ No newline at end of file diff --git a/graphify-out/graph.json b/graphify-out/graph.json index a173322..15a80cb 100644 --- a/graphify-out/graph.json +++ b/graphify-out/graph.json @@ -118,7 +118,7 @@ "label": "Write-Step()", "file_type": "code", "source_file": "ci.ps1", - "source_location": "L28", + "source_location": "L27", "id": "server_ci_write_step", "community": 203, "norm_label": "write-step()" @@ -127,7 +127,7 @@ "label": "Write-Pass()", "file_type": "code", "source_file": "ci.ps1", - "source_location": "L36", + "source_location": "L35", "id": "server_ci_write_pass", "community": 203, "norm_label": "write-pass()" @@ -136,25 +136,16 @@ "label": "Write-Fail()", "file_type": "code", "source_file": "ci.ps1", - "source_location": "L42", + "source_location": "L41", "id": "server_ci_write_fail", "community": 203, "norm_label": "write-fail()" }, - { - "label": "Write-Fix()", - "file_type": "code", - "source_file": "ci.ps1", - "source_location": "L48", - "id": "server_ci_write_fix", - "community": 203, - "norm_label": "write-fix()" - }, { "label": "Run-Check()", "file_type": "code", "source_file": "ci.ps1", - "source_location": "L54", + "source_location": "L47", "id": "server_ci_run_check", "community": 203, "norm_label": "run-check()" @@ -219,7 +210,7 @@ "source_file": "config.py", "source_location": "L61", "id": "server_config_prometheussettings", - "community": 102, + "community": 215, "norm_label": "prometheussettings" }, { @@ -280,7 +271,7 @@ "label": "lifespan()", "file_type": "code", "source_file": "run.py", - "source_location": "L26", + "source_location": "L28", "id": "server_run_lifespan", "community": 110, "norm_label": "lifespan()" @@ -289,7 +280,7 @@ "label": "health()", "file_type": "code", "source_file": "run.py", - "source_location": "L78", + "source_location": "L73", "id": "server_run_health", "community": 110, "norm_label": "health()" @@ -298,7 +289,7 @@ "label": "status()", "file_type": "code", "source_file": "run.py", - "source_location": "L83", + "source_location": "L78", "id": "server_run_status", "community": 110, "norm_label": "status()" @@ -307,7 +298,7 @@ "label": "triggerScraper()", "file_type": "code", "source_file": "run.py", - "source_location": "L117", + "source_location": "L112", "id": "server_run_triggerscraper", "community": 110, "norm_label": "triggerscraper()" @@ -2199,7 +2190,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L1", "id": "main_app_authentication_authentication_py", - "community": 43, + "community": 529, "norm_label": "authentication.py" }, { @@ -2217,7 +2208,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L16", "id": "authentication_authentication_createuseraccount", - "community": 43, + "community": 529, "norm_label": "createuseraccount()" }, { @@ -2226,7 +2217,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L51", "id": "authentication_authentication_authenticategoogleuser", - "community": 43, + "community": 529, "norm_label": "authenticategoogleuser()" }, { @@ -2235,7 +2226,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L65", "id": "authentication_authentication_authenticateuser", - "community": 43, + "community": 529, "norm_label": "authenticateuser()" }, { @@ -2370,14 +2361,14 @@ "source_file": "main/app/authentication/util.py", "source_location": "L1", "id": "main_app_authentication_util_py", - "community": 181, + "community": 519, "norm_label": "util.py" }, { "label": "hashPassword()", "file_type": "code", "source_file": "main/app/authentication/util.py", - "source_location": "L13", + "source_location": "L14", "id": "authentication_util_hashpassword", "community": 43, "norm_label": "hashpassword()" @@ -2386,7 +2377,7 @@ "label": "verifyPassword()", "file_type": "code", "source_file": "main/app/authentication/util.py", - "source_location": "L21", + "source_location": "L22", "id": "authentication_util_verifypassword", "community": 43, "norm_label": "verifypassword()" @@ -2395,7 +2386,7 @@ "label": "createAccessToken()", "file_type": "code", "source_file": "main/app/authentication/util.py", - "source_location": "L30", + "source_location": "L31", "id": "authentication_util_createaccesstoken", "community": 58, "norm_label": "createaccesstoken()" @@ -2404,16 +2395,16 @@ "label": "verifyAccessToken()", "file_type": "code", "source_file": "main/app/authentication/util.py", - "source_location": "L43", + "source_location": "L44", "id": "authentication_util_verifyaccesstoken", - "community": 181, + "community": 519, "norm_label": "verifyaccesstoken()" }, { "label": "extractTokenPayload()", "file_type": "code", "source_file": "main/app/authentication/util.py", - "source_location": "L53", + "source_location": "L54", "id": "authentication_util_extracttokenpayload", "community": 98, "norm_label": "extracttokenpayload()" @@ -2431,7 +2422,7 @@ "label": "safeFilter()", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L26", + "source_location": "L25", "id": "prometheus_agent_safefilter", "community": 116, "norm_label": "safefilter()" @@ -2440,7 +2431,7 @@ "label": "getClient()", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L39", + "source_location": "L38", "id": "prometheus_agent_getclient", "community": 116, "norm_label": "getclient()" @@ -2449,7 +2440,7 @@ "label": "Prometheus", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L202", + "source_location": "L201", "id": "prometheus_agent_prometheus", "community": 116, "norm_label": "prometheus" @@ -2458,7 +2449,7 @@ "label": ".__init__()", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L203", + "source_location": "L202", "id": "prometheus_agent_prometheus_init", "community": 116, "norm_label": ".__init__()" @@ -2467,7 +2458,7 @@ "label": "buildSystemPrompt()", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L207", + "source_location": "L206", "id": "prometheus_agent_buildsystemprompt", "community": 116, "norm_label": "buildsystemprompt()" @@ -2476,7 +2467,7 @@ "label": ".makeChat()", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L236", + "source_location": "L235", "id": "prometheus_agent_prometheus_makechat", "community": 116, "norm_label": ".makechat()" @@ -2485,7 +2476,7 @@ "label": ".streamMessage()", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L247", + "source_location": "L246", "id": "prometheus_agent_prometheus_streammessage", "community": 116, "norm_label": ".streammessage()" @@ -2536,28 +2527,19 @@ "norm_label": "updatesessiontitle()" }, { - "label": "saveMessage()", + "label": "appendHistory()", "file_type": "code", "source_file": "main/app/prometheus/chat.py", "source_location": "L52", - "id": "prometheus_chat_savemessage", + "id": "prometheus_chat_appendhistory", "community": 125, - "norm_label": "savemessage()" - }, - { - "label": "saveLoopEvent()", - "file_type": "code", - "source_file": "main/app/prometheus/chat.py", - "source_location": "L76", - "id": "prometheus_chat_saveloopevent", - "community": 125, - "norm_label": "saveloopevent()" + "norm_label": "appendhistory()" }, { "label": "getHistory()", "file_type": "code", "source_file": "main/app/prometheus/chat.py", - "source_location": "L95", + "source_location": "L71", "id": "prometheus_chat_gethistory", "community": 125, "norm_label": "gethistory()" @@ -2566,7 +2548,7 @@ "label": "deleteSession()", "file_type": "code", "source_file": "main/app/prometheus/chat.py", - "source_location": "L116", + "source_location": "L92", "id": "prometheus_chat_deletesession", "community": 125, "norm_label": "deletesession()" @@ -2575,7 +2557,7 @@ "label": "verifySessionOwnership()", "file_type": "code", "source_file": "main/app/prometheus/chat.py", - "source_location": "L130", + "source_location": "L106", "id": "prometheus_chat_verifysessionownership", "community": 125, "norm_label": "verifysessionownership()" @@ -2593,7 +2575,7 @@ "label": "getTokenizer()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L31", + "source_location": "L33", "id": "prometheus_compact_gettokenizer", "community": 80, "norm_label": "gettokenizer()" @@ -2602,7 +2584,7 @@ "label": "countTokens()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L43", + "source_location": "L45", "id": "prometheus_compact_counttokens", "community": 80, "norm_label": "counttokens()" @@ -2611,7 +2593,7 @@ "label": "getStocksFieldsUrl()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L60", + "source_location": "L62", "id": "prometheus_compact_getstocksfieldsurl", "community": 80, "norm_label": "getstocksfieldsurl()" @@ -2620,7 +2602,7 @@ "label": "loadFieldData()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L64", + "source_location": "L66", "id": "prometheus_compact_loadfielddata", "community": 80, "norm_label": "loadfielddata()" @@ -2629,7 +2611,7 @@ "label": "getHistoricalFields()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L87", + "source_location": "L89", "id": "prometheus_compact_gethistoricalfields", "community": 80, "norm_label": "gethistoricalfields()" @@ -2638,7 +2620,7 @@ "label": "getFundamentalColumns()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L91", + "source_location": "L93", "id": "prometheus_compact_getfundamentalcolumns", "community": 80, "norm_label": "getfundamentalcolumns()" @@ -2647,7 +2629,7 @@ "label": "invalidateFieldData()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L95", + "source_location": "L97", "id": "prometheus_compact_invalidatefielddata", "community": 80, "norm_label": "invalidatefielddata()" @@ -2656,16 +2638,25 @@ "label": "getMetricRegex()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L101", + "source_location": "L103", "id": "prometheus_compact_getmetricregex", "community": 80, "norm_label": "getmetricregex()" }, + { + "label": "dedup()", + "file_type": "code", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L117", + "id": "prometheus_compact_dedup", + "community": 80, + "norm_label": "dedup()" + }, { "label": "extractTickers()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L115", + "source_location": "L121", "id": "prometheus_compact_extracttickers", "community": 80, "norm_label": "extracttickers()" @@ -2674,7 +2665,7 @@ "label": "extractMetrics()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L119", + "source_location": "L125", "id": "prometheus_compact_extractmetrics", "community": 80, "norm_label": "extractmetrics()" @@ -2787,20 +2778,11 @@ "community": 194, "norm_label": "mcp.py" }, - { - "label": "ensureFastmcp()", - "file_type": "code", - "source_file": "main/app/prometheus/mcp.py", - "source_location": "L10", - "id": "prometheus_mcp_ensurefastmcp", - "community": 194, - "norm_label": "ensurefastmcp()" - }, { "label": "buildClient()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L33", + "source_location": "L21", "id": "prometheus_mcp_buildclient", "community": 194, "norm_label": "buildclient()" @@ -2809,7 +2791,7 @@ "label": "MCPClientPool", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L42", + "source_location": "L29", "id": "prometheus_mcp_mcpclientpool", "community": 194, "norm_label": "mcpclientpool" @@ -2818,7 +2800,7 @@ "label": ".__init__()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L43", + "source_location": "L30", "id": "prometheus_mcp_mcpclientpool_init", "community": 194, "norm_label": ".__init__()" @@ -2827,7 +2809,7 @@ "label": ".initialize()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L48", + "source_location": "L35", "id": "prometheus_mcp_mcpclientpool_initialize", "community": 194, "norm_label": ".initialize()" @@ -2836,7 +2818,7 @@ "label": ".getClients()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L65", + "source_location": "L52", "id": "prometheus_mcp_mcpclientpool_getclients", "community": 194, "norm_label": ".getclients()" @@ -2845,7 +2827,7 @@ "label": ".healthCheck()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L72", + "source_location": "L59", "id": "prometheus_mcp_mcpclientpool_healthcheck", "community": 194, "norm_label": ".healthcheck()" @@ -2854,7 +2836,7 @@ "label": ".reconnect()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L84", + "source_location": "L71", "id": "prometheus_mcp_mcpclientpool_reconnect", "community": 194, "norm_label": ".reconnect()" @@ -2863,7 +2845,7 @@ "label": ".close()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L101", + "source_location": "L88", "id": "prometheus_mcp_mcpclientpool_close", "community": 194, "norm_label": ".close()" @@ -2908,7 +2890,7 @@ "label": "invalidateUser()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L53", + "source_location": "L56", "id": "prometheus_memory_invalidateuser", "community": 53, "norm_label": "invalidateuser()" @@ -2917,7 +2899,7 @@ "label": "clearAll()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L57", + "source_location": "L60", "id": "prometheus_memory_clearall", "community": 53, "norm_label": "clearall()" @@ -2926,7 +2908,7 @@ "label": "getClient()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L81", + "source_location": "L84", "id": "prometheus_memory_getclient", "community": 53, "norm_label": "getclient()" @@ -2935,16 +2917,16 @@ "label": "minMax()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L88", + "source_location": "L91", "id": "prometheus_memory_minmax", - "community": 53, + "community": 13, "norm_label": "minmax()" }, { "label": "normalizeKey()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L97", + "source_location": "L100", "id": "prometheus_memory_normalizekey", "community": 53, "norm_label": "normalizekey()" @@ -2953,16 +2935,43 @@ "label": "findSimilarKey()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L104", + "source_location": "L107", "id": "prometheus_memory_findsimilarkey", "community": 53, "norm_label": "findsimilarkey()" }, + { + "label": "scoreRecency()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L130", + "id": "prometheus_memory_scorerecency", + "community": 13, + "norm_label": "scorerecency()" + }, + { + "label": "scoreCandidates()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L148", + "id": "prometheus_memory_scorecandidates", + "community": 13, + "norm_label": "scorecandidates()" + }, + { + "label": "sumTokens()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L176", + "id": "prometheus_memory_sumtokens", + "community": 53, + "norm_label": "sumtokens()" + }, { "label": "PrometheusMemory", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L127", + "source_location": "L191", "id": "prometheus_memory_prometheusmemory", "community": 140, "norm_label": "prometheusmemory" @@ -2971,7 +2980,7 @@ "label": "getMemoryLimit()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L129", + "source_location": "L193", "id": "prometheus_memory_getmemorylimit", "community": 53, "norm_label": "getmemorylimit()" @@ -2980,7 +2989,7 @@ "label": "countMemories()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L135", + "source_location": "L199", "id": "prometheus_memory_countmemories", "community": 53, "norm_label": "countmemories()" @@ -2989,7 +2998,7 @@ "label": "upsertMemory()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L144", + "source_location": "L208", "id": "prometheus_memory_upsertmemory", "community": 53, "norm_label": "upsertmemory()" @@ -2998,34 +3007,34 @@ "label": "search()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L222", + "source_location": "L286", "id": "prometheus_memory_search", - "community": 53, + "community": 13, "norm_label": "search()" }, { "label": "fullTextSearch()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L317", + "source_location": "L349", "id": "prometheus_memory_fulltextsearch", - "community": 53, + "community": 13, "norm_label": "fulltextsearch()" }, { "label": "getUserMemories()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L375", + "source_location": "L407", "id": "prometheus_memory_getusermemories", - "community": 27, + "community": 53, "norm_label": "getusermemories()" }, { "label": "deleteMemory()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L400", + "source_location": "L432", "id": "prometheus_memory_deletememory", "community": 53, "norm_label": "deletememory()" @@ -3034,16 +3043,16 @@ "label": "countTokensCached()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L418", + "source_location": "L450", "id": "prometheus_memory_counttokenscached", - "community": 80, + "community": 53, "norm_label": "counttokenscached()" }, { "label": "extract()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L428", + "source_location": "L454", "id": "prometheus_memory_extract", "community": 53, "norm_label": "extract()" @@ -3079,7 +3088,7 @@ "label": "hostPath()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L32", + "source_location": "L36", "id": "prometheus_sandbox_hostpath", "community": 69, "norm_label": "hostpath()" @@ -3088,7 +3097,7 @@ "label": "sandboxPath()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L46", + "source_location": "L50", "id": "prometheus_sandbox_sandboxpath", "community": 69, "norm_label": "sandboxpath()" @@ -3097,7 +3106,7 @@ "label": "SandboxManager", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L51", + "source_location": "L55", "id": "prometheus_sandbox_sandboxmanager", "community": 2, "norm_label": "sandboxmanager" @@ -3106,7 +3115,7 @@ "label": "create()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L53", + "source_location": "L57", "id": "prometheus_sandbox_create", "community": 69, "norm_label": "create()" @@ -3115,7 +3124,7 @@ "label": "destroy()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L69", + "source_location": "L73", "id": "prometheus_sandbox_destroy", "community": 69, "norm_label": "destroy()" @@ -3124,7 +3133,7 @@ "label": "getOrCreate()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L81", + "source_location": "L85", "id": "prometheus_sandbox_getorcreate", "community": 69, "norm_label": "getorcreate()" @@ -3133,7 +3142,7 @@ "label": "execute()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L128", + "source_location": "L132", "id": "prometheus_sandbox_execute", "community": 69, "norm_label": "execute()" @@ -3142,7 +3151,7 @@ "label": "read_file()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L164", + "source_location": "L168", "id": "prometheus_sandbox_read_file", "community": 69, "norm_label": "read_file()" @@ -3151,7 +3160,7 @@ "label": "write_file()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L171", + "source_location": "L175", "id": "prometheus_sandbox_write_file", "community": 69, "norm_label": "write_file()" @@ -3160,7 +3169,7 @@ "label": "list_files()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L182", + "source_location": "L186", "id": "prometheus_sandbox_list_files", "community": 69, "norm_label": "list_files()" @@ -3169,7 +3178,7 @@ "label": "write_bytes()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L190", + "source_location": "L194", "id": "prometheus_sandbox_write_bytes", "community": 69, "norm_label": "write_bytes()" @@ -3178,7 +3187,7 @@ "label": "delete_file()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L201", + "source_location": "L205", "id": "prometheus_sandbox_delete_file", "community": 69, "norm_label": "delete_file()" @@ -3187,7 +3196,7 @@ "label": "syncToSandbox()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L218", + "source_location": "L222", "id": "prometheus_sandbox_synctosandbox", "community": 69, "norm_label": "synctosandbox()" @@ -3196,7 +3205,7 @@ "label": "syncFromSandbox()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L237", + "source_location": "L241", "id": "prometheus_sandbox_syncfromsandbox", "community": 69, "norm_label": "syncfromsandbox()" @@ -3322,7 +3331,7 @@ "label": "search_memory()", "file_type": "code", "source_file": "main/app/prometheus/tools.py", - "source_location": "L18", + "source_location": "L20", "id": "prometheus_tools_search_memory", "community": 152, "norm_label": "search_memory()" @@ -3331,7 +3340,7 @@ "label": "save_memory()", "file_type": "code", "source_file": "main/app/prometheus/tools.py", - "source_location": "L48", + "source_location": "L51", "id": "prometheus_tools_save_memory", "community": 152, "norm_label": "save_memory()" @@ -3340,16 +3349,16 @@ "label": "execute_code()", "file_type": "code", "source_file": "main/app/prometheus/tools.py", - "source_location": "L89", + "source_location": "L93", "id": "prometheus_tools_execute_code", - "community": 523, + "community": 101, "norm_label": "execute_code()" }, { "label": "read_file()", "file_type": "code", "source_file": "main/app/prometheus/tools.py", - "source_location": "L110", + "source_location": "L114", "id": "prometheus_tools_read_file", "community": 523, "norm_label": "read_file()" @@ -3358,7 +3367,7 @@ "label": "write_file()", "file_type": "code", "source_file": "main/app/prometheus/tools.py", - "source_location": "L124", + "source_location": "L128", "id": "prometheus_tools_write_file", "community": 523, "norm_label": "write_file()" @@ -3367,7 +3376,7 @@ "label": "list_files()", "file_type": "code", "source_file": "main/app/prometheus/tools.py", - "source_location": "L140", + "source_location": "L144", "id": "prometheus_tools_list_files", "community": 523, "norm_label": "list_files()" @@ -3376,7 +3385,7 @@ "label": "serve_file()", "file_type": "code", "source_file": "main/app/prometheus/tools.py", - "source_location": "L153", + "source_location": "L157", "id": "prometheus_tools_serve_file", "community": 523, "norm_label": "serve_file()" @@ -3385,7 +3394,7 @@ "label": "dispatchToolCall()", "file_type": "code", "source_file": "main/app/prometheus/tools.py", - "source_location": "L188", + "source_location": "L190", "id": "prometheus_tools_dispatchtoolcall", "community": 49, "norm_label": "dispatchtoolcall()" @@ -3394,8 +3403,8 @@ "label": "Search user's saved memories, preferences, and past analysis context. Use", "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", - "source_location": "L19", - "id": "prometheus_tools_rationale_19", + "source_location": "L21", + "id": "prometheus_tools_rationale_21", "community": 152, "norm_label": "search user's saved memories, preferences, and past analysis context. use" }, @@ -3403,8 +3412,8 @@ "label": "Store a memory about the user's preferences, analysis results, or feedback.", "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", - "source_location": "L49", - "id": "prometheus_tools_rationale_49", + "source_location": "L52", + "id": "prometheus_tools_rationale_52", "community": 152, "norm_label": "store a memory about the user's preferences, analysis results, or feedback." }, @@ -3412,17 +3421,17 @@ "label": "Execute Python code in an isolated sandbox. Use for quantitative analysis,", "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", - "source_location": "L90", - "id": "prometheus_tools_rationale_90", - "community": 523, + "source_location": "L94", + "id": "prometheus_tools_rationale_94", + "community": 101, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis," }, { "label": "Read a file from the workspace. Args: path: Path to the file (e.", "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", - "source_location": "L111", - "id": "prometheus_tools_rationale_111", + "source_location": "L115", + "id": "prometheus_tools_rationale_115", "community": 523, "norm_label": "read a file from the workspace. args: path: path to the file (e." }, @@ -3430,8 +3439,8 @@ "label": "Write a file to the workspace. Use this to save data files (CSV, JSON, scri", "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", - "source_location": "L125", - "id": "prometheus_tools_rationale_125", + "source_location": "L129", + "id": "prometheus_tools_rationale_129", "community": 523, "norm_label": "write a file to the workspace. use this to save data files (csv, json, scri" }, @@ -3439,8 +3448,8 @@ "label": "List files in the workspace directory. Args: path: Directory pat", "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", - "source_location": "L141", - "id": "prometheus_tools_rationale_141", + "source_location": "L145", + "id": "prometheus_tools_rationale_145", "community": 523, "norm_label": "list files in the workspace directory. args: path: directory pat" }, @@ -3448,8 +3457,8 @@ "label": "Get a download link for a workspace file to share with the user. Use this", "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", - "source_location": "L154", - "id": "prometheus_tools_rationale_154", + "source_location": "L158", + "id": "prometheus_tools_rationale_158", "community": 523, "norm_label": "get a download link for a workspace file to share with the user. use this" }, @@ -3477,7 +3486,7 @@ "source_file": "main/app/prometheus/vector.py", "source_location": "L15", "id": "prometheus_vector_embed", - "community": 84, + "community": 13, "norm_label": "embed()" }, { @@ -3504,7 +3513,7 @@ "source_file": "main/app/prometheus/vector.py", "source_location": "L51", "id": "prometheus_vector_contenthash", - "community": 112, + "community": 53, "norm_label": "contenthash()" }, { @@ -3529,7 +3538,7 @@ "label": "getRelevanceScore()", "file_type": "code", "source_file": "main/app/prometheus/vector.py", - "source_location": "L70", + "source_location": "L71", "id": "prometheus_vector_getrelevancescore", "community": 27, "norm_label": "getrelevancescore()" @@ -3558,7 +3567,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L42", "id": "scraper_b3_scraper_b3scraper", - "community": 72, + "community": 535, "norm_label": "b3scraper" }, { @@ -3630,7 +3639,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L228", "id": "scraper_b3_scraper_b3scraper_historicalcotationprofits_oceans14", - "community": 72, + "community": 535, "norm_label": ".historicalcotationprofits_oceans14()" }, { @@ -3666,7 +3675,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L296", "id": "scraper_b3_scraper_b3scraper_fundamentalindicators", - "community": 72, + "community": 535, "norm_label": ".fundamentalindicators()" }, { @@ -3675,7 +3684,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L419", "id": "scraper_b3_scraper_b3scraper_processticker", - "community": 72, + "community": 535, "norm_label": ".processticker()" }, { @@ -3684,7 +3693,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L450", "id": "scraper_b3_scraper_b3scraper_scrapestocks", - "community": 72, + "community": 535, "norm_label": ".scrapestocks()" }, { @@ -3693,7 +3702,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L497", "id": "scraper_b3_scraper_b3scraper_reordercolumns", - "community": 72, + "community": 535, "norm_label": ".reordercolumns()" }, { @@ -3702,7 +3711,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L506", "id": "scraper_b3_scraper_b3scraper_serializecomplextypes", - "community": 72, + "community": 535, "norm_label": ".serializecomplextypes()" }, { @@ -3711,7 +3720,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L525", "id": "scraper_b3_scraper_b3scraper_exportjson", - "community": 72, + "community": 535, "norm_label": ".exportjson()" }, { @@ -3720,7 +3729,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L533", "id": "scraper_b3_scraper_b3scraper_exportmysql", - "community": 72, + "community": 535, "norm_label": ".exportmysql()" }, { @@ -3823,19 +3832,28 @@ "norm_label": ".__init__()" }, { - "label": ".cacheScheduler()", + "label": ".snapshot()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", "source_location": "L198", + "id": "stocks_api_cache_stockscachemanager_snapshot", + "community": 42, + "norm_label": ".snapshot()" + }, + { + "label": ".cacheScheduler()", + "file_type": "code", + "source_file": "main/app/stocks_api/cache.py", + "source_location": "L202", "id": "stocks_api_cache_stockscachemanager_cachescheduler", - "community": 72, + "community": 500, "norm_label": ".cachescheduler()" }, { "label": ".loadFromFeather()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L209", + "source_location": "L213", "id": "stocks_api_cache_stockscachemanager_loadfromfeather", "community": 82, "norm_label": ".loadfromfeather()" @@ -3844,7 +3862,7 @@ "label": ".getCachedStocks()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L228", + "source_location": "L232", "id": "stocks_api_cache_stockscachemanager_getcachedstocks", "community": 82, "norm_label": ".getcachedstocks()" @@ -3862,7 +3880,7 @@ "label": "getAbbr()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L25", + "source_location": "L23", "id": "stocks_api_compress_getabbr", "community": 521, "norm_label": "getabbr()" @@ -3871,7 +3889,7 @@ "label": "getNest()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L36", + "source_location": "L31", "id": "stocks_api_compress_getnest", "community": 521, "norm_label": "getnest()" @@ -3880,7 +3898,7 @@ "label": "rebuildAbbrevs()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L49", + "source_location": "L41", "id": "stocks_api_compress_rebuildabbrevs", "community": 82, "norm_label": "rebuildabbrevs()" @@ -3889,7 +3907,7 @@ "label": "walk()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L54", + "source_location": "L46", "id": "stocks_api_compress_walk", "community": 521, "norm_label": "walk()" @@ -3898,7 +3916,7 @@ "label": "compactValue()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L62", + "source_location": "L54", "id": "stocks_api_compress_compactvalue", "community": 521, "norm_label": "compactvalue()" @@ -3907,7 +3925,7 @@ "label": "toColumnar()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L83", + "source_location": "L75", "id": "stocks_api_compress_tocolumnar", "community": 521, "norm_label": "tocolumnar()" @@ -3916,7 +3934,7 @@ "label": "fixHeaders()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L92", + "source_location": "L84", "id": "stocks_api_compress_fixheaders", "community": 521, "norm_label": "fixheaders()" @@ -3925,7 +3943,7 @@ "label": "compactRow()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L101", + "source_location": "L93", "id": "stocks_api_compress_compactrow", "community": 521, "norm_label": "compactrow()" @@ -3934,7 +3952,7 @@ "label": "compactCotations()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L129", + "source_location": "L121", "id": "stocks_api_compress_compactcotations", "community": 521, "norm_label": "compactcotations()" @@ -3943,7 +3961,7 @@ "label": "compressResponse()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L163", + "source_location": "L155", "id": "stocks_api_compress_compressresponse", "community": 521, "norm_label": "compressresponse()" @@ -3954,23 +3972,14 @@ "source_file": "main/app/stocks_api/key.py", "source_location": "L1", "id": "main_app_stocks_api_key_py", - "community": 37, - "norm_label": "key.py" - }, - { - "label": "hashKey()", - "file_type": "code", - "source_file": "main/app/stocks_api/key.py", - "source_location": "L17", - "id": "stocks_api_key_hashkey", "community": 26, - "norm_label": "hashkey()" + "norm_label": "key.py" }, { "label": "verifyAPIKey()", "file_type": "code", "source_file": "main/app/stocks_api/key.py", - "source_location": "L21", + "source_location": "L17", "id": "stocks_api_key_verifyapikey", "community": 567, "norm_label": "verifyapikey()" @@ -4006,7 +4015,7 @@ "label": "StocksQueryManager", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L56", + "source_location": "L54", "id": "stocks_api_query_stocksquerymanager", "community": 63, "norm_label": "stocksquerymanager" @@ -4015,16 +4024,34 @@ "label": ".__init__()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L57", + "source_location": "L55", "id": "stocks_api_query_stocksquerymanager_init", "community": 63, "norm_label": ".__init__()" }, + { + "label": ".baseFrame()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L58", + "id": "stocks_api_query_stocksquerymanager_baseframe", + "community": 63, + "norm_label": ".baseframe()" + }, + { + "label": ".finalize()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L69", + "id": "stocks_api_query_stocksquerymanager_finalize", + "community": 63, + "norm_label": ".finalize()" + }, { "label": ".deserializeJsonColumns()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L60", + "source_location": "L109", "id": "stocks_api_query_stocksquerymanager_deserializejsoncolumns", "community": 63, "norm_label": ".deserializejsoncolumns()" @@ -4033,7 +4060,7 @@ "label": ".filterBySearchTerms()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L94", + "source_location": "L136", "id": "stocks_api_query_stocksquerymanager_filterbysearchterms", "community": 63, "norm_label": ".filterbysearchterms()" @@ -4042,7 +4069,7 @@ "label": ".queryHistorical()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L111", + "source_location": "L153", "id": "stocks_api_query_stocksquerymanager_queryhistorical", "community": 63, "norm_label": ".queryhistorical()" @@ -4051,7 +4078,7 @@ "label": ".queryFundamental()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L190", + "source_location": "L220", "id": "stocks_api_query_stocksquerymanager_queryfundamental", "community": 63, "norm_label": ".queryfundamental()" @@ -4060,7 +4087,7 @@ "label": ".queryCotations()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L276", + "source_location": "L284", "id": "stocks_api_query_stocksquerymanager_querycotations", "community": 63, "norm_label": ".querycotations()" @@ -4069,7 +4096,7 @@ "label": ".queryLiveCotation()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L329", + "source_location": "L331", "id": "stocks_api_query_stocksquerymanager_querylivecotation", "community": 63, "norm_label": ".querylivecotation()" @@ -4098,7 +4125,7 @@ "source_file": "main/app/stocks_api/util.py", "source_location": "L1", "id": "main_app_stocks_api_util_py", - "community": 568, + "community": 73, "norm_label": "util.py" }, { @@ -4107,7 +4134,7 @@ "source_file": "main/app/stocks_api/util.py", "source_location": "L20", "id": "stocks_api_util_dedupabbrev", - "community": 568, + "community": 521, "norm_label": "dedupabbrev()" }, { @@ -4116,7 +4143,7 @@ "source_file": "main/app/stocks_api/util.py", "source_location": "L29", "id": "stocks_api_util_autoabbreviate", - "community": 568, + "community": 521, "norm_label": "autoabbreviate()" }, { @@ -4125,7 +4152,7 @@ "source_file": "main/app/stocks_api/util.py", "source_location": "L50", "id": "stocks_api_util_generateabbreviations", - "community": 568, + "community": 521, "norm_label": "generateabbreviations()" }, { @@ -4143,7 +4170,7 @@ "source_file": "main/app/stocks_api/util.py", "source_location": "L76", "id": "stocks_api_util_parsedate", - "community": 568, + "community": 73, "norm_label": "parsedate()" }, { @@ -4161,7 +4188,7 @@ "source_file": "main/app/stocks_api/util.py", "source_location": "L99", "id": "stocks_api_util_detectnestedfields", - "community": 568, + "community": 521, "norm_label": "detectnestedfields()" }, { @@ -4407,38 +4434,11 @@ "community": 169, "norm_label": "stocksapi_controller.py" }, - { - "label": "JSONBytesResponse", - "file_type": "code", - "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L23", - "id": "controller_stocksapi_controller_jsonbytesresponse", - "community": 169, - "norm_label": "jsonbytesresponse" - }, - { - "label": "FastAPIResponse", - "file_type": "code", - "source_file": "", - "source_location": "", - "id": "fastapiresponse", - "community": 169, - "norm_label": "fastapiresponse" - }, - { - "label": ".render()", - "file_type": "code", - "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L26", - "id": "controller_stocksapi_controller_jsonbytesresponse_render", - "community": 169, - "norm_label": ".render()" - }, { "label": "health()", "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L31", + "source_location": "L23", "id": "controller_stocksapi_controller_health", "community": 169, "norm_label": "health()" @@ -4447,7 +4447,7 @@ "label": "listFields()", "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L46", + "source_location": "L38", "id": "controller_stocksapi_controller_listfields", "community": 512, "norm_label": "listfields()" @@ -4456,7 +4456,7 @@ "label": "getHistorical()", "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L93", + "source_location": "L85", "id": "controller_stocksapi_controller_gethistorical", "community": 197, "norm_label": "gethistorical()" @@ -4465,7 +4465,7 @@ "label": "getFundamental()", "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L158", + "source_location": "L150", "id": "controller_stocksapi_controller_getfundamental", "community": 157, "norm_label": "getfundamental()" @@ -4474,7 +4474,7 @@ "label": "getCotations()", "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L228", + "source_location": "L220", "id": "controller_stocksapi_controller_getcotations", "community": 169, "norm_label": "getcotations()" @@ -4483,7 +4483,7 @@ "label": "getLiveCotation()", "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L284", + "source_location": "L276", "id": "controller_stocksapi_controller_getlivecotation", "community": 81, "norm_label": "getlivecotation()" @@ -4492,8 +4492,8 @@ "label": "Discover available field names before querying /historical or /fundamental.", "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L47", - "id": "controller_stocksapi_controller_rationale_47", + "source_location": "L39", + "id": "controller_stocksapi_controller_rationale_39", "community": 512, "norm_label": "discover available field names before querying /historical or /fundamental." }, @@ -4501,8 +4501,8 @@ "label": "Get year-based historical financial data for Brazilian B3 stocks. Returns", "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L103", - "id": "controller_stocksapi_controller_rationale_103", + "source_location": "L95", + "id": "controller_stocksapi_controller_rationale_95", "community": 197, "norm_label": "get year-based historical financial data for brazilian b3 stocks. returns" }, @@ -4510,8 +4510,8 @@ "label": "Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret", "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L168", - "id": "controller_stocksapi_controller_rationale_168", + "source_location": "L160", + "id": "controller_stocksapi_controller_rationale_160", "community": 157, "norm_label": "get point-in-time fundamental/valuation data for brazilian b3 stocks. ret" }, @@ -4519,8 +4519,8 @@ "label": "Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur", "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L236", - "id": "controller_stocksapi_controller_rationale_236", + "source_location": "L228", + "id": "controller_stocksapi_controller_rationale_228", "community": 169, "norm_label": "get 10-year daily price history (cotation) for brazilian b3 stocks. retur" }, @@ -4528,8 +4528,8 @@ "label": "Get real-time price quotation for a single Brazilian B3 stock. Returns th", "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L290", - "id": "controller_stocksapi_controller_rationale_290", + "source_location": "L282", + "id": "controller_stocksapi_controller_rationale_282", "community": 81, "norm_label": "get real-time price quotation for a single brazilian b3 stock. returns th" }, @@ -4656,7 +4656,7 @@ "source_file": "main/models/prometheus.py", "source_location": "L1", "id": "main_models_prometheus_py", - "community": 61, + "community": 125, "norm_label": "prometheus.py" }, { @@ -4665,7 +4665,7 @@ "source_file": "main/models/prometheus.py", "source_location": "L7", "id": "models_prometheus_prometheussession", - "community": 61, + "community": 125, "norm_label": "prometheussession" }, { @@ -4800,7 +4800,7 @@ "source_file": "main/service/authentication_service.py", "source_location": "L1", "id": "main_service_authentication_service_py", - "community": 72, + "community": 222, "norm_label": "authentication_service.py" }, { @@ -4809,7 +4809,7 @@ "source_file": "main/service/authentication_service.py", "source_location": "L9", "id": "service_authentication_service_authenticationservice", - "community": 72, + "community": 222, "norm_label": "authenticationservice" }, { @@ -4818,7 +4818,7 @@ "source_file": "main/service/authentication_service.py", "source_location": "L11", "id": "service_authentication_service_initialize", - "community": 72, + "community": 222, "norm_label": "initialize()" }, { @@ -4827,7 +4827,7 @@ "source_file": "main/service/prometheus_service.py", "source_location": "L1", "id": "main_service_prometheus_service_py", - "community": 72, + "community": 500, "norm_label": "prometheus_service.py" }, { @@ -4836,7 +4836,7 @@ "source_file": "main/service/prometheus_service.py", "source_location": "L23", "id": "service_prometheus_service_memorymaintenance", - "community": 54, + "community": 234, "norm_label": "memorymaintenance()" }, { @@ -4854,7 +4854,7 @@ "source_file": "main/service/prometheus_service.py", "source_location": "L67", "id": "service_prometheus_service_initialize", - "community": 72, + "community": 500, "norm_label": "initialize()" }, { @@ -4863,7 +4863,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L1", "id": "main_service_scraper_service_py", - "community": 72, + "community": 564, "norm_label": "scraper_service.py" }, { @@ -4872,7 +4872,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L13", "id": "service_scraper_service_runscraper", - "community": 72, + "community": 564, "norm_label": "runscraper()" }, { @@ -4881,7 +4881,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L23", "id": "service_scraper_service_registerscraperjobs", - "community": 72, + "community": 564, "norm_label": "registerscraperjobs()" }, { @@ -4890,7 +4890,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L49", "id": "service_scraper_service_scraperservice", - "community": 72, + "community": 564, "norm_label": "scraperservice" }, { @@ -4899,7 +4899,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L51", "id": "service_scraper_service_initialize", - "community": 72, + "community": 564, "norm_label": "initialize()" }, { @@ -4908,7 +4908,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L1", "id": "main_service_stocksapi_service_py", - "community": 72, + "community": 222, "norm_label": "stocksapi_service.py" }, { @@ -4917,7 +4917,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L10", "id": "service_stocksapi_service_mcpdetectmiddleware", - "community": 72, + "community": 222, "norm_label": "mcpdetectmiddleware" }, { @@ -4926,7 +4926,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L11", "id": "service_stocksapi_service_mcpdetectmiddleware_init", - "community": 72, + "community": 222, "norm_label": ".__init__()" }, { @@ -4935,7 +4935,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L14", "id": "service_stocksapi_service_mcpdetectmiddleware_call", - "community": 72, + "community": 222, "norm_label": ".__call__()" }, { @@ -4944,7 +4944,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L25", "id": "service_stocksapi_service_stocksapiservice", - "community": 72, + "community": 222, "norm_label": "stocksapiservice" }, { @@ -4953,7 +4953,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L27", "id": "service_stocksapi_service_initialize", - "community": 72, + "community": 222, "norm_label": "initialize()" }, { @@ -4962,7 +4962,7 @@ "source_file": "main/service/user_service.py", "source_location": "L1", "id": "main_service_user_service_py", - "community": 72, + "community": 488, "norm_label": "user_service.py" }, { @@ -4971,7 +4971,7 @@ "source_file": "main/service/user_service.py", "source_location": "L17", "id": "service_user_service_removeinactivesessions", - "community": 72, + "community": 488, "norm_label": "removeinactivesessions()" }, { @@ -4980,7 +4980,7 @@ "source_file": "main/service/user_service.py", "source_location": "L42", "id": "service_user_service_userservice", - "community": 72, + "community": 488, "norm_label": "userservice" }, { @@ -4989,7 +4989,7 @@ "source_file": "main/service/user_service.py", "source_location": "L44", "id": "service_user_service_initialize", - "community": 72, + "community": 488, "norm_label": "initialize()" }, { @@ -5005,7 +5005,7 @@ "label": "checkDatabaseConnection()", "file_type": "code", "source_file": "main/utils/connectivity.py", - "source_location": "L13", + "source_location": "L12", "id": "utils_connectivity_checkdatabaseconnection", "community": 110, "norm_label": "checkdatabaseconnection()" @@ -5014,7 +5014,7 @@ "label": "checkServiceConnection()", "file_type": "code", "source_file": "main/utils/connectivity.py", - "source_location": "L44", + "source_location": "L41", "id": "utils_connectivity_checkserviceconnection", "community": 59, "norm_label": "checkserviceconnection()" @@ -5025,7 +5025,7 @@ "source_file": "main/utils/errors.py", "source_location": "L1", "id": "main_utils_errors_py", - "community": 33, + "community": 530, "norm_label": "errors.py" }, { @@ -5070,7 +5070,7 @@ "source_file": "main/utils/errors.py", "source_location": "L26", "id": "utils_errors_builderrorresponse", - "community": 33, + "community": 530, "norm_label": "builderrorresponse()" }, { @@ -5079,7 +5079,7 @@ "source_file": "main/utils/errors.py", "source_location": "L36", "id": "utils_errors_httpexceptionhandler", - "community": 33, + "community": 530, "norm_label": "httpexceptionhandler()" }, { @@ -5088,7 +5088,7 @@ "source_file": "main/utils/errors.py", "source_location": "L43", "id": "utils_errors_validationexceptionhandler", - "community": 33, + "community": 530, "norm_label": "validationexceptionhandler()" }, { @@ -5097,7 +5097,7 @@ "source_file": "main/utils/errors.py", "source_location": "L55", "id": "utils_errors_genericexceptionhandler", - "community": 33, + "community": 530, "norm_label": "genericexceptionhandler()" }, { @@ -5115,7 +5115,7 @@ "source_file": "main/utils/http_session.py", "source_location": "L1", "id": "main_utils_http_session_py", - "community": 491, + "community": 522, "norm_label": "http_session.py" }, { @@ -5124,7 +5124,7 @@ "source_file": "main/utils/http_session.py", "source_location": "L8", "id": "utils_http_session_getsession", - "community": 491, + "community": 522, "norm_label": "getsession()" }, { @@ -5232,7 +5232,7 @@ "source_file": "main/utils/roles.py", "source_location": "L1", "id": "main_utils_roles_py", - "community": 112, + "community": 498, "norm_label": "roles.py" }, { @@ -5241,7 +5241,7 @@ "source_file": "main/utils/roles.py", "source_location": "L5", "id": "utils_roles_permission", - "community": 140, + "community": 498, "norm_label": "permission" }, { @@ -5259,7 +5259,7 @@ "source_file": "main/utils/roles.py", "source_location": "L13", "id": "utils_roles_all", - "community": 112, + "community": 131, "norm_label": "all()" }, { @@ -5277,7 +5277,7 @@ "source_file": "main/utils/roles.py", "source_location": "L29", "id": "utils_roles_checkaccess", - "community": 112, + "community": 498, "norm_label": "checkaccess()" }, { @@ -5286,7 +5286,7 @@ "source_file": "main/utils/roles.py", "source_location": "L42", "id": "utils_roles_requirepermission", - "community": 112, + "community": 498, "norm_label": "requirepermission()" }, { @@ -5295,7 +5295,7 @@ "source_file": "main/utils/scheduler.py", "source_location": "L1", "id": "main_utils_scheduler_py", - "community": 72, + "community": 500, "norm_label": "scheduler.py" }, { @@ -5304,7 +5304,7 @@ "source_file": "main/utils/scheduler.py", "source_location": "L10", "id": "utils_scheduler_getsharedscheduler", - "community": 72, + "community": 500, "norm_label": "getsharedscheduler()" }, { @@ -5313,7 +5313,7 @@ "source_file": "main/utils/scheduler.py", "source_location": "L19", "id": "utils_scheduler_registerjob", - "community": 72, + "community": 500, "norm_label": "registerjob()" }, { @@ -5322,7 +5322,7 @@ "source_file": "main/utils/service_manager.py", "source_location": "L1", "id": "main_utils_service_manager_py", - "community": 72, + "community": 222, "norm_label": "service_manager.py" }, { @@ -5331,7 +5331,7 @@ "source_file": "main/utils/service_manager.py", "source_location": "L19", "id": "utils_service_manager_getapp", - "community": 72, + "community": 222, "norm_label": "getapp()" }, { @@ -5340,7 +5340,7 @@ "source_file": "main/utils/service_manager.py", "source_location": "L43", "id": "utils_service_manager_runall", - "community": 72, + "community": 222, "norm_label": "runall()" }, { @@ -5349,7 +5349,7 @@ "source_file": "main/utils/models/loader.py", "source_location": "L1", "id": "main_utils_models_loader_py", - "community": 84, + "community": 541, "norm_label": "loader.py" }, { @@ -5358,7 +5358,7 @@ "source_file": "main/utils/models/loader.py", "source_location": "L12", "id": "models_loader_getembeddingmodel", - "community": 84, + "community": 541, "norm_label": "getembeddingmodel()" }, { @@ -5434,13 +5434,13 @@ "norm_label": "downgrade()" }, { - "label": "Initial migration Revision ID: 25af7ad931e7 Revises: Create Date: 2026-04-03 11", + "label": "Initial migration Revision ID: 25af7ad931e7 Revises: Create Date: 2026-04-0", "file_type": "rationale", "source_file": "migrations/versions/25af7ad931e7_initial_migration.py", "source_location": "L1", "id": "versions_25af7ad931e7_initial_migration_rationale_1", "community": 257, - "norm_label": "initial migration revision id: 25af7ad931e7 revises: create date: 2026-04-03 11" + "norm_label": "initial migration revision id: 25af7ad931e7 revises: create date: 2026-04-0" }, { "label": "4a2f1c9e3b5d_user_sessions.py", @@ -5470,13 +5470,13 @@ "norm_label": "downgrade()" }, { - "label": "User sessions table Revision ID: 4a2f1c9e3b5d Revises: 25af7ad931e7 Create Date", + "label": "User sessions table Revision ID: 4a2f1c9e3b5d Revises: 25af7ad931e7 Create", "file_type": "rationale", "source_file": "migrations/versions/4a2f1c9e3b5d_user_sessions.py", "source_location": "L1", "id": "versions_4a2f1c9e3b5d_user_sessions_rationale_1", "community": 241, - "norm_label": "user sessions table revision id: 4a2f1c9e3b5d revises: 25af7ad931e7 create date" + "norm_label": "user sessions table revision id: 4a2f1c9e3b5d revises: 25af7ad931e7 create" }, { "label": "9f3b339dde20_drop_unused_user_sessions_columns.py", @@ -5506,13 +5506,13 @@ "norm_label": "downgrade()" }, { - "label": "drop unused user sessions columns Revision ID: 9f3b339dde20 Revises: add_access", + "label": "drop unused user sessions columns Revision ID: 9f3b339dde20 Revises: add_acc", "file_type": "rationale", "source_file": "migrations/versions/9f3b339dde20_drop_unused_user_sessions_columns.py", "source_location": "L1", "id": "versions_9f3b339dde20_drop_unused_user_sessions_columns_rationale_1", "community": 198, - "norm_label": "drop unused user sessions columns revision id: 9f3b339dde20 revises: add_access" + "norm_label": "drop unused user sessions columns revision id: 9f3b339dde20 revises: add_acc" }, { "label": "Drop 7 unused columns and their deviceFingerprint index.", @@ -5560,13 +5560,13 @@ "norm_label": "downgrade()" }, { - "label": "Add accessTokenHash, operatingSystem, lastActivityAt to user_sessions Revision", + "label": "Add accessTokenHash, operatingSystem, lastActivityAt to user_sessions Revisio", "file_type": "rationale", "source_file": "migrations/versions/add_access_token_hash.py", "source_location": "L1", "id": "versions_add_access_token_hash_rationale_1", "community": 217, - "norm_label": "add accesstokenhash, operatingsystem, lastactivityat to user_sessions revision" + "norm_label": "add accesstokenhash, operatingsystem, lastactivityat to user_sessions revisio" }, { "label": "Add accessTokenHash, operatingSystem, lastActivityAt, sessionId to user_sessions", @@ -5623,13 +5623,13 @@ "norm_label": "fix_partial()" }, { - "label": "create prometheus_memories with baseScore Revision ID: b1c2d3e4f5a6 Revises: ad", + "label": "create prometheus_memories with baseScore Revision ID: b1c2d3e4f5a6 Revises:", "file_type": "rationale", "source_file": "migrations/versions/b1c2d3e4f5a6_create_prometheus_memories.py", "source_location": "L1", "id": "versions_b1c2d3e4f5a6_create_prometheus_memories_rationale_1", "community": 235, - "norm_label": "create prometheus_memories with basescore revision id: b1c2d3e4f5a6 revises: ad" + "norm_label": "create prometheus_memories with basescore revision id: b1c2d3e4f5a6 revises:" }, { "label": "c2e4f6a8b0c1_drop_embedding_model_version.py", @@ -5659,13 +5659,13 @@ "norm_label": "downgrade()" }, { - "label": "drop embeddingModel and embeddingVersion columns Revision ID: c2e4f6a8b0c1 Revi", + "label": "drop embeddingModel and embeddingVersion columns Revision ID: c2e4f6a8b0c1 R", "file_type": "rationale", "source_file": "migrations/versions/c2e4f6a8b0c1_drop_embedding_model_version.py", "source_location": "L1", "id": "versions_c2e4f6a8b0c1_drop_embedding_model_version_rationale_1", "community": 242, - "norm_label": "drop embeddingmodel and embeddingversion columns revision id: c2e4f6a8b0c1 revi" + "norm_label": "drop embeddingmodel and embeddingversion columns revision id: c2e4f6a8b0c1 r" }, { "label": "d3df3fc5ca72_rename_memory_base_score.py", @@ -5722,13 +5722,13 @@ "norm_label": "downgrade()" }, { - "label": "add prometheus_sandboxes table Revision ID: d3e4f5a6b7c8 Revises: c2e4f6a8b0c1", + "label": "add prometheus_sandboxes table Revision ID: d3e4f5a6b7c8 Revises: c2e4f6a8b0", "file_type": "rationale", "source_file": "migrations/versions/d3e4f5a6b7c8_add_prometheus_sandboxes.py", "source_location": "L1", "id": "versions_d3e4f5a6b7c8_add_prometheus_sandboxes_rationale_1", "community": 243, - "norm_label": "add prometheus_sandboxes table revision id: d3e4f5a6b7c8 revises: c2e4f6a8b0c1" + "norm_label": "add prometheus_sandboxes table revision id: d3e4f5a6b7c8 revises: c2e4f6a8b0" }, { "label": "e4f5a6b7c8d9_fix_fulltext_index_prometheus_memories.py", @@ -5758,13 +5758,13 @@ "norm_label": "downgrade()" }, { - "label": "add missing FULLTEXT index on prometheus_memories Revision ID: e4f5a6b7c8d9 Rev", + "label": "add missing FULLTEXT index on prometheus_memories Revision ID: e4f5a6b7c8d9", "file_type": "rationale", "source_file": "migrations/versions/e4f5a6b7c8d9_fix_fulltext_index_prometheus_memories.py", "source_location": "L1", "id": "versions_e4f5a6b7c8d9_fix_fulltext_index_prometheus_memories_rationale_1", "community": 494, - "norm_label": "add missing fulltext index on prometheus_memories revision id: e4f5a6b7c8d9 rev" + "norm_label": "add missing fulltext index on prometheus_memories revision id: e4f5a6b7c8d9" }, { "label": "e5f6a7b8c9d0_drop_workspace_path_prometheus_sandboxes.py", @@ -5794,13 +5794,13 @@ "norm_label": "downgrade()" }, { - "label": "drop workspacePath column from prometheus_sandboxes Revision ID: e5f6a7b8c9d0 R", + "label": "drop workspacePath column from prometheus_sandboxes Revision ID: e5f6a7b8c9d0", "file_type": "rationale", "source_file": "migrations/versions/e5f6a7b8c9d0_drop_workspace_path_prometheus_sandboxes.py", "source_location": "L1", "id": "versions_e5f6a7b8c9d0_drop_workspace_path_prometheus_sandboxes_rationale_1", "community": 507, - "norm_label": "drop workspacepath column from prometheus_sandboxes revision id: e5f6a7b8c9d0 r" + "norm_label": "drop workspacepath column from prometheus_sandboxes revision id: e5f6a7b8c9d0" }, { "label": "f1a2b3c4d5e6_session_gc_index.py", @@ -5830,13 +5830,13 @@ "norm_label": "downgrade()" }, { - "label": "composite index for session GC sweep (M2) Revision ID: f1a2b3c4d5e6 Revises: e5", + "label": "composite index for session GC sweep (M2) Revision ID: f1a2b3c4d5e6 Revises:", "file_type": "rationale", "source_file": "migrations/versions/f1a2b3c4d5e6_session_gc_index.py", "source_location": "L1", "id": "versions_f1a2b3c4d5e6_session_gc_index_rationale_1", "community": 531, - "norm_label": "composite index for session gc sweep (m2) revision id: f1a2b3c4d5e6 revises: e5" + "norm_label": "composite index for session gc sweep (m2) revision id: f1a2b3c4d5e6 revises:" }, { "label": "AGENTS.md", @@ -8607,7 +8607,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L1", "id": "docs_superpowers_plans_2026_09_04_wallet_management_md", - "community": 503, + "community": 497, "norm_label": "2026-09-04-wallet-management.md" }, { @@ -8616,7 +8616,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L1", "id": "plans_2026_09_04_wallet_management_wallet_management_thoth_iyagba_implementation_plan", - "community": 503, + "community": 497, "norm_label": "wallet management (thoth/iyagba) implementation plan" }, { @@ -8625,7 +8625,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L13", "id": "plans_2026_09_04_wallet_management_global_constraints", - "community": 503, + "community": 497, "norm_label": "global constraints" }, { @@ -8634,7 +8634,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L35", "id": "plans_2026_09_04_wallet_management_file_structure", - "community": 503, + "community": 497, "norm_label": "file structure" }, { @@ -8697,7 +8697,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L166", "id": "plans_2026_09_04_wallet_management_task_2_alembic_migration_for_wallet_tables", - "community": 497, + "community": 132, "norm_label": "task 2: alembic migration for wallet tables" }, { @@ -8706,7 +8706,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L189", "id": "plans_2026_09_04_wallet_management_codeblock_6", - "community": 497, + "community": 132, "norm_label": "code:python (\"\"\"add wallet_holdings and wallet_lots tables)" }, { @@ -8715,7 +8715,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L248", "id": "plans_2026_09_04_wallet_management_codeblock_7", - "community": 497, + "community": 132, "norm_label": "code:python (import main.models.wallet)" }, { @@ -8724,7 +8724,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L262", "id": "plans_2026_09_04_wallet_management_codeblock_8", - "community": 497, + "community": 132, "norm_label": "code:bash (git add migrations/versions/wallet_tables_20260904_add_walle)" }, { @@ -8733,7 +8733,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L269", "id": "plans_2026_09_04_wallet_management_task_3_pure_derivation_math", - "community": 503, + "community": 497, "norm_label": "task 3: pure derivation math" }, { @@ -8742,7 +8742,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L281", "id": "plans_2026_09_04_wallet_management_codeblock_9", - "community": 503, + "community": 497, "norm_label": "code:python (from datetime import date)" }, { @@ -8751,7 +8751,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L325", "id": "plans_2026_09_04_wallet_management_codeblock_10", - "community": 503, + "community": 497, "norm_label": "code:python (from dataclasses import dataclass)" }, { @@ -8760,7 +8760,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L384", "id": "plans_2026_09_04_wallet_management_codeblock_11", - "community": 503, + "community": 497, "norm_label": "code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py )" }, { @@ -9438,6 +9438,303 @@ "community": 94, "norm_label": "spec self-review" }, + { + "label": "ensureFastmcp()", + "file_type": "code", + "source_file": "main/app/prometheus/mcp.py", + "source_location": "L10", + "community": 194, + "norm_label": "ensurefastmcp()", + "id": "prometheus_mcp_ensurefastmcp" + }, + { + "label": "getMatrixAsync()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L43", + "community": 53, + "norm_label": "getmatrixasync()", + "id": "prometheus_memory_getmatrixasync" + }, + { + "label": "invalidateUserAsync()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L55", + "community": 53, + "norm_label": "invalidateuserasync()", + "id": "prometheus_memory_invalidateuserasync" + }, + { + "label": "clearAllAsync()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L59", + "community": 53, + "norm_label": "clearallasync()", + "id": "prometheus_memory_clearallasync" + }, + { + "label": "upsertMemoryAsync()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L244", + "community": 53, + "norm_label": "upsertmemoryasync()", + "id": "prometheus_memory_upsertmemoryasync" + }, + { + "label": "searchAsync()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L333", + "community": 13, + "norm_label": "searchasync()", + "id": "prometheus_memory_searchasync" + }, + { + "label": "deleteMemoryAsync()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L483", + "community": 53, + "norm_label": "deletememoryasync()", + "id": "prometheus_memory_deletememoryasync" + }, + { + "label": "Search user's saved memories, preferences, and past analysis context. Use", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L20", + "community": 152, + "norm_label": "search user's saved memories, preferences, and past analysis context. use", + "id": "prometheus_tools_rationale_20" + }, + { + "label": "Store a memory about the user's preferences, analysis results, or feedback.", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L50", + "community": 152, + "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", + "id": "prometheus_tools_rationale_50" + }, + { + "label": "Execute Python code in an isolated sandbox. Use for quantitative analysis,", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L91", + "community": 101, + "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", + "id": "prometheus_tools_rationale_91" + }, + { + "label": "Read a file from the workspace. Args: path: Path to the file (e.", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L112", + "community": 101, + "norm_label": "read a file from the workspace. args: path: path to the file (e.", + "id": "prometheus_tools_rationale_112" + }, + { + "label": "Write a file to the workspace. Use this to save data files (CSV, JSON, scri", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L126", + "community": 523, + "norm_label": "write a file to the workspace. use this to save data files (csv, json, scri", + "id": "prometheus_tools_rationale_126" + }, + { + "label": "List files in the workspace directory. Args: path: Directory pat", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L142", + "community": 523, + "norm_label": "list files in the workspace directory. args: path: directory pat", + "id": "prometheus_tools_rationale_142" + }, + { + "label": "Get a download link for a workspace file to share with the user. Use this", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L155", + "community": 523, + "norm_label": "get a download link for a workspace file to share with the user. use this", + "id": "prometheus_tools_rationale_155" + }, + { + "label": "Write-Fix()", + "file_type": "code", + "source_file": "ci.ps1", + "source_location": "L48", + "community": 203, + "norm_label": "write-fix()", + "id": "server_ci_write_fix" + }, + { + "label": "saveMessage()", + "file_type": "code", + "source_file": "main/app/prometheus/chat.py", + "source_location": "L52", + "community": 125, + "norm_label": "savemessage()", + "id": "prometheus_chat_savemessage" + }, + { + "label": "saveLoopEvent()", + "file_type": "code", + "source_file": "main/app/prometheus/chat.py", + "source_location": "L76", + "community": 125, + "norm_label": "saveloopevent()", + "id": "prometheus_chat_saveloopevent" + }, + { + "label": "Search user's saved memories, preferences, and past analysis context. Use", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L19", + "community": 152, + "norm_label": "search user's saved memories, preferences, and past analysis context. use", + "id": "prometheus_tools_rationale_19" + }, + { + "label": "Store a memory about the user's preferences, analysis results, or feedback.", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L49", + "community": 152, + "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", + "id": "prometheus_tools_rationale_49" + }, + { + "label": "Execute Python code in an isolated sandbox. Use for quantitative analysis,", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L90", + "community": 101, + "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", + "id": "prometheus_tools_rationale_90" + }, + { + "label": "Read a file from the workspace. Args: path: Path to the file (e.", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L111", + "community": 523, + "norm_label": "read a file from the workspace. args: path: path to the file (e.", + "id": "prometheus_tools_rationale_111" + }, + { + "label": "Write a file to the workspace. Use this to save data files (CSV, JSON, scri", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L125", + "community": 523, + "norm_label": "write a file to the workspace. use this to save data files (csv, json, scri", + "id": "prometheus_tools_rationale_125" + }, + { + "label": "List files in the workspace directory. Args: path: Directory pat", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L141", + "community": 523, + "norm_label": "list files in the workspace directory. args: path: directory pat", + "id": "prometheus_tools_rationale_141" + }, + { + "label": "Get a download link for a workspace file to share with the user. Use this", + "file_type": "rationale", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L154", + "community": 523, + "norm_label": "get a download link for a workspace file to share with the user. use this", + "id": "prometheus_tools_rationale_154" + }, + { + "label": "hashKey()", + "file_type": "code", + "source_file": "main/app/stocks_api/key.py", + "source_location": "L17", + "community": 26, + "norm_label": "hashkey()", + "id": "stocks_api_key_hashkey" + }, + { + "label": "JSONBytesResponse", + "file_type": "code", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L23", + "community": 169, + "norm_label": "jsonbytesresponse", + "id": "controller_stocksapi_controller_jsonbytesresponse" + }, + { + "label": "FastAPIResponse", + "file_type": "code", + "source_file": "", + "source_location": "", + "community": 169, + "norm_label": "fastapiresponse", + "id": "fastapiresponse" + }, + { + "label": ".render()", + "file_type": "code", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L26", + "community": 169, + "norm_label": ".render()", + "id": "controller_stocksapi_controller_jsonbytesresponse_render" + }, + { + "label": "Discover available field names before querying /historical or /fundamental.", + "file_type": "rationale", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L47", + "community": 512, + "norm_label": "discover available field names before querying /historical or /fundamental.", + "id": "controller_stocksapi_controller_rationale_47" + }, + { + "label": "Get year-based historical financial data for Brazilian B3 stocks. Returns", + "file_type": "rationale", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L103", + "community": 197, + "norm_label": "get year-based historical financial data for brazilian b3 stocks. returns", + "id": "controller_stocksapi_controller_rationale_103" + }, + { + "label": "Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret", + "file_type": "rationale", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L168", + "community": 157, + "norm_label": "get point-in-time fundamental/valuation data for brazilian b3 stocks. ret", + "id": "controller_stocksapi_controller_rationale_168" + }, + { + "label": "Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur", + "file_type": "rationale", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L236", + "community": 169, + "norm_label": "get 10-year daily price history (cotation) for brazilian b3 stocks. retur", + "id": "controller_stocksapi_controller_rationale_236" + }, + { + "label": "Get real-time price quotation for a single Brazilian B3 stock. Returns th", + "file_type": "rationale", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L290", + "community": 81, + "norm_label": "get real-time price quotation for a single brazilian b3 stock. returns th", + "id": "controller_stocksapi_controller_rationale_290" + }, { "label": "Load historical/fundamental field names via STOCKS_API /fields endpoint, caching", "file_type": "rationale", @@ -10226,7 +10523,7 @@ "file_type": "rationale", "source_file": "main/service/scraper_service.py", "source_location": "L23", - "community": 72, + "community": 564, "norm_label": "p5: register the scraper cron jobs on the shared scheduler. kept in this", "id": "service_scraper_service_rationale_23" }, @@ -10235,7 +10532,7 @@ "file_type": "code", "source_file": "main/service/user_service.py", "source_location": "L46", - "community": 72, + "community": 488, "norm_label": "registersessioncleanupjobs()", "id": "service_user_service_registersessioncleanupjobs" }, @@ -10244,7 +10541,7 @@ "file_type": "rationale", "source_file": "main/service/user_service.py", "source_location": "L47", - "community": 72, + "community": 488, "norm_label": "p5: register the session-cleanup job on the shared scheduler. kept in thi", "id": "service_user_service_rationale_47" }, @@ -11378,7 +11675,7 @@ "file_type": "code", "source_file": "main/service/prometheus_service.py", "source_location": "L60", - "community": 72, + "community": 500, "norm_label": "registermemorymaintenancejob()", "id": "service_prometheus_service_registermemorymaintenancejob" }, @@ -11387,7 +11684,7 @@ "file_type": "rationale", "source_file": "main/service/prometheus_service.py", "source_location": "L61", - "community": 72, + "community": 500, "norm_label": "p5: register memory maintenance on the shared scheduler. kept in this ser", "id": "service_prometheus_service_rationale_61" }, @@ -11396,7 +11693,7 @@ "file_type": "rationale", "source_file": "main/utils/scheduler.py", "source_location": "L1", - "community": 72, + "community": 500, "norm_label": "p5: single shared backgroundscheduler for all services. replaces the 4 per-serv", "id": "utils_scheduler_rationale_1" }, @@ -11405,7 +11702,7 @@ "file_type": "rationale", "source_file": "main/utils/scheduler.py", "source_location": "L33", - "community": 72, + "community": 500, "norm_label": "return the process-wide scheduler, starting it on first use.", "id": "utils_scheduler_rationale_33" }, @@ -11414,7 +11711,7 @@ "file_type": "rationale", "source_file": "main/utils/scheduler.py", "source_location": "L43", - "community": 72, + "community": 500, "norm_label": "register func on the shared scheduler (replaces any same-id job). trigger i", "id": "utils_scheduler_rationale_43" }, @@ -11603,7 +11900,7 @@ "file_type": "code", "source_file": "main/app/prometheus/compact.py", "source_location": "L222", - "community": 517, + "community": 80, "norm_label": ".__init__()", "id": "prometheus_compact_prometheuscompactor_init" }, @@ -11639,7 +11936,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L92", - "community": 523, + "community": 101, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", "id": "prometheus_tools_rationale_92" }, @@ -11747,7 +12044,7 @@ "file_type": "code", "source_file": "main/utils/service_manager.py", "source_location": "L15", - "community": 72, + "community": 222, "norm_label": "servicemanager", "id": "utils_service_manager_servicemanager" }, @@ -11913,15 +12210,6 @@ "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_135" }, - { - "label": "Get a download link for a workspace file to share with the user. Use this", - "file_type": "rationale", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L145", - "community": 523, - "norm_label": "get a download link for a workspace file to share with the user. use this", - "id": "prometheus_tools_rationale_145" - }, { "label": "_get_client()", "file_type": "code", @@ -12269,7 +12557,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L1", - "community": 63, + "community": 521, "norm_label": "response_cache.py", "id": "main_app_stocks_api_response_cache_py" }, @@ -12278,7 +12566,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L19", - "community": 63, + "community": 521, "norm_label": "responsecache", "id": "stocks_api_response_cache_responsecache" }, @@ -12287,7 +12575,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L20", - "community": 63, + "community": 521, "norm_label": ".__init__()", "id": "stocks_api_response_cache_responsecache_init" }, @@ -12296,7 +12584,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L29", - "community": 63, + "community": 521, "norm_label": ".makekey()", "id": "stocks_api_response_cache_responsecache_makekey" }, @@ -12305,7 +12593,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L34", - "community": 63, + "community": 521, "norm_label": ".get()", "id": "stocks_api_response_cache_responsecache_get" }, @@ -12314,7 +12602,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L51", - "community": 63, + "community": 521, "norm_label": ".set()", "id": "stocks_api_response_cache_responsecache_set" }, @@ -12327,15 +12615,6 @@ "norm_label": "createsession()", "id": "controller_prometheus_controller_createsession" }, - { - "label": "Get year-based historical financial data for Brazilian B3 stocks. Returns", - "file_type": "rationale", - "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L95", - "community": 197, - "norm_label": "get year-based historical financial data for brazilian b3 stocks. returns", - "id": "controller_stocksapi_controller_rationale_95" - }, { "label": "Get point-in-time fundamental/valuation data for Brazilian B3 stocks. Ret", "file_type": "rationale", @@ -12368,7 +12647,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L323", - "community": 26, + "community": 169, "norm_label": "generatekey()", "id": "controller_stocksapi_controller_generatekey" }, @@ -12399,15 +12678,6 @@ "norm_label": "get point-in-time fundamental/valuation data for brazilian b3 stocks. ret", "id": "controller_stocksapi_controller_rationale_155" }, - { - "label": "Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur", - "file_type": "rationale", - "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L228", - "community": 169, - "norm_label": "get 10-year daily price history (cotation) for brazilian b3 stocks. retur", - "id": "controller_stocksapi_controller_rationale_228" - }, { "label": "Get real-time price quotation for a single Brazilian B3 stock. Returns th", "file_type": "rationale", @@ -14213,7 +14483,7 @@ "file_type": "code", "source_file": "main/app/prometheus/tools.py", "source_location": "L104", - "community": 536, + "community": 101, "norm_label": "set_state()", "id": "prometheus_tools_set_state" }, @@ -14222,7 +14492,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L105", - "community": 536, + "community": 101, "norm_label": "store a value in the harness state for this session. use this to save inter", "id": "prometheus_tools_rationale_105" }, @@ -14231,7 +14501,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L123", - "community": 523, + "community": 101, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", "id": "prometheus_tools_rationale_123" }, @@ -14244,15 +14514,6 @@ "norm_label": "read a file from the workspace. args: path: path to the file (e.", "id": "prometheus_tools_rationale_144" }, - { - "label": "Write a file to the workspace. Use this to save data files (CSV, JSON, scri", - "file_type": "rationale", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L155", - "community": 523, - "norm_label": "write a file to the workspace. use this to save data files (csv, json, scri", - "id": "prometheus_tools_rationale_155" - }, { "label": "List files in the workspace directory. Args: path: Directory pat", "file_type": "rationale", @@ -14708,7 +14969,7 @@ "file_type": "code", "source_file": "main/app/prometheus/memory.py", "source_location": "L48", - "community": 112, + "community": 53, "norm_label": "applyupdate()", "id": "prometheus_memory_applyupdate" }, @@ -15644,7 +15905,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L96", - "community": 536, + "community": 101, "norm_label": "store a value in the harness state for this session. use this to save inter", "id": "prometheus_tools_rationale_96" }, @@ -15653,7 +15914,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L114", - "community": 523, + "community": 101, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", "id": "prometheus_tools_rationale_114" }, @@ -16364,7 +16625,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/util.py", "source_location": "L27", - "community": 568, + "community": 73, "norm_label": "_parse_date()", "id": "stocks_api_util_parse_date" }, @@ -16580,7 +16841,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/util.py", "source_location": "L39", - "community": 568, + "community": 73, "norm_label": "parsedatestart()", "id": "stocks_api_util_parsedatestart" }, @@ -16589,7 +16850,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/util.py", "source_location": "L43", - "community": 568, + "community": 73, "norm_label": "parsedateend()", "id": "stocks_api_util_parsedateend" }, @@ -22295,7 +22556,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L23", - "community": 561, + "community": 26, "norm_label": "testatomicquotaincrement", "id": "tests_test_api_key_quota_atomic_testatomicquotaincrement" }, @@ -22322,7 +22583,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L88", - "community": 561, + "community": 26, "norm_label": ".test_concurrent_requests_serialized_at_db_level()", "id": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_concurrent_requests_serialized_at_db_level" }, @@ -22340,7 +22601,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L150", - "community": 561, + "community": 26, "norm_label": ".test_invalid_api_key_returns_zero_rows()", "id": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_invalid_api_key_returns_zero_rows" }, @@ -22439,7 +22700,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L24", - "community": 561, + "community": 26, "norm_label": "test that atomic increment prevents race conditions.", "id": "tests_test_api_key_quota_atomic_rationale_24" }, @@ -22466,7 +22727,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L89", - "community": 561, + "community": 26, "norm_label": "test that concurrent requests are properly serialized at db level. th", "id": "tests_test_api_key_quota_atomic_rationale_89" }, @@ -22484,7 +22745,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L151", - "community": 561, + "community": 26, "norm_label": "test that invalid api key returns zero rows affected.", "id": "tests_test_api_key_quota_atomic_rationale_151" }, @@ -22754,7 +23015,7 @@ "file_type": "code", "source_file": "tests/test_config.py", "source_location": "L1", - "community": 251, + "community": 215, "norm_label": "test_config.py", "id": "tests_test_config_py" }, @@ -23042,7 +23303,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L57", - "community": 16, + "community": 99, "norm_label": "_make_prometheus_client()", "id": "tests_test_controllers_coverage_make_prometheus_client" }, @@ -23114,7 +23375,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L146", - "community": 120, + "community": 498, "norm_label": "testregisterendpoint", "id": "tests_test_controllers_coverage_testregisterendpoint" }, @@ -23159,7 +23420,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L215", - "community": 120, + "community": 498, "norm_label": "testloginendpoint", "id": "tests_test_controllers_coverage_testloginendpoint" }, @@ -23276,7 +23537,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L390", - "community": 120, + "community": 498, "norm_label": "testgooglecallback", "id": "tests_test_controllers_coverage_testgooglecallback" }, @@ -23456,7 +23717,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L668", - "community": 104, + "community": 107, "norm_label": "testgetcurrentsession", "id": "tests_test_controllers_coverage_testgetcurrentsession" }, @@ -23465,7 +23726,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L671", - "community": 104, + "community": 107, "norm_label": ".test_get_current_session_found()", "id": "tests_test_controllers_coverage_testgetcurrentsession_test_get_current_session_found" }, @@ -23474,7 +23735,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L704", - "community": 104, + "community": 107, "norm_label": ".test_get_current_session_not_found()", "id": "tests_test_controllers_coverage_testgetcurrentsession_test_get_current_session_not_found" }, @@ -23555,7 +23816,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L849", - "community": 16, + "community": 99, "norm_label": "testprometheusgetsessions", "id": "tests_test_controllers_coverage_testprometheusgetsessions" }, @@ -23564,7 +23825,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L852", - "community": 16, + "community": 99, "norm_label": ".test_get_sessions()", "id": "tests_test_controllers_coverage_testprometheusgetsessions_test_get_sessions" }, @@ -23573,7 +23834,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L867", - "community": 16, + "community": 99, "norm_label": "testprometheuscreatesession", "id": "tests_test_controllers_coverage_testprometheuscreatesession" }, @@ -23582,7 +23843,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L870", - "community": 16, + "community": 99, "norm_label": ".test_create_session()", "id": "tests_test_controllers_coverage_testprometheuscreatesession_test_create_session" }, @@ -23591,7 +23852,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L881", - "community": 16, + "community": 99, "norm_label": "testprometheusupdatesessiontitle", "id": "tests_test_controllers_coverage_testprometheusupdatesessiontitle" }, @@ -23600,7 +23861,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L884", - "community": 16, + "community": 99, "norm_label": ".test_update_title_success()", "id": "tests_test_controllers_coverage_testprometheusupdatesessiontitle_test_update_title_success" }, @@ -23609,7 +23870,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L895", - "community": 16, + "community": 99, "norm_label": ".test_update_title_not_owner()", "id": "tests_test_controllers_coverage_testprometheusupdatesessiontitle_test_update_title_not_owner" }, @@ -23618,7 +23879,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L904", - "community": 16, + "community": 99, "norm_label": ".test_update_title_not_found()", "id": "tests_test_controllers_coverage_testprometheusupdatesessiontitle_test_update_title_not_found" }, @@ -23681,7 +23942,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1020", - "community": 101, + "community": 16, "norm_label": "testprometheuschat", "id": "tests_test_controllers_coverage_testprometheuschat" }, @@ -23690,7 +23951,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1023", - "community": 101, + "community": 99, "norm_label": ".test_chat_new_session()", "id": "tests_test_controllers_coverage_testprometheuschat_test_chat_new_session" }, @@ -23699,7 +23960,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1042", - "community": 101, + "community": 16, "norm_label": ".test_chat_existing_session_verified()", "id": "tests_test_controllers_coverage_testprometheuschat_test_chat_existing_session_verified" }, @@ -23708,7 +23969,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1085", - "community": 101, + "community": 16, "norm_label": ".test_chat_existing_session_not_owner()", "id": "tests_test_controllers_coverage_testprometheuschat_test_chat_existing_session_not_owner" }, @@ -23762,7 +24023,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1172", - "community": 14, + "community": 503, "norm_label": "teststocksapifundamental", "id": "tests_test_controllers_coverage_teststocksapifundamental" }, @@ -23771,7 +24032,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1175", - "community": 14, + "community": 503, "norm_label": ".test_get_fundamental()", "id": "tests_test_controllers_coverage_teststocksapifundamental_test_get_fundamental" }, @@ -23834,7 +24095,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1249", - "community": 493, + "community": 528, "norm_label": ".test_add_role_already_has_role()", "id": "tests_test_controllers_coverage_testaddroletouser_test_add_role_already_has_role" }, @@ -23879,7 +24140,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1307", - "community": 493, + "community": 528, "norm_label": ".test_get_current_user_session_revoked()", "id": "tests_test_controllers_coverage_testgetcurrentuser_test_get_current_user_session_revoked" }, @@ -23960,7 +24221,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1422", - "community": 114, + "community": 498, "norm_label": "testextracttokenpayloadreraise", "id": "tests_test_controllers_coverage_testextracttokenpayloadreraise" }, @@ -24023,7 +24284,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L58", - "community": 16, + "community": 99, "norm_label": "return (client, app) with prometheus router and mocked deps.", "id": "tests_test_controllers_coverage_rationale_58" }, @@ -24059,7 +24320,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L147", - "community": 120, + "community": 498, "norm_label": "covers lines 44-54, 63, 66-71: register success, valueerror, generic exception.", "id": "tests_test_controllers_coverage_rationale_147" }, @@ -24104,7 +24365,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L216", - "community": 120, + "community": 498, "norm_label": "covers lines 87-93, 102: login success and failure paths.", "id": "tests_test_controllers_coverage_rationale_216" }, @@ -24221,7 +24482,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L391", - "community": 120, + "community": 498, "norm_label": "covers lines 155-156, 158, 160-168, 170-177, 179-184, 186, 190-204: googlecallba", "id": "tests_test_controllers_coverage_rationale_391" }, @@ -24329,7 +24590,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L669", - "community": 104, + "community": 107, "norm_label": "covers lines 100-104, 106: get /user/sessions/current.", "id": "tests_test_controllers_coverage_rationale_669" }, @@ -24338,7 +24599,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L672", - "community": 104, + "community": 107, "norm_label": "covers lines 100-104, 106: session found.", "id": "tests_test_controllers_coverage_rationale_672" }, @@ -24347,7 +24608,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L705", - "community": 104, + "community": 107, "norm_label": "covers line 104: session not found.", "id": "tests_test_controllers_coverage_rationale_705" }, @@ -24419,7 +24680,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L850", - "community": 16, + "community": 99, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_850" }, @@ -24428,7 +24689,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L868", - "community": 16, + "community": 99, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_868" }, @@ -24437,7 +24698,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L882", - "community": 16, + "community": 99, "norm_label": "covers lines 62-63, 65-68: put /prometheus/sessions/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_882" }, @@ -24446,7 +24707,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L885", - "community": 16, + "community": 99, "norm_label": "covers lines 65-68: title updated successfully.", "id": "tests_test_controllers_coverage_rationale_885" }, @@ -24455,7 +24716,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L896", - "community": 16, + "community": 99, "norm_label": "covers lines 62-63: not the session owner.", "id": "tests_test_controllers_coverage_rationale_896" }, @@ -24464,7 +24725,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L905", - "community": 16, + "community": 99, "norm_label": "covers lines 66-67: session not found.", "id": "tests_test_controllers_coverage_rationale_905" }, @@ -24527,7 +24788,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1021", - "community": 101, + "community": 16, "norm_label": "covers lines 109-136: post /prometheus/chat/stream (sse).", "id": "tests_test_controllers_coverage_rationale_1021" }, @@ -24536,7 +24797,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1024", - "community": 101, + "community": 99, "norm_label": "covers lines 118-119: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1024" }, @@ -24545,7 +24806,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1043", - "community": 101, + "community": 16, "norm_label": "covers lines 120-121: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1043" }, @@ -24554,7 +24815,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1086", - "community": 101, + "community": 16, "norm_label": "covers lines 120-121: session ownership check fails.", "id": "tests_test_controllers_coverage_rationale_1086" }, @@ -24590,7 +24851,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1173", - "community": 14, + "community": 503, "norm_label": "covers line 47: get /stocks/fundamental.", "id": "tests_test_controllers_coverage_rationale_1173" }, @@ -24653,7 +24914,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1250", - "community": 493, + "community": 528, "norm_label": "covers line 27: user already has the role.", "id": "tests_test_controllers_coverage_rationale_1250" }, @@ -24689,7 +24950,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1308", - "community": 493, + "community": 528, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1308" }, @@ -24761,7 +25022,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1423", - "community": 114, + "community": 498, "norm_label": "covers line 67: extracttokenpayload re-raises httpexception from verifyaccesstok", "id": "tests_test_controllers_coverage_rationale_1423" }, @@ -25355,7 +25616,7 @@ "file_type": "code", "source_file": "tests/test_error_handlers.py", "source_location": "L25", - "community": 33, + "community": 120, "norm_label": "app()", "id": "tests_test_error_handlers_app" }, @@ -25643,7 +25904,7 @@ "file_type": "code", "source_file": "tests/test_harness_state.py", "source_location": "L1", - "community": 251, + "community": 215, "norm_label": "test_harness_state.py", "id": "tests_test_harness_state_py" }, @@ -25895,7 +26156,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L80", - "community": 25, + "community": 560, "norm_label": "testprometheussessionvalidation", "id": "tests_test_input_validation_testprometheussessionvalidation" }, @@ -25904,7 +26165,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L83", - "community": 25, + "community": 560, "norm_label": ".test_valid_create_session()", "id": "tests_test_input_validation_testprometheussessionvalidation_test_valid_create_session" }, @@ -25913,7 +26174,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L92", - "community": 25, + "community": 560, "norm_label": ".test_empty_title()", "id": "tests_test_input_validation_testprometheussessionvalidation_test_empty_title" }, @@ -25922,7 +26183,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L100", - "community": 25, + "community": 560, "norm_label": ".test_title_too_long()", "id": "tests_test_input_validation_testprometheussessionvalidation_test_title_too_long" }, @@ -25958,7 +26219,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L129", - "community": 25, + "community": 544, "norm_label": "testchatvalidation", "id": "tests_test_input_validation_testchatvalidation" }, @@ -25967,7 +26228,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L132", - "community": 25, + "community": 544, "norm_label": ".test_empty_text()", "id": "tests_test_input_validation_testchatvalidation_test_empty_text" }, @@ -25976,7 +26237,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L140", - "community": 25, + "community": 544, "norm_label": ".test_text_too_long()", "id": "tests_test_input_validation_testchatvalidation_test_text_too_long" }, @@ -25985,7 +26246,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L148", - "community": 25, + "community": 544, "norm_label": ".test_max_length_boundary()", "id": "tests_test_input_validation_testchatvalidation_test_max_length_boundary" }, @@ -26057,7 +26318,7 @@ "file_type": "rationale", "source_file": "tests/test_input_validation.py", "source_location": "L81", - "community": 25, + "community": 560, "norm_label": "post /prometheus/sessions \u2014 validates title via body(...)", "id": "tests_test_input_validation_rationale_81" }, @@ -26075,7 +26336,7 @@ "file_type": "rationale", "source_file": "tests/test_input_validation.py", "source_location": "L130", - "community": 25, + "community": 544, "norm_label": "post /prometheus/chat/stream \u2014 validates query via body(...)", "id": "tests_test_input_validation_rationale_130" }, @@ -26606,7 +26867,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L171", - "community": 54, + "community": 234, "norm_label": ".test_no_memories_does_not_crash()", "id": "tests_test_memory_maintenance_testemptydatabase_test_no_memories_does_not_crash" }, @@ -26732,7 +26993,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L9", - "community": 140, + "community": 571, "norm_label": ".test_basic_user()", "id": "tests_test_memory_manager_testgetmemorylimit_test_basic_user" }, @@ -26750,7 +27011,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L15", - "community": 140, + "community": 575, "norm_label": ".test_admin_user()", "id": "tests_test_memory_manager_testgetmemorylimit_test_admin_user" }, @@ -26786,7 +27047,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L40", - "community": 140, + "community": 576, "norm_label": ".test_unchanged()", "id": "tests_test_memory_manager_testupsertmemory_test_unchanged" }, @@ -26795,7 +27056,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L45", - "community": 140, + "community": 577, "norm_label": ".test_limit_enforcement()", "id": "tests_test_memory_manager_testupsertmemory_test_limit_enforcement" }, @@ -26804,7 +27065,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L59", - "community": 140, + "community": 578, "norm_label": ".test_limit_not_enforced_without_roles()", "id": "tests_test_memory_manager_testupsertmemory_test_limit_not_enforced_without_roles" }, @@ -26813,7 +27074,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L66", - "community": 140, + "community": 579, "norm_label": ".test_upsert_with_embedding()", "id": "tests_test_memory_manager_testupsertmemory_test_upsert_with_embedding" }, @@ -26867,7 +27128,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L102", - "community": 140, + "community": 570, "norm_label": ".test_returns_memories()", "id": "tests_test_memory_manager_testgetusermemories_test_returns_memories" }, @@ -26876,7 +27137,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L109", - "community": 140, + "community": 572, "norm_label": ".test_pagination()", "id": "tests_test_memory_manager_testgetusermemories_test_pagination" }, @@ -26885,7 +27146,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L115", - "community": 140, + "community": 573, "norm_label": ".test_excludes_archived()", "id": "tests_test_memory_manager_testgetusermemories_test_excludes_archived" }, @@ -26903,7 +27164,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L126", - "community": 140, + "community": 574, "norm_label": ".test_soft_delete()", "id": "tests_test_memory_manager_testdeletememory_test_soft_delete" }, @@ -27074,7 +27335,7 @@ "file_type": "code", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L79", - "community": 488, + "community": 487, "norm_label": "testmakechatincludesmemorytools", "id": "tests_test_memory_tools_wiring_testmakechatincludesmemorytools" }, @@ -27155,7 +27416,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L80", - "community": 488, + "community": 487, "norm_label": "makechat must include memory_tools alongside mcp sessions.", "id": "tests_test_memory_tools_wiring_rationale_80" }, @@ -27281,7 +27542,7 @@ "file_type": "code", "source_file": "tests/test_models.py", "source_location": "L1", - "community": 61, + "community": 125, "norm_label": "test_models.py", "id": "tests_test_models_py" }, @@ -27497,7 +27758,7 @@ "file_type": "code", "source_file": "tests/test_models.py", "source_location": "L162", - "community": 61, + "community": 125, "norm_label": "testprometheussessionmodel", "id": "tests_test_models_testprometheussessionmodel" }, @@ -27506,7 +27767,7 @@ "file_type": "code", "source_file": "tests/test_models.py", "source_location": "L163", - "community": 61, + "community": 125, "norm_label": ".test_create_session()", "id": "tests_test_models_testprometheussessionmodel_test_create_session" }, @@ -27515,7 +27776,7 @@ "file_type": "code", "source_file": "tests/test_models.py", "source_location": "L172", - "community": 61, + "community": 125, "norm_label": ".test_default_history()", "id": "tests_test_models_testprometheussessionmodel_test_default_history" }, @@ -28568,7 +28829,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L44", - "community": 132, + "community": 231, "norm_label": "testmemorytoolfunctions", "id": "tests_test_prometheus_tools_testmemorytoolfunctions" }, @@ -28577,7 +28838,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L45", - "community": 132, + "community": 231, "norm_label": ".test_search_memory_has_docstring()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_search_memory_has_docstring" }, @@ -28586,7 +28847,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L49", - "community": 132, + "community": 231, "norm_label": ".test_save_memory_has_docstring()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_save_memory_has_docstring" }, @@ -28595,7 +28856,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L53", - "community": 132, + "community": 231, "norm_label": ".test_search_memory_signature()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_search_memory_signature" }, @@ -28604,7 +28865,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L59", - "community": 132, + "community": 231, "norm_label": ".test_save_memory_signature()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_save_memory_signature" }, @@ -28613,7 +28874,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L66", - "community": 132, + "community": 231, "norm_label": ".test_search_memory_has_type_hints()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_search_memory_has_type_hints" }, @@ -28622,7 +28883,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L71", - "community": 132, + "community": 231, "norm_label": ".test_save_memory_has_type_hints()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_save_memory_has_type_hints" }, @@ -28631,7 +28892,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L77", - "community": 132, + "community": 231, "norm_label": ".test_memory_tools_is_list_of_callables()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_memory_tools_is_list_of_callables" }, @@ -28640,7 +28901,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L83", - "community": 132, + "community": 231, "norm_label": ".test_memory_tool_names_unchanged()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_memory_tool_names_unchanged" }, @@ -29189,7 +29450,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L1", - "community": 251, + "community": 67, "norm_label": "test_roles.py", "id": "tests_test_roles_py" }, @@ -29198,7 +29459,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L4", - "community": 251, + "community": 67, "norm_label": "testpermission", "id": "tests_test_roles_testpermission" }, @@ -29207,7 +29468,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L5", - "community": 251, + "community": 67, "norm_label": ".test_permission_enum_values()", "id": "tests_test_roles_testpermission_test_permission_enum_values" }, @@ -29216,7 +29477,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L10", - "community": 251, + "community": 67, "norm_label": ".test_permission_all_includes_all()", "id": "tests_test_roles_testpermission_test_permission_all_includes_all" }, @@ -29963,7 +30224,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L6", - "community": 263, + "community": 49, "norm_label": "testsandboxtooldefinitions", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions" }, @@ -29972,7 +30233,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L7", - "community": 263, + "community": 49, "norm_label": ".test_execute_code_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_execute_code_in_registry" }, @@ -29981,7 +30242,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L10", - "community": 263, + "community": 49, "norm_label": ".test_read_file_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_read_file_in_registry" }, @@ -29990,7 +30251,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L13", - "community": 263, + "community": 49, "norm_label": ".test_write_file_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_write_file_in_registry" }, @@ -29999,7 +30260,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L16", - "community": 263, + "community": 49, "norm_label": ".test_list_files_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_list_files_in_registry" }, @@ -30008,7 +30269,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L19", - "community": 263, + "community": 49, "norm_label": ".test_execute_code_has_docstring()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_execute_code_has_docstring" }, @@ -30593,7 +30854,7 @@ "file_type": "code", "source_file": "tests/test_state_tools.py", "source_location": "L97", - "community": 536, + "community": 101, "norm_label": "test_set_state_no_state()", "id": "tests_test_state_tools_test_set_state_no_state" }, @@ -30890,7 +31151,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L152", - "community": 490, + "community": 567, "norm_label": "testverifyapikey", "id": "tests_test_stocks_api_coverage_testverifyapikey" }, @@ -30998,7 +31259,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L287", - "community": 567, + "community": 565, "norm_label": "testcreatekey", "id": "tests_test_stocks_api_coverage_testcreatekey" }, @@ -31007,7 +31268,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L291", - "community": 26, + "community": 567, "norm_label": "test_create_key_new_user()", "id": "tests_test_stocks_api_coverage_test_create_key_new_user" }, @@ -31025,7 +31286,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L323", - "community": 26, + "community": 567, "norm_label": "test_create_key_exception_rollback()", "id": "tests_test_stocks_api_coverage_test_create_key_exception_rollback" }, @@ -31340,7 +31601,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L617", - "community": 215, + "community": 263, "norm_label": ".test_historical_no_historical_fields()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_no_historical_fields" }, @@ -31502,7 +31763,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L766", - "community": 107, + "community": 137, "norm_label": ".test_fundamental_with_invalid_date()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_invalid_date" }, @@ -31664,7 +31925,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L986", - "community": 10, + "community": 3, "norm_label": "._make_manager()", "id": "tests_test_stocks_api_coverage_testquerycotations_make_manager" }, @@ -31808,7 +32069,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1139", - "community": 130, + "community": 10, "norm_label": ".test_cotations_http_route()", "id": "tests_test_stocks_api_coverage_testquerycotations_test_cotations_http_route" }, @@ -31826,7 +32087,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1169", - "community": 3, + "community": 10, "norm_label": "._make_manager()", "id": "tests_test_stocks_api_coverage_testquerylivecotation_make_manager" }, @@ -31898,7 +32159,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1265", - "community": 222, + "community": 112, "norm_label": ".test_http_route_search_required()", "id": "tests_test_stocks_api_coverage_testquerylivecotation_test_http_route_search_required" }, @@ -31934,7 +32195,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1315", - "community": 234, + "community": 112, "norm_label": ".test_cotations_search_required()", "id": "tests_test_stocks_api_coverage_testquerylivecotation_test_cotations_search_required" }, @@ -31970,7 +32231,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L153", - "community": 490, + "community": 567, "norm_label": "tests covering key.py lines 15-40. uses asyncio.run() since pytest-asyncio", "id": "tests_test_stocks_api_coverage_rationale_153" }, @@ -32051,7 +32312,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L288", - "community": 567, + "community": 565, "norm_label": "tests covering key.py lines 48-66.", "id": "tests_test_stocks_api_coverage_rationale_288" }, @@ -32168,7 +32429,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L618", - "community": 215, + "community": 263, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_618" }, @@ -32213,7 +32474,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L694", - "community": 215, + "community": 263, "norm_label": "multiple search terms, all found in tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_694" }, @@ -32240,7 +32501,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L767", - "community": 107, + "community": 137, "norm_label": "invalid date -> inner 400 passes through (not wrapped as 500).", "id": "tests_test_stocks_api_coverage_rationale_767" }, @@ -32267,7 +32528,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L842", - "community": 39, + "community": 137, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_842" }, @@ -32375,7 +32636,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1140", - "community": 130, + "community": 10, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1140" }, @@ -32393,7 +32654,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1266", - "community": 222, + "community": 112, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1266" }, @@ -32402,7 +32663,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1316", - "community": 234, + "community": 112, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1316" }, @@ -33644,7 +33905,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L1", - "community": 54, + "community": 234, "norm_label": "test_type_aware_decay.py", "id": "tests_test_type_aware_decay_py" }, @@ -33653,7 +33914,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L11", - "community": 54, + "community": 234, "norm_label": "_create()", "id": "tests_test_type_aware_decay_create" }, @@ -33662,7 +33923,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L29", - "community": 54, + "community": 234, "norm_label": "testtypeawaredecay", "id": "tests_test_type_aware_decay_testtypeawaredecay" }, @@ -33671,7 +33932,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L30", - "community": 54, + "community": 234, "norm_label": ".test_preference_decays_slowly()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_preference_decays_slowly" }, @@ -33680,7 +33941,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L36", - "community": 54, + "community": 234, "norm_label": ".test_context_decays_fast()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_context_decays_fast" }, @@ -33689,7 +33950,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L42", - "community": 54, + "community": 234, "norm_label": ".test_analysis_decays_normally()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_analysis_decays_normally" }, @@ -33698,7 +33959,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L48", - "community": 54, + "community": 234, "norm_label": ".test_feedback_decays_medium()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_feedback_decays_medium" }, @@ -33707,7 +33968,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L54", - "community": 54, + "community": 234, "norm_label": ".test_unknown_type_uses_default()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_unknown_type_uses_default" }, @@ -33716,7 +33977,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L60", - "community": 54, + "community": 234, "norm_label": ".test_mixed_types_all_correct()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_mixed_types_all_correct" }, @@ -33725,7 +33986,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L76", - "community": 54, + "community": 234, "norm_label": ".test_preference_survives_longer()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_preference_survives_longer" }, @@ -33734,7 +33995,7 @@ "file_type": "rationale", "source_file": "tests/test_type_aware_decay.py", "source_location": "L77", - "community": 54, + "community": 234, "norm_label": "after 10 cycles, preference (0.99^10) > context (0.90^10).", "id": "tests_test_type_aware_decay_rationale_77" }, @@ -33743,7 +34004,7 @@ "file_type": "code", "source_file": "tests/test_user_deps.py", "source_location": "L1", - "community": 181, + "community": 529, "norm_label": "test_user_deps.py", "id": "tests_test_user_deps_py" }, @@ -33932,7 +34193,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L38", - "community": 112, + "community": 131, "norm_label": "testcontenthash", "id": "tests_test_vector_utils_testcontenthash" }, @@ -33941,7 +34202,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L39", - "community": 112, + "community": 131, "norm_label": ".test_deterministic()", "id": "tests_test_vector_utils_testcontenthash_test_deterministic" }, @@ -33950,7 +34211,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L42", - "community": 112, + "community": 131, "norm_label": ".test_different_inputs()", "id": "tests_test_vector_utils_testcontenthash_test_different_inputs" }, @@ -33959,7 +34220,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L45", - "community": 112, + "community": 131, "norm_label": ".test_hex_format()", "id": "tests_test_vector_utils_testcontenthash_test_hex_format" }, @@ -35291,7 +35552,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1042", - "community": 101, + "community": 16, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1042" }, @@ -35300,7 +35561,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1083", - "community": 101, + "community": 16, "norm_label": "covers lines 114-115: session ownership check fails.", "id": "tests_test_controllers_coverage_rationale_1083" }, @@ -35336,7 +35597,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1166", - "community": 14, + "community": 503, "norm_label": "covers line 47: get /stocks/fundamental.", "id": "tests_test_controllers_coverage_rationale_1166" }, @@ -35399,7 +35660,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1243", - "community": 493, + "community": 528, "norm_label": "covers line 27: user already has the role.", "id": "tests_test_controllers_coverage_rationale_1243" }, @@ -35426,7 +35687,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1301", - "community": 493, + "community": 528, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1301" }, @@ -35637,24 +35898,6 @@ "norm_label": "retrieve values from the harness state. use this to recall intermediate results,", "id": "prometheus_tools_rationale_79" }, - { - "label": "Store a value in the harness state for this session. Use this to save inter", - "file_type": "rationale", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L94", - "community": 536, - "norm_label": "store a value in the harness state for this session. use this to save inter", - "id": "prometheus_tools_rationale_94" - }, - { - "label": "Execute Python code in an isolated sandbox. Use for quantitative analysis,", - "file_type": "rationale", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L112", - "community": 523, - "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", - "id": "prometheus_tools_rationale_112" - }, { "label": "Read a file from the workspace. Args: path: Path to the file (e.", "file_type": "rationale", @@ -35664,15 +35907,6 @@ "norm_label": "read a file from the workspace. args: path: path to the file (e.", "id": "prometheus_tools_rationale_147" }, - { - "label": "Write a file to the workspace. Use this to save data files (CSV, JSON, scri", - "file_type": "rationale", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L158", - "community": 523, - "norm_label": "write a file to the workspace. use this to save data files (csv, json, scri", - "id": "prometheus_tools_rationale_158" - }, { "label": "List files in the workspace directory. Args: path: Directory pat", "file_type": "rationale", @@ -36182,7 +36416,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L7", - "community": 137, + "community": 8, "norm_label": "testagentsandboxintegration", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration" }, @@ -36191,7 +36425,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L8", - "community": 137, + "community": 8, "norm_label": ".test_build_system_prompt_includes_sandbox_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_includes_sandbox_instructions" }, @@ -36200,7 +36434,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L14", - "community": 137, + "community": 8, "norm_label": ".test_build_system_prompt_includes_state_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_includes_state_instructions" }, @@ -36209,7 +36443,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L19", - "community": 137, + "community": 8, "norm_label": ".test_build_system_prompt_with_state()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_with_state" }, @@ -36326,7 +36560,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L93", - "community": 536, + "community": 101, "norm_label": "store a value in the harness state for this session. use this to save inter", "id": "prometheus_tools_rationale_93" }, @@ -38522,7 +38756,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L119", - "community": 100, + "community": 101, "norm_label": "test_set_state_no_state_returns_error()", "id": "tests_test_prometheus_tools_test_set_state_no_state_returns_error" }, @@ -38702,7 +38936,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L109", - "community": 523, + "community": 101, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", "id": "prometheus_tools_rationale_109" }, @@ -38738,7 +38972,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L9", - "community": 137, + "community": 8, "norm_label": ".test_build_system_prompt_no_state()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_no_state" }, @@ -38747,7 +38981,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L20", - "community": 137, + "community": 8, "norm_label": ".test_build_system_prompt_empty_state()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_empty_state" }, @@ -38756,7 +38990,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L25", - "community": 137, + "community": 8, "norm_label": ".test_system_prompt_includes_state_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_system_prompt_includes_state_instructions" }, @@ -38765,7 +38999,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L30", - "community": 137, + "community": 8, "norm_label": ".test_system_prompt_includes_sandbox_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_system_prompt_includes_sandbox_instructions" }, @@ -38774,7 +39008,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L34", - "community": 137, + "community": 8, "norm_label": ".test_system_prompt_includes_cache_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_system_prompt_includes_cache_instructions" }, @@ -38783,7 +39017,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L38", - "community": 137, + "community": 8, "norm_label": ".test_makechat_uses_tool_registry()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_makechat_uses_tool_registry" }, @@ -38819,7 +39053,7 @@ "file_type": "code", "source_file": "tests/test_cache.py", "source_location": "L1", - "community": 95, + "community": 135, "norm_label": "test_cache.py", "id": "tests_test_cache_py" }, @@ -38828,7 +39062,7 @@ "file_type": "code", "source_file": "tests/test_cache.py", "source_location": "L11", - "community": 95, + "community": 135, "norm_label": "cache()", "id": "tests_test_cache_cache" }, @@ -38945,7 +39179,7 @@ "file_type": "rationale", "source_file": "tests/test_cache.py", "source_location": "L1", - "community": 95, + "community": 135, "norm_label": "tests for resultcache.", "id": "tests_test_cache_rationale_1" }, @@ -38954,7 +39188,7 @@ "file_type": "code", "source_file": "tests/test_config_sandbox.py", "source_location": "L1", - "community": 251, + "community": 215, "norm_label": "test_config_sandbox.py", "id": "tests_test_config_sandbox_py" }, @@ -38963,7 +39197,7 @@ "file_type": "code", "source_file": "tests/test_config_sandbox.py", "source_location": "L5", - "community": 102, + "community": 215, "norm_label": "testsandboxconfig", "id": "tests_test_config_sandbox_testsandboxconfig" }, @@ -38972,7 +39206,7 @@ "file_type": "code", "source_file": "tests/test_config_sandbox.py", "source_location": "L6", - "community": 102, + "community": 215, "norm_label": ".test_sandbox_defaults()", "id": "tests_test_config_sandbox_testsandboxconfig_test_sandbox_defaults" }, @@ -38981,7 +39215,7 @@ "file_type": "code", "source_file": "tests/test_config_sandbox.py", "source_location": "L13", - "community": 102, + "community": 215, "norm_label": ".test_sandbox_fields_exist()", "id": "tests_test_config_sandbox_testsandboxconfig_test_sandbox_fields_exist" }, @@ -38990,7 +39224,7 @@ "file_type": "code", "source_file": "tests/test_config_sandbox.py", "source_location": "L21", - "community": 102, + "community": 215, "norm_label": ".test_sandbox_types()", "id": "tests_test_config_sandbox_testsandboxconfig_test_sandbox_types" }, @@ -39251,7 +39485,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L12", - "community": 263, + "community": 49, "norm_label": ".test_read_sandbox_file_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_read_sandbox_file_in_registry" }, @@ -39260,7 +39494,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L15", - "community": 263, + "community": 49, "norm_label": ".test_check_cache_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_check_cache_in_registry" }, @@ -39269,7 +39503,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L23", - "community": 263, + "community": 49, "norm_label": ".test_read_sandbox_file_has_docstring()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_read_sandbox_file_has_docstring" }, @@ -39278,7 +39512,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L28", - "community": 263, + "community": 49, "norm_label": ".test_check_cache_has_docstring()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_check_cache_has_docstring" }, @@ -39408,15 +39642,6 @@ "norm_label": ".__post_init__()", "id": "prometheus_context_toolcontext_post_init" }, - { - "label": "Read a file from the sandbox filesystem. Args: path: Absolute pa", - "file_type": "rationale", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L142", - "community": 523, - "norm_label": "read a file from the sandbox filesystem. args: path: absolute pa", - "id": "prometheus_tools_rationale_142" - }, { "label": "test_context.py", "file_type": "code", @@ -40020,15 +40245,6 @@ "norm_label": "retrieve values from the harness state. use this to recall intermediate results,", "id": "prometheus_tools_rationale_77" }, - { - "label": "Store a value in the harness state for this session. Use this to save interm", - "file_type": "rationale", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L91", - "community": 536, - "norm_label": "store a value in the harness state for this session. use this to save interm", - "id": "prometheus_tools_rationale_91" - }, { "label": "Phase 4: ToolContext (Replace God Function)", "file_type": "document", @@ -40286,7 +40502,7 @@ "file_type": "code", "source_file": "main/app/prometheus/tools.py", "source_location": "L46", - "community": 84, + "community": 541, "norm_label": "executememorytool()", "id": "prometheus_tools_executememorytool" }, @@ -40430,7 +40646,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L52", - "community": 488, + "community": 487, "norm_label": "makechat must include memory_tools alongside mcp sessions.", "id": "tests_test_memory_tools_wiring_rationale_52" }, @@ -40466,7 +40682,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L57", - "community": 488, + "community": 487, "norm_label": "makechat must include memory_tools alongside mcp sessions.", "id": "tests_test_memory_tools_wiring_rationale_57" }, @@ -40592,7 +40808,7 @@ "file_type": "code", "source_file": "main/utils/models/loader.py", "source_location": "L23", - "community": 84, + "community": 541, "norm_label": "embed()", "id": "models_loader_embed" }, @@ -40772,7 +40988,7 @@ "file_type": "code", "source_file": "main/utils/models/loader.py", "source_location": "L11", - "community": 84, + "community": 541, "norm_label": "_downloadmodel()", "id": "models_loader_downloadmodel" }, @@ -40916,7 +41132,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1302", - "community": 493, + "community": 528, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1302" }, @@ -40988,7 +41204,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1417", - "community": 114, + "community": 498, "norm_label": "covers line 67: extracttokenpayload re-raises httpexception from verifyaccesstok", "id": "tests_test_controllers_coverage_rationale_1417" }, @@ -41231,7 +41447,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L56", - "community": 488, + "community": 487, "norm_label": "makechat must include memory_tools alongside mcp sessions.", "id": "tests_test_memory_tools_wiring_rationale_56" }, @@ -41267,7 +41483,7 @@ "file_type": "code", "source_file": "main/utils/vector.py", "source_location": "L20", - "community": 112, + "community": 131, "norm_label": "contenthash()", "id": "utils_vector_contenthash" }, @@ -41564,7 +41780,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L48", - "community": 488, + "community": 487, "norm_label": "makechat must include memory_tools alongside mcp sessions.", "id": "tests_test_memory_tools_wiring_rationale_48" }, @@ -41663,7 +41879,7 @@ "file_type": "code", "source_file": "main/controller/prometheus_controller.py", "source_location": "L177", - "community": 84, + "community": 541, "norm_label": "creatememory()", "id": "controller_prometheus_controller_creatememory" }, @@ -41681,7 +41897,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L1", - "community": 99, + "community": 86, "norm_label": "test_memory_controller.py", "id": "tests_test_memory_controller_py" }, @@ -41690,7 +41906,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L10", - "community": 86, + "community": 130, "norm_label": "testmemorycontrollerroutes", "id": "tests_test_memory_controller_testmemorycontrollerroutes" }, @@ -41699,7 +41915,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L11", - "community": 86, + "community": 130, "norm_label": ".test_get_memories_endpoint_exists()", "id": "tests_test_memory_controller_testmemorycontrollerroutes_test_get_memories_endpoint_exists" }, @@ -41708,7 +41924,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L15", - "community": 86, + "community": 130, "norm_label": ".test_post_memories_endpoint_exists()", "id": "tests_test_memory_controller_testmemorycontrollerroutes_test_post_memories_endpoint_exists" }, @@ -41717,7 +41933,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L19", - "community": 86, + "community": 130, "norm_label": ".test_delete_memories_endpoint_exists()", "id": "tests_test_memory_controller_testmemorycontrollerroutes_test_delete_memories_endpoint_exists" }, @@ -41726,7 +41942,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L23", - "community": 86, + "community": 130, "norm_label": ".test_get_memories_rejects_unauthenticated()", "id": "tests_test_memory_controller_testmemorycontrollerroutes_test_get_memories_rejects_unauthenticated" }, @@ -41735,7 +41951,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L38", - "community": 86, + "community": 130, "norm_label": ".test_get_memories_rejects_basic_user()", "id": "tests_test_memory_controller_testmemorycontrollerroutes_test_get_memories_rejects_basic_user" }, @@ -41744,7 +41960,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L65", - "community": 99, + "community": 86, "norm_label": "testmemoryendpointsintegration", "id": "tests_test_memory_controller_testmemoryendpointsintegration" }, @@ -41753,7 +41969,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L67", - "community": 99, + "community": 86, "norm_label": "test_get_memories_calls_manager()", "id": "tests_test_memory_controller_test_get_memories_calls_manager" }, @@ -41762,7 +41978,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L90", - "community": 99, + "community": 86, "norm_label": "test_create_memory_calls_manager()", "id": "tests_test_memory_controller_test_create_memory_calls_manager" }, @@ -41771,7 +41987,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L111", - "community": 99, + "community": 86, "norm_label": "test_create_memory_limit_reached()", "id": "tests_test_memory_controller_test_create_memory_limit_reached" }, @@ -41780,7 +41996,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L126", - "community": 99, + "community": 86, "norm_label": "test_delete_memory_calls_manager()", "id": "tests_test_memory_controller_test_delete_memory_calls_manager" }, @@ -41789,7 +42005,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L135", - "community": 99, + "community": 86, "norm_label": "test_delete_memory_not_found()", "id": "tests_test_memory_controller_test_delete_memory_not_found" }, @@ -41798,7 +42014,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L141", - "community": 99, + "community": 86, "norm_label": ".test_create_memory_missing_key()", "id": "tests_test_memory_controller_testmemoryendpointsintegration_test_create_memory_missing_key" }, @@ -41807,7 +42023,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L145", - "community": 99, + "community": 86, "norm_label": ".test_create_memory_missing_value()", "id": "tests_test_memory_controller_testmemoryendpointsintegration_test_create_memory_missing_value" }, @@ -41834,7 +42050,7 @@ "file_type": "rationale", "source_file": "main/utils/vector.py", "source_location": "L19", - "community": 112, + "community": 131, "norm_label": "md5 hash for change detection.", "id": "utils_vector_rationale_19" }, @@ -42347,7 +42563,7 @@ "file_type": "code", "source_file": "main/app/prometheus/memory.py", "source_location": "L138", - "community": 53, + "community": 13, "norm_label": "_fulltext_search()", "id": "prometheus_memory_fulltext_search" }, @@ -42473,7 +42689,7 @@ "file_type": "code", "source_file": "main/controller/prometheus_controller.py", "source_location": "L177", - "community": 84, + "community": 541, "norm_label": "create_memory()", "id": "controller_prometheus_controller_create_memory" }, @@ -42527,7 +42743,7 @@ "file_type": "code", "source_file": "main/utils/vector.py", "source_location": "L41", - "community": 112, + "community": 131, "norm_label": "content_hash()", "id": "utils_vector_content_hash" }, @@ -42563,7 +42779,7 @@ "file_type": "rationale", "source_file": "main/utils/vector.py", "source_location": "L42", - "community": 112, + "community": 131, "norm_label": "md5 hash for change detection.", "id": "utils_vector_rationale_42" }, @@ -42572,7 +42788,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L11", - "community": 86, + "community": 130, "norm_label": "verify memory endpoints exist and are wired correctly.", "id": "tests_test_memory_controller_rationale_11" }, @@ -42581,7 +42797,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L14", - "community": 86, + "community": 130, "norm_label": "get /prometheus/memories exists.", "id": "tests_test_memory_controller_rationale_14" }, @@ -42590,7 +42806,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L20", - "community": 86, + "community": 130, "norm_label": "post /prometheus/memories exists.", "id": "tests_test_memory_controller_rationale_20" }, @@ -42599,7 +42815,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L25", - "community": 86, + "community": 130, "norm_label": "delete /prometheus/memories/{id} exists.", "id": "tests_test_memory_controller_rationale_25" }, @@ -42608,7 +42824,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L30", - "community": 86, + "community": 130, "norm_label": "get /memories requires authentication.", "id": "tests_test_memory_controller_rationale_30" }, @@ -42617,7 +42833,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L47", - "community": 86, + "community": 130, "norm_label": "get /memories requires use_prometheus (basic user role denied).", "id": "tests_test_memory_controller_rationale_47" }, @@ -42626,7 +42842,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L75", - "community": 99, + "community": 86, "norm_label": "full integration tests using mocked memorymanager.", "id": "tests_test_memory_controller_rationale_75" }, @@ -42680,7 +42896,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L141", - "community": 99, + "community": 86, "norm_label": "post /memories rejects missing key.", "id": "tests_test_memory_controller_rationale_141" }, @@ -42689,7 +42905,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L146", - "community": 99, + "community": 86, "norm_label": "post /memories rejects missing value.", "id": "tests_test_memory_controller_rationale_146" }, @@ -42698,7 +42914,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L11", - "community": 140, + "community": 571, "norm_label": "non-extended role gets basic limit.", "id": "tests_test_memory_manager_rationale_11" }, @@ -42716,7 +42932,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L19", - "community": 140, + "community": 575, "norm_label": "admin gets extended limit (has all permissions).", "id": "tests_test_memory_manager_rationale_19" }, @@ -42743,7 +42959,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L43", - "community": 140, + "community": 576, "norm_label": "returns unchanged when value is identical.", "id": "tests_test_memory_manager_rationale_43" }, @@ -42752,7 +42968,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L49", - "community": 140, + "community": 577, "norm_label": "rejects new memory when limit reached.", "id": "tests_test_memory_manager_rationale_49" }, @@ -42761,7 +42977,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L61", - "community": 140, + "community": 578, "norm_label": "no role check when user_roles not provided.", "id": "tests_test_memory_manager_rationale_61" }, @@ -42770,7 +42986,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L69", - "community": 140, + "community": 579, "norm_label": "stores embedding alongside memory.", "id": "tests_test_memory_manager_rationale_69" }, @@ -42797,7 +43013,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L107", - "community": 140, + "community": 570, "norm_label": "returns paginated memories.", "id": "tests_test_memory_manager_rationale_107" }, @@ -42806,7 +43022,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L115", - "community": 140, + "community": 572, "norm_label": "offset and limit work.", "id": "tests_test_memory_manager_rationale_115" }, @@ -42815,7 +43031,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L122", - "community": 140, + "community": 573, "norm_label": "archived memories excluded.", "id": "tests_test_memory_manager_rationale_122" }, @@ -42824,7 +43040,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L135", - "community": 140, + "community": 574, "norm_label": "soft-deletes a memory.", "id": "tests_test_memory_manager_rationale_135" }, @@ -43058,7 +43274,7 @@ "file_type": "rationale", "source_file": "tests/test_vector_utils.py", "source_location": "L101", - "community": 112, + "community": 131, "norm_label": "same input \u2192 same hash.", "id": "tests_test_vector_utils_rationale_101" }, @@ -43067,7 +43283,7 @@ "file_type": "rationale", "source_file": "tests/test_vector_utils.py", "source_location": "L105", - "community": 112, + "community": 131, "norm_label": "different inputs \u2192 different hashes.", "id": "tests_test_vector_utils_rationale_105" }, @@ -43076,7 +43292,7 @@ "file_type": "rationale", "source_file": "tests/test_vector_utils.py", "source_location": "L109", - "community": 112, + "community": 131, "norm_label": "returns 32-char hex string.", "id": "tests_test_vector_utils_rationale_109" }, @@ -43949,7 +44165,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L1", - "community": 29, + "community": 563, "norm_label": "generation.py", "id": "main_app_prometheus_generation_py" }, @@ -43985,7 +44201,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L36", - "community": 29, + "community": 563, "norm_label": ".executeworkflow()", "id": "prometheus_generation_prometheusgenerator_executeworkflow" }, @@ -44147,7 +44363,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L665", - "community": 104, + "community": 107, "norm_label": "covers lines 100-104, 106: get /user/sessions/current.", "id": "tests_test_controllers_coverage_rationale_665" }, @@ -44156,7 +44372,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L668", - "community": 104, + "community": 107, "norm_label": "covers lines 100-104, 106: session found.", "id": "tests_test_controllers_coverage_rationale_668" }, @@ -44165,7 +44381,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L701", - "community": 104, + "community": 107, "norm_label": "covers line 104: session not found.", "id": "tests_test_controllers_coverage_rationale_701" }, @@ -44237,7 +44453,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L846", - "community": 16, + "community": 99, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_846" }, @@ -44246,7 +44462,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L864", - "community": 16, + "community": 99, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_864" }, @@ -44255,7 +44471,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L878", - "community": 16, + "community": 99, "norm_label": "covers lines 62-63, 65-68: put /prometheus/sessions/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_878" }, @@ -44264,7 +44480,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L881", - "community": 16, + "community": 99, "norm_label": "covers lines 65-68: title updated successfully.", "id": "tests_test_controllers_coverage_rationale_881" }, @@ -44273,7 +44489,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L892", - "community": 16, + "community": 99, "norm_label": "covers lines 62-63: not the session owner.", "id": "tests_test_controllers_coverage_rationale_892" }, @@ -44282,7 +44498,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L901", - "community": 16, + "community": 99, "norm_label": "covers lines 66-67: session not found.", "id": "tests_test_controllers_coverage_rationale_901" }, @@ -44345,7 +44561,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1017", - "community": 101, + "community": 16, "norm_label": "covers lines 114-115, 117-120, 122, 125: post /prometheus/chat.", "id": "tests_test_controllers_coverage_rationale_1017" }, @@ -44354,7 +44570,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1020", - "community": 101, + "community": 99, "norm_label": "covers lines 111-112: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1020" }, @@ -44363,7 +44579,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1038", - "community": 101, + "community": 16, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1038" }, @@ -44372,7 +44588,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1079", - "community": 101, + "community": 16, "norm_label": "covers lines 114-115: session ownership check fails.", "id": "tests_test_controllers_coverage_rationale_1079" }, @@ -44408,7 +44624,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1162", - "community": 14, + "community": 503, "norm_label": "covers line 47: get /stocks/fundamental.", "id": "tests_test_controllers_coverage_rationale_1162" }, @@ -44471,7 +44687,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1239", - "community": 493, + "community": 528, "norm_label": "covers line 27: user already has the role.", "id": "tests_test_controllers_coverage_rationale_1239" }, @@ -44507,7 +44723,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1298", - "community": 493, + "community": 528, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1298" }, @@ -44561,7 +44777,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1413", - "community": 114, + "community": 498, "norm_label": "covers line 67: extracttokenpayload re-raises httpexception from verifyaccesstok", "id": "tests_test_controllers_coverage_rationale_1413" }, @@ -44759,7 +44975,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L663", - "community": 104, + "community": 107, "norm_label": "covers lines 100-104, 106: get /user/sessions/current.", "id": "tests_test_controllers_coverage_rationale_663" }, @@ -44768,7 +44984,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L666", - "community": 104, + "community": 107, "norm_label": "covers lines 100-104, 106: session found.", "id": "tests_test_controllers_coverage_rationale_666" }, @@ -44777,7 +44993,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L699", - "community": 104, + "community": 107, "norm_label": "covers line 104: session not found.", "id": "tests_test_controllers_coverage_rationale_699" }, @@ -44849,7 +45065,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L844", - "community": 16, + "community": 99, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_844" }, @@ -44858,7 +45074,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L862", - "community": 16, + "community": 99, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_862" }, @@ -44867,7 +45083,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L876", - "community": 16, + "community": 99, "norm_label": "covers lines 62-63, 65-68: put /prometheus/sessions/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_876" }, @@ -44876,7 +45092,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L879", - "community": 16, + "community": 99, "norm_label": "covers lines 65-68: title updated successfully.", "id": "tests_test_controllers_coverage_rationale_879" }, @@ -44885,7 +45101,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L890", - "community": 16, + "community": 99, "norm_label": "covers lines 62-63: not the session owner.", "id": "tests_test_controllers_coverage_rationale_890" }, @@ -44894,7 +45110,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L899", - "community": 16, + "community": 99, "norm_label": "covers lines 66-67: session not found.", "id": "tests_test_controllers_coverage_rationale_899" }, @@ -44957,7 +45173,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1015", - "community": 101, + "community": 16, "norm_label": "covers lines 114-115, 117-120, 122, 125: post /prometheus/chat.", "id": "tests_test_controllers_coverage_rationale_1015" }, @@ -44966,7 +45182,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1018", - "community": 101, + "community": 99, "norm_label": "covers lines 111-112: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1018" }, @@ -44975,7 +45191,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1036", - "community": 101, + "community": 16, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1036" }, @@ -44984,7 +45200,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1078", - "community": 101, + "community": 16, "norm_label": "covers lines 114-115: session ownership check fails.", "id": "tests_test_controllers_coverage_rationale_1078" }, @@ -45020,7 +45236,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1161", - "community": 14, + "community": 503, "norm_label": "covers line 47: get /stocks/fundamental.", "id": "tests_test_controllers_coverage_rationale_1161" }, @@ -45074,7 +45290,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1238", - "community": 493, + "community": 528, "norm_label": "covers line 27: user already has the role.", "id": "tests_test_controllers_coverage_rationale_1238" }, @@ -45110,7 +45326,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1297", - "community": 493, + "community": 528, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1297" }, @@ -45182,7 +45398,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1412", - "community": 114, + "community": 498, "norm_label": "covers line 67: extracttokenpayload re-raises httpexception from verifyaccesstok", "id": "tests_test_controllers_coverage_rationale_1412" }, @@ -45380,7 +45596,7 @@ "file_type": "code", "source_file": "tests/test_cache.py", "source_location": "L89", - "community": 95, + "community": 135, "norm_label": "testcolumnvalidator", "id": "tests_test_cache_testcolumnvalidator" }, @@ -45389,7 +45605,7 @@ "file_type": "code", "source_file": "tests/test_cache.py", "source_location": "L90", - "community": 95, + "community": 135, "norm_label": ".test_valid_column_names()", "id": "tests_test_cache_testcolumnvalidator_test_valid_column_names" }, @@ -45398,7 +45614,7 @@ "file_type": "code", "source_file": "tests/test_cache.py", "source_location": "L97", - "community": 95, + "community": 135, "norm_label": ".test_invalid_column_names()", "id": "tests_test_cache_testcolumnvalidator_test_invalid_column_names" }, @@ -45407,7 +45623,7 @@ "file_type": "code", "source_file": "tests/test_cache.py", "source_location": "L103", - "community": 95, + "community": 135, "norm_label": ".test_empty_string()", "id": "tests_test_cache_testcolumnvalidator_test_empty_string" }, @@ -45524,7 +45740,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L229", - "community": 490, + "community": 567, "norm_label": "tests covering key.py lines 15-40. uses asyncio.run() since pytest-asyncio", "id": "tests_test_stocks_api_coverage_rationale_229" }, @@ -45596,7 +45812,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L364", - "community": 567, + "community": 565, "norm_label": "tests covering key.py lines 48-66.", "id": "tests_test_stocks_api_coverage_rationale_364" }, @@ -45776,7 +45992,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L843", - "community": 107, + "community": 137, "norm_label": "invalid date -> inner 400 passes through (not wrapped as 500).", "id": "tests_test_stocks_api_coverage_rationale_843" }, @@ -45794,7 +46010,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L905", - "community": 17, + "community": 39, "norm_label": "dataframe without time column.", "id": "tests_test_stocks_api_coverage_rationale_905" }, @@ -45911,7 +46127,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1216", - "community": 130, + "community": 10, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1216" }, @@ -45929,7 +46145,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1342", - "community": 222, + "community": 112, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1342" }, @@ -45938,7 +46154,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1392", - "community": 234, + "community": 112, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1392" }, @@ -46064,7 +46280,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1344", - "community": 222, + "community": 112, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1344" }, @@ -46073,7 +46289,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1394", - "community": 234, + "community": 112, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1394" }, @@ -46253,7 +46469,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1400", - "community": 222, + "community": 112, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1400" }, @@ -46262,7 +46478,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1468", - "community": 234, + "community": 112, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1468" }, @@ -46289,7 +46505,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L228", - "community": 490, + "community": 567, "norm_label": "tests covering key.py lines 15-40. uses asyncio.run() since pytest-asyncio", "id": "tests_test_stocks_api_coverage_rationale_228" }, @@ -46361,7 +46577,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L363", - "community": 567, + "community": 565, "norm_label": "tests covering key.py lines 48-66.", "id": "tests_test_stocks_api_coverage_rationale_363" }, @@ -46478,7 +46694,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L693", - "community": 215, + "community": 263, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_693" }, @@ -46667,7 +46883,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1212", - "community": 130, + "community": 10, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1212" }, @@ -46685,7 +46901,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1396", - "community": 222, + "community": 112, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1396" }, @@ -46694,7 +46910,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1464", - "community": 234, + "community": 112, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1464" }, @@ -46721,7 +46937,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1388", - "community": 222, + "community": 112, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1388" }, @@ -46730,7 +46946,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1456", - "community": 234, + "community": 112, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1456" }, @@ -46811,7 +47027,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1210", - "community": 130, + "community": 10, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1210" }, @@ -46829,7 +47045,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L832", - "community": 107, + "community": 17, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_832" }, @@ -46955,7 +47171,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1191", - "community": 130, + "community": 10, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1191" }, @@ -47486,7 +47702,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1170", - "community": 130, + "community": 10, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1170" }, @@ -47531,7 +47747,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1141", - "community": 130, + "community": 10, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1141" }, @@ -47612,7 +47828,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1148", - "community": 130, + "community": 10, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1148" }, @@ -47648,7 +47864,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L19", - "community": 29, + "community": 563, "norm_label": "sessionproxy", "id": "prometheus_generation_sessionproxy" }, @@ -47657,7 +47873,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L20", - "community": 29, + "community": 563, "norm_label": ".get()", "id": "prometheus_generation_sessionproxy_get" }, @@ -47666,7 +47882,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L23", - "community": 29, + "community": 563, "norm_label": ".post()", "id": "prometheus_generation_sessionproxy_post" }, @@ -47765,7 +47981,7 @@ "file_type": "code", "source_file": "main/utils/pagination.py", "source_location": "L1", - "community": 482, + "community": 529, "norm_label": "pagination.py", "id": "main_utils_pagination_py" }, @@ -47774,7 +47990,7 @@ "file_type": "code", "source_file": "main/utils/pagination.py", "source_location": "L4", - "community": 482, + "community": 529, "norm_label": "paginationparams", "id": "utils_pagination_paginationparams" }, @@ -47783,7 +47999,7 @@ "file_type": "code", "source_file": "main/utils/pagination.py", "source_location": "L5", - "community": 482, + "community": 529, "norm_label": ".__init__()", "id": "utils_pagination_paginationparams_init" }, @@ -47837,7 +48053,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L39", - "community": 561, + "community": 26, "norm_label": "test that atomic increment prevents race conditions.", "id": "tests_test_api_key_quota_atomic_rationale_39" }, @@ -47864,7 +48080,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L104", - "community": 561, + "community": 26, "norm_label": "test that concurrent requests are properly serialized at db level. th", "id": "tests_test_api_key_quota_atomic_rationale_104" }, @@ -47882,7 +48098,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L166", - "community": 561, + "community": 26, "norm_label": "test that invalid api key returns zero rows affected.", "id": "tests_test_api_key_quota_atomic_rationale_166" }, @@ -48026,7 +48242,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L148", - "community": 120, + "community": 498, "norm_label": "covers lines 44-54, 63, 66-71: register success, valueerror, generic exception.", "id": "tests_test_controllers_coverage_rationale_148" }, @@ -48053,7 +48269,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L228", - "community": 120, + "community": 498, "norm_label": "covers lines 87-93, 102: login success and failure paths.", "id": "tests_test_controllers_coverage_rationale_228" }, @@ -48161,7 +48377,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L425", - "community": 120, + "community": 498, "norm_label": "covers lines 155-156, 158, 160-168, 170-177, 179-184, 186, 190-204: googlecallba", "id": "tests_test_controllers_coverage_rationale_425" }, @@ -48251,7 +48467,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L708", - "community": 104, + "community": 107, "norm_label": "covers lines 100-104, 106: get /user/sessions/current.", "id": "tests_test_controllers_coverage_rationale_708" }, @@ -48260,7 +48476,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L711", - "community": 104, + "community": 107, "norm_label": "covers lines 100-104, 106: session found.", "id": "tests_test_controllers_coverage_rationale_711" }, @@ -48269,7 +48485,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L744", - "community": 104, + "community": 107, "norm_label": "covers line 104: session not found.", "id": "tests_test_controllers_coverage_rationale_744" }, @@ -48341,7 +48557,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L889", - "community": 16, + "community": 99, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_889" }, @@ -48350,7 +48566,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L907", - "community": 16, + "community": 99, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_907" }, @@ -48359,7 +48575,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L921", - "community": 16, + "community": 99, "norm_label": "covers lines 62-63, 65-68: put /prometheus/sessions/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_921" }, @@ -48368,7 +48584,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L924", - "community": 16, + "community": 99, "norm_label": "covers lines 65-68: title updated successfully.", "id": "tests_test_controllers_coverage_rationale_924" }, @@ -48377,7 +48593,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L935", - "community": 16, + "community": 99, "norm_label": "covers lines 62-63: not the session owner.", "id": "tests_test_controllers_coverage_rationale_935" }, @@ -48386,7 +48602,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L944", - "community": 16, + "community": 99, "norm_label": "covers lines 66-67: session not found.", "id": "tests_test_controllers_coverage_rationale_944" }, @@ -48449,7 +48665,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1060", - "community": 101, + "community": 16, "norm_label": "covers lines 114-115, 117-120, 122, 125: post /prometheus/chat.", "id": "tests_test_controllers_coverage_rationale_1060" }, @@ -48458,7 +48674,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1063", - "community": 101, + "community": 99, "norm_label": "covers lines 111-112: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1063" }, @@ -48467,7 +48683,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1081", - "community": 101, + "community": 16, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1081" }, @@ -48476,7 +48692,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1123", - "community": 101, + "community": 16, "norm_label": "covers lines 114-115: session ownership check fails.", "id": "tests_test_controllers_coverage_rationale_1123" }, @@ -48521,7 +48737,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1220", - "community": 14, + "community": 503, "norm_label": "covers line 47: get /stocks/fundamental.", "id": "tests_test_controllers_coverage_rationale_1220" }, @@ -48575,7 +48791,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1356", - "community": 493, + "community": 528, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1356" }, @@ -48629,7 +48845,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1471", - "community": 114, + "community": 498, "norm_label": "covers line 67: extracttokenpayload re-raises httpexception from verifyaccesstok", "id": "tests_test_controllers_coverage_rationale_1471" }, @@ -49106,7 +49322,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L227", - "community": 490, + "community": 567, "norm_label": "tests covering key.py lines 15-40. uses asyncio.run() since pytest-asyncio", "id": "tests_test_stocks_api_coverage_rationale_227" }, @@ -49178,7 +49394,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L362", - "community": 567, + "community": 565, "norm_label": "tests covering key.py lines 48-66.", "id": "tests_test_stocks_api_coverage_rationale_362" }, @@ -49295,7 +49511,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L692", - "community": 215, + "community": 263, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_692" }, @@ -49349,7 +49565,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L831", - "community": 107, + "community": 137, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_831" }, @@ -49403,7 +49619,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L945", - "community": 17, + "community": 39, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_945" }, @@ -49619,7 +49835,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L827", - "community": 107, + "community": 137, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_827" }, @@ -49709,7 +49925,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L826", - "community": 107, + "community": 137, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_826" }, @@ -49718,7 +49934,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L874", - "community": 46, + "community": 17, "norm_label": "search.strip() == '' should still dedup (line 181).", "id": "tests_test_stocks_api_coverage_rationale_874" }, @@ -49763,7 +49979,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/generation.py", "source_location": "L20", - "community": 29, + "community": 563, "norm_label": "thread-safe proxy that delegates to per-thread sessions.", "id": "prometheus_generation_rationale_20" }, @@ -49790,7 +50006,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L646", - "community": 215, + "community": 263, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_646" }, @@ -49844,7 +50060,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L780", - "community": 107, + "community": 137, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_780" }, @@ -49961,7 +50177,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L647", - "community": 215, + "community": 263, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_647" }, @@ -50015,7 +50231,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L781", - "community": 107, + "community": 137, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_781" }, @@ -50087,7 +50303,7 @@ "file_type": "code", "source_file": "main/utils/errors.py", "source_location": "L27", - "community": 33, + "community": 530, "norm_label": "_build_error_response()", "id": "utils_errors_build_error_response" }, @@ -50096,7 +50312,7 @@ "file_type": "code", "source_file": "main/utils/errors.py", "source_location": "L37", - "community": 33, + "community": 530, "norm_label": "http_exception_handler()", "id": "utils_errors_http_exception_handler" }, @@ -50105,7 +50321,7 @@ "file_type": "code", "source_file": "main/utils/errors.py", "source_location": "L44", - "community": 33, + "community": 530, "norm_label": "validation_exception_handler()", "id": "utils_errors_validation_exception_handler" }, @@ -50114,7 +50330,7 @@ "file_type": "code", "source_file": "main/utils/errors.py", "source_location": "L56", - "community": 33, + "community": 530, "norm_label": "generic_exception_handler()", "id": "utils_errors_generic_exception_handler" }, @@ -50123,7 +50339,7 @@ "file_type": "code", "source_file": "main/utils/errors.py", "source_location": "L65", - "community": 104, + "community": 120, "norm_label": "register_error_handlers()", "id": "utils_errors_register_error_handlers" }, @@ -50582,7 +50798,7 @@ "file_type": "code", "source_file": "main/service/user_service.py", "source_location": "L35", - "community": 72, + "community": 488, "norm_label": "inactivesessionsscheduler()", "id": "service_user_service_inactivesessionsscheduler" }, @@ -50933,7 +51149,7 @@ "file_type": "rationale", "source_file": "main/utils/errors.py", "source_location": "L68", - "community": 104, + "community": 120, "norm_label": "register exception handlers on the fastapi app. note: httpexception and r", "id": "utils_errors_rationale_68" }, @@ -50987,7 +51203,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L358", - "community": 567, + "community": 565, "norm_label": "tests covering key.py lines 48-66.", "id": "tests_test_stocks_api_coverage_rationale_358" }, @@ -51077,7 +51293,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L641", - "community": 215, + "community": 263, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_641" }, @@ -51131,7 +51347,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L775", - "community": 107, + "community": 137, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_775" }, @@ -51446,7 +51662,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L185", - "community": 161, + "community": 543, "norm_label": "category 7: code quality (low)", "id": "server_code_review_report_category_7_code_quality_low" }, @@ -51455,7 +51671,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L187", - "community": 161, + "community": 543, "norm_label": "issue 7.1 \u2014 unused imports", "id": "server_code_review_report_issue_7_1_unused_imports" }, @@ -51464,7 +51680,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L194", - "community": 161, + "community": 543, "norm_label": "issue 7.2 \u2014 missing type hints", "id": "server_code_review_report_issue_7_2_missing_type_hints" }, @@ -51473,7 +51689,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L205", - "community": 161, + "community": 543, "norm_label": "issue 7.3 \u2014 `usermanager.__init__` does nothing", "id": "server_code_review_report_issue_7_3_usermanager_init_does_nothing" }, @@ -51482,7 +51698,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L210", - "community": 161, + "community": 543, "norm_label": "issue 7.4 \u2014 mixed async/sync in roles.py", "id": "server_code_review_report_issue_7_4_mixed_async_sync_in_roles_py" }, @@ -51491,7 +51707,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L217", - "community": 231, + "community": 161, "norm_label": "category 8: testing gaps (medium)", "id": "server_code_review_report_category_8_testing_gaps_medium" }, @@ -51500,7 +51716,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L219", - "community": 231, + "community": 161, "norm_label": "issue 8.1 \u2014 no integration tests for full request lifecycle", "id": "server_code_review_report_issue_8_1_no_integration_tests_for_full_request_lifecycle" }, @@ -51509,7 +51725,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L223", - "community": 231, + "community": 161, "norm_label": "issue 8.2 \u2014 no tests for scraper, stocks query, or cache", "id": "server_code_review_report_issue_8_2_no_tests_for_scraper_stocks_query_or_cache" }, @@ -51518,7 +51734,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L230", - "community": 231, + "community": 161, "norm_label": "issue 8.3 \u2014 no tests for google oauth callback", "id": "server_code_review_report_issue_8_3_no_tests_for_google_oauth_callback" }, @@ -51527,7 +51743,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L234", - "community": 231, + "community": 161, "norm_label": "issue 8.4 \u2014 no tests for session cleanup", "id": "server_code_review_report_issue_8_4_no_tests_for_session_cleanup" }, @@ -51590,7 +51806,7 @@ "file_type": "rationale", "source_file": "main/utils/errors.py", "source_location": "L67", - "community": 104, + "community": 120, "norm_label": "register exception handlers on the fastapi app. note: httpexception and r", "id": "utils_errors_rationale_67" }, @@ -52517,7 +52733,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L1", - "community": 518, + "community": 490, "norm_label": "test_stocks_optimization.py", "id": "tests_test_stocks_optimization_py" }, @@ -52526,7 +52742,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L17", - "community": 518, + "community": 490, "norm_label": "testtickerindex", "id": "tests_test_stocks_optimization_testtickerindex" }, @@ -52535,7 +52751,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L20", - "community": 518, + "community": 490, "norm_label": ".test_tickerindex_built_after_cache_load()", "id": "tests_test_stocks_optimization_testtickerindex_test_tickerIndex_built_after_cache_load" }, @@ -52544,7 +52760,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L28", - "community": 518, + "community": 490, "norm_label": ".test_tickerindex_contains_all_tickers()", "id": "tests_test_stocks_optimization_testtickerindex_test_tickerIndex_contains_all_tickers" }, @@ -52553,7 +52769,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L38", - "community": 518, + "community": 490, "norm_label": ".test_tickerindex_case_insensitive()", "id": "tests_test_stocks_optimization_testtickerindex_test_tickerIndex_case_insensitive" }, @@ -52562,7 +52778,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L47", - "community": 518, + "community": 490, "norm_label": ".test_ticker_lookup_returns_valid_index()", "id": "tests_test_stocks_optimization_testtickerindex_test_ticker_lookup_returns_valid_index" }, @@ -52571,7 +52787,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L58", - "community": 518, + "community": 490, "norm_label": ".test_tickerindex_rebuilt_on_cache_refresh()", "id": "tests_test_stocks_optimization_testtickerindex_test_tickerIndex_rebuilt_on_cache_refresh" }, @@ -52634,7 +52850,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L111", - "community": 518, + "community": 490, "norm_label": "testconnectionpool", "id": "tests_test_stocks_optimization_testconnectionpool" }, @@ -52643,7 +52859,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L114", - "community": 518, + "community": 490, "norm_label": ".test_stocks_engine_has_pool_configuration()", "id": "tests_test_stocks_optimization_testconnectionpool_test_stocks_engine_has_pool_configuration" }, @@ -52652,7 +52868,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L123", - "community": 518, + "community": 490, "norm_label": "testlazydeserialization", "id": "tests_test_stocks_optimization_testlazydeserialization" }, @@ -52661,7 +52877,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L126", - "community": 518, + "community": 490, "norm_label": ".test_query_manager_has_deserialize_method()", "id": "tests_test_stocks_optimization_testlazydeserialization_test_query_manager_has_deserialize_method" }, @@ -52760,7 +52976,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L301", - "community": 563, + "community": 524, "norm_label": "testfilterbysearchterms", "id": "tests_test_stocks_optimization_testfilterbysearchterms" }, @@ -52769,7 +52985,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L304", - "community": 563, + "community": 524, "norm_label": ".test_filter_with_tickerindex()", "id": "tests_test_stocks_optimization_testfilterbysearchterms_test_filter_with_tickerIndex" }, @@ -52778,7 +52994,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L310", - "community": 524, + "community": 539, "norm_label": "testqueryperformance", "id": "tests_test_stocks_optimization_testqueryperformance" }, @@ -52787,7 +53003,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L313", - "community": 524, + "community": 539, "norm_label": ".test_query_response_time_under_1_second()", "id": "tests_test_stocks_optimization_testqueryperformance_test_query_response_time_under_1_second" }, @@ -52796,7 +53012,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L18", - "community": 518, + "community": 490, "norm_label": "tests for dynamic ticker index feature", "id": "tests_test_stocks_optimization_rationale_18" }, @@ -52805,7 +53021,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L21", - "community": 518, + "community": 490, "norm_label": "ticker index should be built when cache is loaded", "id": "tests_test_stocks_optimization_rationale_21" }, @@ -52814,7 +53030,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L29", - "community": 518, + "community": 490, "norm_label": "ticker index should contain all tickers from cache", "id": "tests_test_stocks_optimization_rationale_29" }, @@ -52823,7 +53039,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L39", - "community": 518, + "community": 490, "norm_label": "ticker index should be case-insensitive", "id": "tests_test_stocks_optimization_rationale_39" }, @@ -52832,7 +53048,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L48", - "community": 518, + "community": 490, "norm_label": "looking up ticker should return valid row index", "id": "tests_test_stocks_optimization_rationale_48" }, @@ -52841,7 +53057,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L59", - "community": 518, + "community": 490, "norm_label": "ticker index should be rebuilt when cache refreshes", "id": "tests_test_stocks_optimization_rationale_59" }, @@ -52904,7 +53120,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L112", - "community": 518, + "community": 490, "norm_label": "tests for connection pool configuration", "id": "tests_test_stocks_optimization_rationale_112" }, @@ -52913,7 +53129,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L115", - "community": 518, + "community": 490, "norm_label": "stocks engine should have optimized pool settings", "id": "tests_test_stocks_optimization_rationale_115" }, @@ -52922,7 +53138,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L124", - "community": 518, + "community": 490, "norm_label": "tests for lazy json deserialization", "id": "tests_test_stocks_optimization_rationale_124" }, @@ -52931,7 +53147,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L127", - "community": 518, + "community": 490, "norm_label": "query manager should have deserialize method", "id": "tests_test_stocks_optimization_rationale_127" }, @@ -53030,7 +53246,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L302", - "community": 563, + "community": 524, "norm_label": "tests for optimized search filtering", "id": "tests_test_stocks_optimization_rationale_302" }, @@ -53039,7 +53255,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L305", - "community": 563, + "community": 524, "norm_label": "filter should use ticker index for o(1) lookup", "id": "tests_test_stocks_optimization_rationale_305" }, @@ -53048,7 +53264,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L311", - "community": 524, + "community": 539, "norm_label": "performance tests for query operations", "id": "tests_test_stocks_optimization_rationale_311" }, @@ -53057,7 +53273,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L314", - "community": 524, + "community": 539, "norm_label": "query should respond within 1 second", "id": "tests_test_stocks_optimization_rationale_314" }, @@ -53075,7 +53291,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L173", - "community": 563, + "community": 524, "norm_label": "tests for optimized search filtering", "id": "tests_test_stocks_optimization_rationale_173" }, @@ -53084,7 +53300,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L176", - "community": 563, + "community": 524, "norm_label": "filter should use ticker index for o(1) lookup", "id": "tests_test_stocks_optimization_rationale_176" }, @@ -53093,7 +53309,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L182", - "community": 524, + "community": 539, "norm_label": "performance tests for query operations", "id": "tests_test_stocks_optimization_rationale_182" }, @@ -53102,7 +53318,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L185", - "community": 524, + "community": 539, "norm_label": "query should respond within 1 second", "id": "tests_test_stocks_optimization_rationale_185" }, @@ -53385,7 +53601,7 @@ "label": "FastAPI", "file_type": "rationale", "source_file": "README.md", - "community": 181, + "community": 529, "norm_label": "fastapi", "id": "fastapi" }, @@ -53529,7 +53745,7 @@ "label": "Pytest Testing", "file_type": "rationale", "source_file": "pyproject.toml", - "community": 251, + "community": 215, "norm_label": "pytest testing", "id": "pytest" }, @@ -53695,21 +53911,21 @@ "relation": "contains", "confidence": "EXTRACTED", "source_file": "ci.ps1", - "source_location": "L48", + "source_location": "L45", "weight": 1.0, "confidence_score": 1.0, "source": "ci_ps1", - "target": "server_ci_write_fix" + "target": "server_ci_run_check" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "ci.ps1", - "source_location": "L45", + "source_location": "L48", "weight": 1.0, "confidence_score": 1.0, "source": "ci_ps1", - "target": "server_ci_run_check" + "target": "server_ci_write_fix" }, { "relation": "calls", @@ -60298,51 +60514,61 @@ "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/chat.py", - "source_location": "L54", + "source_location": "L52", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_chat_py", - "target": "prometheus_chat_savemessage" + "target": "prometheus_chat_appendhistory" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/chat.py", - "source_location": "L76", + "source_location": "L82", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_chat_py", - "target": "prometheus_chat_saveloopevent" + "target": "prometheus_chat_gethistory" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/chat.py", - "source_location": "L82", + "source_location": "L105", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_chat_py", - "target": "prometheus_chat_gethistory" + "target": "prometheus_chat_deletesession" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/chat.py", - "source_location": "L105", + "source_location": "L119", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_chat_py", - "target": "prometheus_chat_deletesession" + "target": "prometheus_chat_verifysessionownership" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/chat.py", - "source_location": "L119", + "source_location": "L54", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_chat_py", - "target": "prometheus_chat_verifysessionownership" + "target": "prometheus_chat_savemessage" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/chat.py", + "source_location": "L76", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_chat_py", + "target": "prometheus_chat_saveloopevent" }, { "relation": "contains", @@ -60586,6 +60812,16 @@ "source": "main_app_prometheus_compact_py", "target": "prometheus_compact_getmetricregex" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L117", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_compact_py", + "target": "prometheus_compact_dedup" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -60698,6 +60934,17 @@ "source": "prometheus_compact_prometheuscompactor_shouldcompact", "target": "prometheus_compact_counttokens" }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/prometheus/memory.py", + "source_location": "L191", + "weight": 1.0, + "source": "prometheus_memory_sumtokens", + "target": "prometheus_compact_counttokens" + }, { "relation": "calls", "context": "call", @@ -60806,6 +61053,83 @@ "source": "prometheus_compact_extractmetrics", "target": "prometheus_compact_getmetricregex" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L122", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_compact_extracttickers", + "target": "prometheus_compact_dedup" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L128", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_compact_extractmetrics", + "target": "prometheus_compact_dedup" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L142", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_compact_extractdecisions", + "target": "prometheus_compact_dedup" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L155", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_compact_extractsnapshots", + "target": "prometheus_compact_dedup" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L171", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_compact_extracttoolcalls", + "target": "prometheus_compact_dedup" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L236", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_compact_prometheuscompactor_extractepisode", + "target": "prometheus_compact_dedup" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L265", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_compact_prometheuscompactor_consolidate", + "target": "prometheus_compact_dedup" + }, { "relation": "calls", "context": "call", @@ -61033,31 +61357,31 @@ "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L10", + "source_location": "L26", "weight": 1.0, + "confidence_score": 1.0, "source": "main_app_prometheus_mcp_py", - "target": "prometheus_mcp_ensurefastmcp", - "confidence_score": 1.0 + "target": "prometheus_mcp_buildclient" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L26", + "source_location": "L15", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_mcp_py", - "target": "prometheus_mcp_buildclient" + "target": "prometheus_mcp_mcpclientpool" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L15", + "source_location": "L10", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_mcp_py", - "target": "prometheus_mcp_mcpclientpool" + "target": "prometheus_mcp_ensurefastmcp" }, { "relation": "contains", @@ -61074,21 +61398,21 @@ "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L34", + "source_location": "L55", "weight": 1.0, - "source": "prometheus_mcp_buildclient", - "target": "prometheus_mcp_ensurefastmcp", - "confidence_score": 1.0 + "confidence_score": 1.0, + "source": "prometheus_mcp_mcpclientpool_initialize", + "target": "prometheus_mcp_buildclient" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L55", + "source_location": "L95", "weight": 1.0, "confidence_score": 1.0, - "source": "prometheus_mcp_mcpclientpool_initialize", + "source": "prometheus_mcp_mcpclientpool_reconnect", "target": "prometheus_mcp_buildclient" }, { @@ -61096,11 +61420,11 @@ "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L95", + "source_location": "L34", "weight": 1.0, "confidence_score": 1.0, - "source": "prometheus_mcp_mcpclientpool_reconnect", - "target": "prometheus_mcp_buildclient" + "source": "prometheus_mcp_buildclient", + "target": "prometheus_mcp_ensurefastmcp" }, { "relation": "method", @@ -61317,6 +61641,36 @@ "source": "main_app_prometheus_memory_py", "target": "prometheus_memory_findsimilarkey" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L141", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_scorerecency" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L159", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_scorecandidates" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L187", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_sumtokens" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -61417,6 +61771,66 @@ "source": "main_app_prometheus_memory_py", "target": "prometheus_memory_extract" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L43", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_getmatrixasync" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L55", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_invalidateuserasync" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L59", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_clearallasync" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L244", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_upsertmemoryasync" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L333", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_searchasync" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L483", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_deletememoryasync" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -61588,6 +62002,17 @@ "source": "prometheus_memory_getmatrix", "target": "prometheus_memory_matrixkey" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L46", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_getmatrixasync", + "target": "prometheus_memory_matrixkey" + }, { "relation": "calls", "context": "call", @@ -61599,6 +62024,17 @@ "source": "prometheus_memory_getmatrix", "target": "prometheus_memory_matrixusertag" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L51", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_getmatrixasync", + "target": "prometheus_memory_matrixusertag" + }, { "relation": "calls", "context": "call", @@ -61610,6 +62046,17 @@ "source": "prometheus_memory_search", "target": "prometheus_memory_getmatrix" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L64", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_getmatrix", + "target": "prometheus_memory_getmatrixasync" + }, { "relation": "calls", "context": "call", @@ -61643,6 +62090,28 @@ "source": "service_prometheus_service_memorymaintenance", "target": "prometheus_memory_invalidateuser" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L68", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_invalidateuser", + "target": "prometheus_memory_invalidateuserasync" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L72", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_clearall", + "target": "prometheus_memory_clearallasync" + }, { "relation": "calls", "context": "call", @@ -61665,6 +62134,17 @@ "source": "prometheus_memory_search", "target": "prometheus_memory_minmax" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L385", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_searchasync", + "target": "prometheus_memory_minmax" + }, { "relation": "calls", "context": "call", @@ -61709,6 +62189,17 @@ "source": "prometheus_memory_findsimilarkey", "target": "prometheus_memory_upsertmemory" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L281", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_upsertmemoryasync", + "target": "prometheus_memory_findsimilarkey" + }, { "relation": "calls", "context": "call", @@ -61720,6 +62211,83 @@ "source": "prometheus_memory_findsimilarkey", "target": "prometheus_memory_normalize_key" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L314", + "weight": 1.0, + "source": "prometheus_memory_search", + "target": "prometheus_memory_scorerecency", + "confidence_score": 1.0 + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/prometheus/memory.py", + "source_location": "L149", + "weight": 1.0, + "source": "prometheus_memory_scorerecency", + "target": "prometheus_vector_getrelevancescore" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L361", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_searchasync", + "target": "prometheus_memory_scorerecency" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L342", + "weight": 1.0, + "source": "prometheus_memory_search", + "target": "prometheus_memory_scorecandidates", + "confidence_score": 1.0 + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/prometheus/memory.py", + "source_location": "L169", + "weight": 1.0, + "source": "prometheus_memory_scorecandidates", + "target": "prometheus_vector_getrelevancescore" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L389", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_searchasync", + "target": "prometheus_memory_scorecandidates" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L502", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_counttokenscached", + "target": "prometheus_memory_sumtokens" + }, { "relation": "uses", "confidence": "INFERRED", @@ -61953,6 +62521,17 @@ "source": "prometheus_memory_extract", "target": "prometheus_memory_getmemorylimit" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L299", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_upsertmemoryasync", + "target": "prometheus_memory_getmemorylimit" + }, { "relation": "calls", "context": "call", @@ -61975,6 +62554,17 @@ "source": "prometheus_memory_extract", "target": "prometheus_memory_countmemories" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L300", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_upsertmemoryasync", + "target": "prometheus_memory_countmemories" + }, { "relation": "calls", "context": "call", @@ -61997,6 +62587,17 @@ "source": "prometheus_memory_upsertmemory", "target": "prometheus_vector_contenthash" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L231", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_upsertmemory", + "target": "prometheus_memory_upsertmemoryasync" + }, { "relation": "calls", "context": "call", @@ -62063,17 +62664,6 @@ "source": "prometheus_memory_search", "target": "prometheus_memory_fulltextsearch" }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "main/app/prometheus/memory.py", - "source_location": "L120", - "weight": 1.0, - "source": "prometheus_memory_search", - "target": "prometheus_vector_getrelevancescore" - }, { "relation": "calls", "context": "call", @@ -62096,6 +62686,28 @@ "source": "prometheus_memory_search", "target": "prometheus_vector_batchcosinesimilarity" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L330", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_search", + "target": "prometheus_memory_searchasync" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/prometheus/memory.py", + "source_location": "L120", + "weight": 1.0, + "source": "prometheus_memory_search", + "target": "prometheus_vector_getrelevancescore" + }, { "relation": "calls", "context": "call", @@ -62173,6 +62785,17 @@ "source": "prometheus_memory_search", "target": "utils_vector_batch_cosine_similarity" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L386", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_searchasync", + "target": "prometheus_memory_fulltextsearch" + }, { "relation": "calls", "context": "call", @@ -62217,6 +62840,17 @@ "source": "prometheus_memory_getusermemories", "target": "prometheus_memory_now" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L480", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_deletememory", + "target": "prometheus_memory_deletememoryasync" + }, { "relation": "calls", "context": "call", @@ -63544,6 +64178,26 @@ "source": "main_app_prometheus_tools_py", "target": "prometheus_tools_executememorytool" }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L21", + "weight": 1.0, + "source": "prometheus_tools_rationale_21", + "target": "prometheus_tools_search_memory", + "confidence_score": 1.0 + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L20", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_rationale_20", + "target": "prometheus_tools_search_memory" + }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -63639,11 +64293,11 @@ "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/tools.py", - "source_location": "L49", + "source_location": "L52", "weight": 1.0, - "confidence_score": 1.0, - "source": "prometheus_tools_rationale_49", - "target": "prometheus_tools_save_memory" + "source": "prometheus_tools_rationale_52", + "target": "prometheus_tools_save_memory", + "confidence_score": 1.0 }, { "relation": "calls", @@ -63656,6 +64310,26 @@ "source": "prometheus_tools_save_memory", "target": "prometheus_vector_embed" }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L50", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_rationale_50", + "target": "prometheus_tools_save_memory" + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L49", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_rationale_49", + "target": "prometheus_tools_save_memory" + }, { "relation": "calls", "context": "call", @@ -63737,6 +64411,26 @@ "source": "prometheus_tools_save_memory", "target": "prometheus_tools_rationale_29" }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L94", + "weight": 1.0, + "source": "prometheus_tools_rationale_94", + "target": "prometheus_tools_execute_code", + "confidence_score": 1.0 + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L91", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_rationale_91", + "target": "prometheus_tools_execute_code" + }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -63807,6 +64501,26 @@ "source": "prometheus_tools_execute_code", "target": "prometheus_tools_rationale_109" }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L115", + "weight": 1.0, + "source": "prometheus_tools_rationale_115", + "target": "prometheus_tools_read_file", + "confidence_score": 1.0 + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L112", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_rationale_112", + "target": "prometheus_tools_read_file" + }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -63877,6 +64591,26 @@ "source": "prometheus_tools_read_file", "target": "prometheus_tools_rationale_130" }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L129", + "weight": 1.0, + "source": "prometheus_tools_rationale_129", + "target": "prometheus_tools_write_file", + "confidence_score": 1.0 + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L126", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_rationale_126", + "target": "prometheus_tools_write_file" + }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -63957,6 +64691,26 @@ "source": "prometheus_tools_write_file", "target": "prometheus_tools_rationale_143" }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L145", + "weight": 1.0, + "source": "prometheus_tools_rationale_145", + "target": "prometheus_tools_list_files", + "confidence_score": 1.0 + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L142", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_rationale_142", + "target": "prometheus_tools_list_files" + }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -64027,6 +64781,26 @@ "source": "prometheus_tools_list_files", "target": "prometheus_tools_rationale_158" }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L158", + "weight": 1.0, + "source": "prometheus_tools_rationale_158", + "target": "prometheus_tools_serve_file", + "confidence_score": 1.0 + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L155", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_rationale_155", + "target": "prometheus_tools_serve_file" + }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -64259,31 +65033,11 @@ "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/tools.py", - "source_location": "L19", - "weight": 1.0, - "confidence_score": 1.0, - "source": "prometheus_tools_rationale_19", - "target": "prometheus_tools_getdb" - }, - { - "relation": "rationale_for", - "confidence": "EXTRACTED", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L90", - "weight": 1.0, - "confidence_score": 1.0, - "source": "prometheus_tools_rationale_90", - "target": "prometheus_tools_get_state" - }, - { - "relation": "rationale_for", - "confidence": "EXTRACTED", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L154", + "source_location": "L94", "weight": 1.0, "confidence_score": 1.0, - "source": "prometheus_tools_check_cache", - "target": "prometheus_tools_rationale_154" + "source": "prometheus_tools_set_state", + "target": "prometheus_tools_rationale_94" }, { "relation": "contains", @@ -64387,6 +65141,17 @@ "source": "prometheus_vector_embed", "target": "models_loader_getembeddingmodel" }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/prometheus/memory.py", + "source_location": "L379", + "weight": 1.0, + "source": "prometheus_memory_searchasync", + "target": "prometheus_vector_embed" + }, { "relation": "calls", "context": "call", @@ -64420,6 +65185,17 @@ "source": "bench_bench_memory_vector_benchonce", "target": "prometheus_vector_decodeembeddings" }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/prometheus/memory.py", + "source_location": "L380", + "weight": 1.0, + "source": "prometheus_memory_searchasync", + "target": "prometheus_vector_batchcosinesimilarity" + }, { "relation": "calls", "context": "call", @@ -64475,6 +65251,17 @@ "source": "prometheus_vector_batchcosinesimilarity", "target": "tests_test_vector_utils_testbatchcosinesimilarity_test_zero_query" }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/prometheus/memory.py", + "source_location": "L262", + "weight": 1.0, + "source": "prometheus_memory_upsertmemoryasync", + "target": "prometheus_vector_contenthash" + }, { "relation": "calls", "context": "call", @@ -64695,17 +65482,6 @@ "source": "prometheus_vector_getrelevancescore", "target": "tests_test_relevance_score_testnocronneeded_test_different_times_different_scores" }, - { - "relation": "imports_from", - "context": "import", - "confidence": "EXTRACTED", - "source_file": "main/app/scraper_b3/scraper.py", - "source_location": "L20", - "weight": 1.0, - "confidence_score": 1.0, - "source": "main_app_scraper_b3_scraper_py", - "target": "main_app_scraper_b3_xango_py" - }, { "relation": "contains", "confidence": "EXTRACTED", @@ -64816,6 +65592,17 @@ "source": "main_app_scraper_b3_scraper_py", "target": "scraper_b3_scraper_stocknews" }, + { + "relation": "imports_from", + "context": "import", + "confidence": "EXTRACTED", + "source_file": "main/app/scraper_b3/scraper.py", + "source_location": "L20", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_scraper_b3_scraper_py", + "target": "main_app_scraper_b3_xango_py" + }, { "relation": "calls", "context": "call", @@ -65232,6 +66019,16 @@ "source": "stocks_api_cache_stockscachemanager", "target": "stocks_api_cache_stockscachemanager_init" }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/cache.py", + "source_location": "L198", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_cache_stockscachemanager", + "target": "stocks_api_cache_stockscachemanager_snapshot" + }, { "relation": "method", "confidence": "EXTRACTED", @@ -66455,21 +67252,21 @@ "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/key.py", - "source_location": "L16", + "source_location": "L14", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_stocks_api_key_py", - "target": "stocks_api_key_hashkey" + "target": "stocks_api_key_verifyapikey" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/key.py", - "source_location": "L14", + "source_location": "L16", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_stocks_api_key_py", - "target": "stocks_api_key_verifyapikey" + "target": "stocks_api_key_hashkey" }, { "relation": "contains", @@ -66572,94 +67369,6 @@ "source": "stocks_api_key_hashkey", "target": "stocks_api_key_verifyapikey" }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/key.py", - "source_location": "L61", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_key_hashkey", - "target": "stocks_api_key_createkey" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_api_key_quota_atomic.py", - "source_location": "L35", - "weight": 1.0, - "source": "stocks_api_key_hashkey", - "target": "tests_test_api_key_quota_atomic_samplekeydata" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_api_key_quota_atomic.py", - "source_location": "L56", - "weight": 1.0, - "source": "stocks_api_key_hashkey", - "target": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_normal_quota_check_works" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_api_key_quota_atomic.py", - "source_location": "L79", - "weight": 1.0, - "source": "stocks_api_key_hashkey", - "target": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_atomic_increment_prevents_overuse" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_api_key_quota_atomic.py", - "source_location": "L121", - "weight": 1.0, - "source": "stocks_api_key_hashkey", - "target": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_concurrent_requests_serialized_at_db_level" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_api_key_quota_atomic.py", - "source_location": "L154", - "weight": 1.0, - "source": "stocks_api_key_hashkey", - "target": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_request_at_exact_quota_limit" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_api_key_quota_atomic.py", - "source_location": "L224", - "weight": 1.0, - "source": "stocks_api_key_hashkey", - "target": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_increment_from_zero" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L392", - "weight": 1.0, - "source": "stocks_api_key_hashkey", - "target": "tests_test_stocks_api_coverage_test_create_key_existing_user_updates" - }, { "relation": "calls", "context": "call", @@ -66884,6 +67593,17 @@ "source": "main_app_stocks_api_query_py", "target": "stocks_api_query_filtercotationbydate" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L106", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_finalize", + "target": "stocks_api_query_sanitizenanvalues" + }, { "relation": "calls", "context": "call", @@ -66928,6 +67648,17 @@ "source": "stocks_api_query_sanitizenanvalues", "target": "stocks_api_query_stocksquerymanager_querycotations" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L99", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_finalize", + "target": "stocks_api_query_filtercotationcolumn" + }, { "relation": "calls", "context": "call", @@ -67015,6 +67746,26 @@ "source": "stocks_api_query_stocksquerymanager", "target": "stocks_api_query_stocksquerymanager_init" }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L58", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_baseframe" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L69", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_finalize" + }, { "relation": "method", "confidence": "EXTRACTED", @@ -67476,6 +68227,105 @@ "source": "stocks_api_query_stocksquerymanager", "target": "tests_test_stocks_optimization_testqueryoptimization_test_query_filter_uses_optimization" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L163", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryhistorical", + "target": "stocks_api_query_stocksquerymanager_baseframe" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L230", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryfundamental", + "target": "stocks_api_query_stocksquerymanager_baseframe" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L290", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_querycotations", + "target": "stocks_api_query_stocksquerymanager_baseframe" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L84", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_finalize", + "target": "stocks_api_query_stocksquerymanager_filterbysearchterms" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L93", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_finalize", + "target": "stocks_api_query_stocksquerymanager_deserializejsoncolumns" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L202", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryhistorical", + "target": "stocks_api_query_stocksquerymanager_finalize" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L277", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryfundamental", + "target": "stocks_api_query_stocksquerymanager_finalize" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L313", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_querycotations", + "target": "stocks_api_query_stocksquerymanager_finalize" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L97", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager_finalize", + "target": "stocks_api_util_parsedaterange" + }, { "relation": "calls", "context": "call", @@ -67525,33 +68375,33 @@ "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L99", + "source_location": "L151", "weight": 1.0, "confidence_score": 1.0, "source": "stocks_api_query_stocksquerymanager_filterbysearchterms", - "target": "stocks_api_query_stocksquerymanager_queryhistorical" + "target": "stocks_api_query_stocksquerymanager_queryfundamental" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L151", + "source_location": "L306", "weight": 1.0, "confidence_score": 1.0, "source": "stocks_api_query_stocksquerymanager_filterbysearchterms", - "target": "stocks_api_query_stocksquerymanager_queryfundamental" + "target": "stocks_api_query_stocksquerymanager_querycotations" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L306", + "source_location": "L99", "weight": 1.0, "confidence_score": 1.0, "source": "stocks_api_query_stocksquerymanager_filterbysearchterms", - "target": "stocks_api_query_stocksquerymanager_querycotations" + "target": "stocks_api_query_stocksquerymanager_queryhistorical" }, { "relation": "calls", @@ -69595,16 +70445,6 @@ "source": "main_controller_stocksapi_controller_py", "target": "fastapi" }, - { - "relation": "contains", - "confidence": "EXTRACTED", - "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L23", - "weight": 1.0, - "confidence_score": 1.0, - "source": "main_controller_stocksapi_controller_py", - "target": "controller_stocksapi_controller_jsonbytesresponse" - }, { "relation": "contains", "confidence": "EXTRACTED", @@ -69669,61 +70509,51 @@ "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L46", + "source_location": "L23", "weight": 1.0, "confidence_score": 1.0, "source": "main_controller_stocksapi_controller_py", - "target": "controller_stocksapi_controller_generatekey" + "target": "controller_stocksapi_controller_jsonbytesresponse" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L63", + "source_location": "L46", "weight": 1.0, "confidence_score": 1.0, "source": "main_controller_stocksapi_controller_py", - "target": "controller_stocksapi_controller_getrealtimecotation" + "target": "controller_stocksapi_controller_generatekey" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L20", + "source_location": "L63", "weight": 1.0, "confidence_score": 1.0, "source": "main_controller_stocksapi_controller_py", - "target": "controller_stocksapi_controller_apikeytest" - }, - { - "relation": "inherits", - "confidence": "EXTRACTED", - "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L23", - "weight": 1.0, - "confidence_score": 1.0, - "source": "controller_stocksapi_controller_jsonbytesresponse", - "target": "fastapiresponse" + "target": "controller_stocksapi_controller_getrealtimecotation" }, { - "relation": "method", + "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L28", + "source_location": "L20", "weight": 1.0, "confidence_score": 1.0, - "source": "controller_stocksapi_controller_jsonbytesresponse", - "target": "controller_stocksapi_controller_jsonbytesresponse_render" + "source": "main_controller_stocksapi_controller_py", + "target": "controller_stocksapi_controller_apikeytest" }, { "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L24", + "source_location": "L39", "weight": 1.0, "confidence_score": 1.0, - "source": "controller_stocksapi_controller_rationale_24", - "target": "controller_stocksapi_controller_jsonbytesresponse" + "source": "controller_stocksapi_controller_rationale_39", + "target": "controller_stocksapi_controller_listfields" }, { "relation": "rationale_for", @@ -69816,6 +70646,16 @@ "source": "controller_stocksapi_controller_listfields", "target": "controller_stocksapi_controller_rationale_26" }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L95", + "weight": 1.0, + "confidence_score": 1.0, + "source": "controller_stocksapi_controller_rationale_95", + "target": "controller_stocksapi_controller_gethistorical" + }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -69866,16 +70706,6 @@ "source": "controller_stocksapi_controller_rationale_105", "target": "controller_stocksapi_controller_gethistorical" }, - { - "relation": "rationale_for", - "confidence": "EXTRACTED", - "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L95", - "weight": 1.0, - "confidence_score": 1.0, - "source": "controller_stocksapi_controller_rationale_95", - "target": "controller_stocksapi_controller_gethistorical" - }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -69927,6 +70757,16 @@ "source": "controller_stocksapi_controller_gethistorical", "target": "controller_stocksapi_controller_rationale_65" }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L160", + "weight": 1.0, + "confidence_score": 1.0, + "source": "controller_stocksapi_controller_rationale_160", + "target": "controller_stocksapi_controller_getfundamental" + }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -70038,6 +70878,16 @@ "source": "controller_stocksapi_controller_getfundamental", "target": "controller_stocksapi_controller_rationale_123" }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L228", + "weight": 1.0, + "confidence_score": 1.0, + "source": "controller_stocksapi_controller_rationale_228", + "target": "controller_stocksapi_controller_getcotations" + }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -70098,16 +70948,6 @@ "source": "controller_stocksapi_controller_rationale_238", "target": "controller_stocksapi_controller_getcotations" }, - { - "relation": "rationale_for", - "confidence": "EXTRACTED", - "source_file": "main/controller/stocksapi_controller.py", - "source_location": "L228", - "weight": 1.0, - "confidence_score": 1.0, - "source": "controller_stocksapi_controller_rationale_228", - "target": "controller_stocksapi_controller_getcotations" - }, { "relation": "calls", "context": "call", @@ -70149,6 +70989,16 @@ "source": "controller_stocksapi_controller_getcotations", "target": "controller_stocksapi_controller_rationale_184" }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L282", + "weight": 1.0, + "confidence_score": 1.0, + "source": "controller_stocksapi_controller_rationale_282", + "target": "controller_stocksapi_controller_getlivecotation" + }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -79239,6 +80089,207 @@ "source": "specs_2026_09_04_wallet_design_2_decision_design_a_pure_event_log_derive_at_read_time", "target": "specs_2026_09_04_wallet_design_approaches_considered" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L377", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_searchasync", + "target": "prometheus_memory_getmatrixasync" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L277", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_upsertmemoryasync", + "target": "prometheus_memory_invalidateuserasync" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L496", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_deletememoryasync", + "target": "prometheus_memory_invalidateuserasync" + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L91", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_set_state", + "target": "prometheus_tools_rationale_91" + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L142", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_read_sandbox_file", + "target": "prometheus_tools_rationale_142" + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L19", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_rationale_19", + "target": "prometheus_tools_getdb" + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L90", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_rationale_90", + "target": "prometheus_tools_get_state" + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/tools.py", + "source_location": "L154", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_tools_check_cache", + "target": "prometheus_tools_rationale_154" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/key.py", + "source_location": "L61", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_key_hashkey", + "target": "stocks_api_key_createkey" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_api_key_quota_atomic.py", + "source_location": "L35", + "weight": 1.0, + "source": "stocks_api_key_hashkey", + "target": "tests_test_api_key_quota_atomic_samplekeydata" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_api_key_quota_atomic.py", + "source_location": "L56", + "weight": 1.0, + "source": "stocks_api_key_hashkey", + "target": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_normal_quota_check_works" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_api_key_quota_atomic.py", + "source_location": "L79", + "weight": 1.0, + "source": "stocks_api_key_hashkey", + "target": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_atomic_increment_prevents_overuse" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_api_key_quota_atomic.py", + "source_location": "L121", + "weight": 1.0, + "source": "stocks_api_key_hashkey", + "target": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_concurrent_requests_serialized_at_db_level" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_api_key_quota_atomic.py", + "source_location": "L154", + "weight": 1.0, + "source": "stocks_api_key_hashkey", + "target": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_request_at_exact_quota_limit" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_api_key_quota_atomic.py", + "source_location": "L224", + "weight": 1.0, + "source": "stocks_api_key_hashkey", + "target": "tests_test_api_key_quota_atomic_testatomicquotaincrement_test_increment_from_zero" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L392", + "weight": 1.0, + "source": "stocks_api_key_hashkey", + "target": "tests_test_stocks_api_coverage_test_create_key_existing_user_updates" + }, + { + "relation": "inherits", + "confidence": "EXTRACTED", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L23", + "weight": 1.0, + "confidence_score": 1.0, + "source": "controller_stocksapi_controller_jsonbytesresponse", + "target": "fastapiresponse" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L28", + "weight": 1.0, + "confidence_score": 1.0, + "source": "controller_stocksapi_controller_jsonbytesresponse", + "target": "controller_stocksapi_controller_jsonbytesresponse_render" + }, + { + "relation": "rationale_for", + "confidence": "EXTRACTED", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L24", + "weight": 1.0, + "confidence_score": 1.0, + "source": "controller_stocksapi_controller_rationale_24", + "target": "controller_stocksapi_controller_jsonbytesresponse" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -85851,16 +86902,6 @@ "source": "prometheus_tools_set_state", "target": "tests_test_state_tools_test_set_state_no_state" }, - { - "relation": "rationale_for", - "confidence": "EXTRACTED", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L94", - "weight": 1.0, - "confidence_score": 1.0, - "source": "prometheus_tools_set_state", - "target": "prometheus_tools_rationale_94" - }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -85882,16 +86923,6 @@ "source": "prometheus_tools_set_state", "target": "tests_test_prometheus_tools_test_set_state_no_state_returns_error" }, - { - "relation": "rationale_for", - "confidence": "EXTRACTED", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L91", - "weight": 1.0, - "confidence_score": 1.0, - "source": "prometheus_tools_set_state", - "target": "prometheus_tools_rationale_91" - }, { "relation": "calls", "context": "call", @@ -125863,16 +126894,6 @@ "source": "prometheus_tools_read_sandbox_file", "target": "prometheus_tools_rationale_140" }, - { - "relation": "rationale_for", - "confidence": "EXTRACTED", - "source_file": "main/app/prometheus/tools.py", - "source_location": "L142", - "weight": 1.0, - "confidence_score": 1.0, - "source": "prometheus_tools_read_sandbox_file", - "target": "prometheus_tools_rationale_142" - }, { "relation": "rationale_for", "confidence": "EXTRACTED", @@ -134925,5 +135946,5 @@ "label": "User Authentication & Authorization" } ], - "built_at_commit": "0f03079f2fef4a78efd67aed61edd543b3bfc497" + "built_at_commit": "8e244c48aba386cd3418415429062c9b01ab8b0d" } \ No newline at end of file diff --git a/graphify-out/manifest.json b/graphify-out/manifest.json index 7c74b94..26fe68d 100644 --- a/graphify-out/manifest.json +++ b/graphify-out/manifest.json @@ -5,18 +5,18 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\ci.ps1": { - "mtime": 1788411558.9481854, - "ast_hash": "342949e2d0408e253deb27aed009e742", + "mtime": 1789278829.3713293, + "ast_hash": "4fac1d9574863bccc6687504739dd8d2", "semantic_hash": "" }, "D:\\Repositories\\server\\config.py": { - "mtime": 1788412747.13282, - "ast_hash": "61a38ebf565138e8262311dd875ea0f0", + "mtime": 1789281902.8629024, + "ast_hash": "a9e0df3ac791a43734658c97fa8b5f16", "semantic_hash": "" }, "D:\\Repositories\\server\\run.py": { - "mtime": 1789165435.4754658, - "ast_hash": "8856c087c4c66080621d00487e4bc52c", + "mtime": 1789266824.6521552, + "ast_hash": "7355f5c18bcf9d44dd7cc641270b32df", "semantic_hash": "" }, "D:\\Repositories\\server\\frontend\\components.json": { @@ -205,374 +205,374 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\authentication\\authentication.py": { - "mtime": 1788411558.9717386, + "mtime": 1789266824.5949514, "ast_hash": "e747d01f0db15e4322833ed9dc067348", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\authentication\\constants.py": { - "mtime": 1788411558.9717386, - "ast_hash": "9f497c5874db5d3f79d079145ca926b0", + "mtime": 1789266824.5959513, + "ast_hash": "6ecf8e66be1de1ff26dca48638218fc4", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\authentication\\session.py": { - "mtime": 1789165435.4499094, + "mtime": 1789266824.5969524, "ast_hash": "6507469627574af836ec8caf56062999", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\authentication\\sso.py": { - "mtime": 1788411558.9727383, - "ast_hash": "42ac137d44a44df20077f415f55b55f9", + "mtime": 1789266824.5979493, + "ast_hash": "aa87b1f6ca93c9a754a7919d6980afe2", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\authentication\\util.py": { - "mtime": 1788462740.4739487, - "ast_hash": "231aab012741da01973c25e86d7b532f", + "mtime": 1789266824.5994601, + "ast_hash": "67a1157414105353b72219fbc0804fbb", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\agent.py": { - "mtime": 1789246171.1370957, - "ast_hash": "76f1ef738f48ff9dcbba3fc576b14ae7", + "mtime": 1789282177.9672518, + "ast_hash": "dd0ff02b01201cbe2f5144f9b95bab61", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\chat.py": { - "mtime": 1788411558.975254, - "ast_hash": "208eb03ea19a9d91f84010f1337292b3", + "mtime": 1789266824.60047, + "ast_hash": "8795017b4ff81f81d5e107f6aa6082a4", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\compact.py": { - "mtime": 1789246597.687021, - "ast_hash": "c02301d71deffbe964945a99e6eeee2b", + "mtime": 1789266824.6014771, + "ast_hash": "955e54ce6de3039635c540c1ad0e4511", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\mcp.py": { - "mtime": 1789246733.6920986, - "ast_hash": "28dcd15b418641878fb794030d63a3ad", + "mtime": 1789282153.988783, + "ast_hash": "f2db9643cce48d937619f6ffe181a07b", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\memory.py": { - "mtime": 1789246519.473933, - "ast_hash": "1912a302f266300963231b4d648fe1f1", + "mtime": 1789282414.1017342, + "ast_hash": "fa53feb5163a2b399aaefa2b393794cf", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\sandbox.py": { - "mtime": 1789165435.4529066, - "ast_hash": "494b384f69446280bcff4fab8b3acbf6", + "mtime": 1789278691.4397347, + "ast_hash": "de536b4a09d235508f0caf3e039a801f", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\stream_bus.py": { - "mtime": 1788411558.979262, - "ast_hash": "6a80c42ab84489b8a70c1cd4e855c8e5", + "mtime": 1789266824.6054785, + "ast_hash": "09ed8f9196ab4d41b95499735d2d1af9", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\tools.py": { - "mtime": 1789165435.453908, - "ast_hash": "39a7952d9fc6ce047e1e5800cd48f269", + "mtime": 1789282460.734141, + "ast_hash": "d54cd35bb02513bca16bc806f1ab4c6a", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\vector.py": { - "mtime": 1789242566.5574288, - "ast_hash": "6b3c9f8d80bd2ac84294cd0c389ecd07", + "mtime": 1789266824.606479, + "ast_hash": "dd0df7ede0dd28d74c307a7aea6ba04b", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\scraper_b3\\scraper.py": { - "mtime": 1788411558.980779, - "ast_hash": "e6a8134ca3294e14633ef568439dc6e6", + "mtime": 1789282003.1280055, + "ast_hash": "1d4b74cf65d7cc8f304a53f12110a77e", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\scraper_b3\\xango.py": { - "mtime": 1788411558.9817748, - "ast_hash": "aee41f95df8f7d49c419194774d65c90", + "mtime": 1789266824.60899, + "ast_hash": "0cbeed2304027b45b74b36f17b47cca7", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\cache.py": { - "mtime": 1789165435.4559073, - "ast_hash": "6a98784ad560b372f318f672671b457c", + "mtime": 1789266824.609999, + "ast_hash": "b88e8c309402b9d68b54fb4954c4d706", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\compress.py": { - "mtime": 1789165435.4574144, - "ast_hash": "780168715e675b2ba0d260b2cbbf7b5a", + "mtime": 1789266824.6110003, + "ast_hash": "06fef344001f68f7335f88d81bb0dc02", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\key.py": { - "mtime": 1788411558.9837754, - "ast_hash": "024e1edd98cbd3cd69f07755cbb1a957", + "mtime": 1789266824.6110003, + "ast_hash": "41e13069c81260e08594fd9e35557e2c", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\query.py": { - "mtime": 1789246171.1410954, - "ast_hash": "6e8bd7ff9b8b48282d2e2db917cfd2ca", + "mtime": 1789281924.4611645, + "ast_hash": "a4d94b431337c15d31c743ee6699a3a8", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\sync_cache.py": { - "mtime": 1789244868.9023068, - "ast_hash": "58fb001054397418eab03630ce699674", + "mtime": 1789266824.6130083, + "ast_hash": "1bac9bc5d8d5977215ff7bc27eea5477", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\util.py": { - "mtime": 1788411558.9852843, + "mtime": 1789266824.6140084, "ast_hash": "8c5c4bd501148c5eef30a1053def2712", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\user\\user.py": { - "mtime": 1789165435.459432, + "mtime": 1789266824.6150067, "ast_hash": "b9fdcffec5ca0cbad6252af644acbe02", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\controller\\authentication_controller.py": { - "mtime": 1789165435.4604318, + "mtime": 1789266824.6160088, "ast_hash": "c1ff3fd4aaaae1d2d03877cc298f260b", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\controller\\prometheus_controller.py": { - "mtime": 1788411558.9872923, + "mtime": 1789266824.617007, "ast_hash": "0af3e9b5a00f92f201cf0a5cc93ba9f6", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\controller\\stocksapi_controller.py": { - "mtime": 1789165435.4624305, - "ast_hash": "0db02fcde3b2e0d565d4ae3c20f7e8cb", + "mtime": 1789266824.618007, + "ast_hash": "b5bc6c647ad244d94e7ba69caba3c778", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\controller\\user_controller.py": { - "mtime": 1788411558.9892921, - "ast_hash": "290f39ddba216cd5b2190219ac46e7c3", + "mtime": 1789266824.6195102, + "ast_hash": "7cf59e6c85a74e74c377c9bf648eadb8", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\models\\base.py": { - "mtime": 1788411558.9897985, - "ast_hash": "f9ce77713f2a3c4312568d2f1de24402", + "mtime": 1789266824.6195102, + "ast_hash": "7dcf1fbc4850b465566daca90de0deb4", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\models\\memory.py": { - "mtime": 1789165435.4624305, + "mtime": 1789266824.6205156, "ast_hash": "c76f29fef1fab50d579d6dd8f82b9c60", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\models\\prometheus.py": { - "mtime": 1789165435.4634314, + "mtime": 1789266824.6215203, "ast_hash": "68de0cc1a6d9707a26241e318130c41f", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\models\\sandbox.py": { - "mtime": 1789165435.4644322, + "mtime": 1789266824.6225207, "ast_hash": "812b7c0da8ae615fd35f8c5b9c107b14", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\models\\stocksapi_key.py": { - "mtime": 1788411558.9928021, + "mtime": 1789266824.6225207, "ast_hash": "cd0caec105a4e1f6821f3be8f77bc6d4", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\models\\types.py": { - "mtime": 1788411558.9928021, - "ast_hash": "8a2a39ea5eb68ed6a8db8cd9fee6a111", - "semantic_hash": "8a2a39ea5eb68ed6a8db8cd9fee6a111" + "mtime": 1789266824.6235218, + "ast_hash": "6d16d39bde8e1314f7534f6654169177", + "semantic_hash": "" }, "D:\\Repositories\\server\\main\\models\\user.py": { - "mtime": 1789165435.4679475, + "mtime": 1789266824.6245222, "ast_hash": "e17234b7fc422b15eecce1497d94b107", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\models\\user_session.py": { - "mtime": 1789165435.4704657, + "mtime": 1789266824.6255214, "ast_hash": "0245c293779cd189e1e74b2d006af625", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\service\\authentication_service.py": { - "mtime": 1788411558.9943094, - "ast_hash": "e42ca9e50634513e3f144cedf88aa45a", + "mtime": 1789266824.6255214, + "ast_hash": "68127fe1d44a44242ce3a5ed2bf4d464", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\service\\prometheus_service.py": { - "mtime": 1789246843.710394, + "mtime": 1789266824.626519, "ast_hash": "3e14105613ccb9deb1c43d6e0e8502ff", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\service\\scraper_service.py": { - "mtime": 1788463590.1617267, + "mtime": 1789266824.627523, "ast_hash": "6575c31ecdafb6c1b0b7b7313e6b1458", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\service\\stocksapi_service.py": { - "mtime": 1788463568.1610415, - "ast_hash": "4dab046f696157a0738792d24d99971b", + "mtime": 1789267774.0200655, + "ast_hash": "83d9740ec96a60fc7c671db7a850f86e", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\service\\user_service.py": { - "mtime": 1789165435.4714649, + "mtime": 1789266824.6290352, "ast_hash": "aab8360aeaaa776f5d17e5a0e0caf6dd", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\connectivity.py": { - "mtime": 1788411558.9973257, - "ast_hash": "319fbd817c2f11f5de4886ace9381df0", + "mtime": 1789266824.630044, + "ast_hash": "f5bb506f5374eab04ff6e761ffec1807", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\errors.py": { - "mtime": 1789165435.4734647, + "mtime": 1789266824.6310434, "ast_hash": "c2b4821f5e848dfe9154343dcefda2d2", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\http_session.py": { - "mtime": 1788411558.9993258, - "ast_hash": "d8a2d3c5d1841718c1bd68ad05ff01c4", + "mtime": 1789266824.6320508, + "ast_hash": "0837b2c1f6a7f9e678f96844d4d1aadc", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\logging_config.py": { - "mtime": 1788411558.999831, - "ast_hash": "724d53c6fddbd992b0865ac76ac85751", + "mtime": 1789267774.022068, + "ast_hash": "8f7c2f17ff2d4f0f94116fb8c1bcfe64", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\migrator.py": { - "mtime": 1788411559.000839, - "ast_hash": "4947148d3988a31aa2a607f8dba204dd", + "mtime": 1789266824.6340508, + "ast_hash": "7ef9216d73553fdad80095cfba9d1985", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\request_id.py": { - "mtime": 1788411559.0018365, - "ast_hash": "25407e6736b0590defb1969f44d97ed6", + "mtime": 1789266824.636052, + "ast_hash": "9ea759d02a226f40ac0b377bc8159dac", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\roles.py": { - "mtime": 1789165435.4734647, + "mtime": 1789266824.6370509, "ast_hash": "4cd3b8e35737d786f10bfb7f46d3444a", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\scheduler.py": { - "mtime": 1788462610.1068745, + "mtime": 1789266824.6380517, "ast_hash": "93c45f5b637d85cfcb42f2217a40b6f6", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\service_manager.py": { - "mtime": 1788462740.4754858, + "mtime": 1789266824.6380517, "ast_hash": "5c306a3c9b76df14f50c9662d0efa10d", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\models\\loader.py": { - "mtime": 1788428759.017697, + "mtime": 1789266824.6350515, "ast_hash": "53d7f85c943e3cac2acb81fb5ebe5a79", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\models\\__init__.py": { - "mtime": 1788411559.000839, + "mtime": 1789266824.6350515, "ast_hash": "d41d8cd98f00b204e9800998ecf8427e", "semantic_hash": "d41d8cd98f00b204e9800998ecf8427e" }, "D:\\Repositories\\server\\migrations\\env.py": { - "mtime": 1789165435.4744656, + "mtime": 1789266824.639558, "ast_hash": "345111c3a60677e141468fe7d6af0cd3", "semantic_hash": "" }, "D:\\Repositories\\server\\migrations\\versions\\25af7ad931e7_initial_migration.py": { - "mtime": 1788411559.0058544, - "ast_hash": "2c9c99f201fc86d6c6fb0c9aaee3fa86", + "mtime": 1789266824.641565, + "ast_hash": "5a2d467db4e7ab0dbd15238dd5ccad84", "semantic_hash": "" }, "D:\\Repositories\\server\\migrations\\versions\\4a2f1c9e3b5d_user_sessions.py": { - "mtime": 1788411559.006864, - "ast_hash": "b455720b147264fe134c0d8aa07603a4", - "semantic_hash": "b455720b147264fe134c0d8aa07603a4" + "mtime": 1789266824.641565, + "ast_hash": "6f701ad504554b99772333851ddf4e1b", + "semantic_hash": "" }, "D:\\Repositories\\server\\migrations\\versions\\9f3b339dde20_drop_unused_user_sessions_columns.py": { - "mtime": 1788411559.0078592, - "ast_hash": "d0fd4d9509782538dafcab3e7b4248da", - "semantic_hash": "d0fd4d9509782538dafcab3e7b4248da" + "mtime": 1789266824.643073, + "ast_hash": "7b002454a5a67cf5b15845847da95ff9", + "semantic_hash": "" }, "D:\\Repositories\\server\\migrations\\versions\\add_access_token_hash.py": { - "mtime": 1788411559.0078592, - "ast_hash": "8b284b1987a01828e921712f5c87a703", - "semantic_hash": "8b284b1987a01828e921712f5c87a703" + "mtime": 1789266824.6436262, + "ast_hash": "064bfc3a4a97befb8b999cf957d12c6e", + "semantic_hash": "" }, "D:\\Repositories\\server\\migrations\\versions\\b1c2d3e4f5a6_create_prometheus_memories.py": { - "mtime": 1788411559.0078592, - "ast_hash": "e30a4e930c72c90ca296e324eda3864a", - "semantic_hash": "e30a4e930c72c90ca296e324eda3864a" + "mtime": 1789266824.6446335, + "ast_hash": "abee1bb6fa8ed383e35018989a778302", + "semantic_hash": "" }, "D:\\Repositories\\server\\migrations\\versions\\c2e4f6a8b0c1_drop_embedding_model_version.py": { - "mtime": 1788411559.009362, - "ast_hash": "5ba30486e8a7362e83eecac30f75b409", - "semantic_hash": "5ba30486e8a7362e83eecac30f75b409" + "mtime": 1789266824.6456323, + "ast_hash": "01916ec30942638aac469c4c0ec1171a", + "semantic_hash": "" }, "D:\\Repositories\\server\\migrations\\versions\\d3df3fc5ca72_rename_memory_base_score.py": { - "mtime": 1788411559.0103703, - "ast_hash": "54e60df5ef93248db559f14c893547c8", + "mtime": 1789266824.6456323, + "ast_hash": "598b19c1d4efb7dccf7917244aa145ee", "semantic_hash": "" }, "D:\\Repositories\\server\\migrations\\versions\\d3e4f5a6b7c8_add_prometheus_sandboxes.py": { - "mtime": 1788411559.0113704, - "ast_hash": "35e7305edfc17a02ff36bb113761bead", - "semantic_hash": "35e7305edfc17a02ff36bb113761bead" + "mtime": 1789266824.6476328, + "ast_hash": "1cd806b72716facac6dbf7ec3e0bbe12", + "semantic_hash": "" }, "D:\\Repositories\\server\\migrations\\versions\\e4f5a6b7c8d9_fix_fulltext_index_prometheus_memories.py": { - "mtime": 1788411559.0113704, - "ast_hash": "bc73f85625cf67526ac60e7795d19d42", + "mtime": 1789266824.6476328, + "ast_hash": "9ae7aa16f3e81e913d533d84a9c932b9", "semantic_hash": "" }, "D:\\Repositories\\server\\migrations\\versions\\e5f6a7b8c9d0_drop_workspace_path_prometheus_sandboxes.py": { - "mtime": 1788411559.0123703, - "ast_hash": "30a8c784764a7660bccff313b95561bd", + "mtime": 1789266824.6491404, + "ast_hash": "4fbbe4a9ed6e05e3d20adb75447fab27", "semantic_hash": "" }, "D:\\Repositories\\server\\migrations\\versions\\f1a2b3c4d5e6_session_gc_index.py": { - "mtime": 1788411559.0123703, - "ast_hash": "987f65fe263d5cfa0cf4ed155f7d13d0", + "mtime": 1789266824.6491404, + "ast_hash": "f3a0b7e1b13ba540d0727d9a33da9a87", "semantic_hash": "" }, "D:\\Repositories\\server\\AGENTS.md": { - "mtime": 1788411558.9381454, - "ast_hash": "57ec88c5e3c30976589788f9c761d7bb", - "semantic_hash": "57ec88c5e3c30976589788f9c761d7bb" + "mtime": 1789266824.546347, + "ast_hash": "3ebebc033e590dc2507e972b310ffd49", + "semantic_hash": "" }, "D:\\Repositories\\server\\docker-compose.yml": { - "mtime": 1788457311.7157784, - "ast_hash": "10e0e54217c49c2f86c4a5f83ba93da5", + "mtime": 1789278227.9939115, + "ast_hash": "bd9e5bbd860519a0b71bbac1fb076084", "semantic_hash": "" }, "D:\\Repositories\\server\\forgevm.yaml": { - "mtime": 1788457329.2121491, + "mtime": 1789266824.5653808, "ast_hash": "061d7cea62f7e674af297ae3f858be8f", "semantic_hash": "" }, "D:\\Repositories\\server\\README.md": { - "mtime": 1788412160.9457698, - "ast_hash": "dd8a04494de59b18c3f7f146835b29a6", + "mtime": 1789266824.5528724, + "ast_hash": "eefffc81bc23e76d2429b5d93525910e", "semantic_hash": "" }, "D:\\Repositories\\server\\requirements.txt": { - "mtime": 1788645353.379248, - "ast_hash": "30c8b37aa441a613aada9cb1aa3bcca2", + "mtime": 1789266824.6521552, + "ast_hash": "ca468b8c46eaec66585c6626007b2e6a", "semantic_hash": "" }, "D:\\Repositories\\server\\TODO.md": { - "mtime": 1788411558.9471855, - "ast_hash": "ff368c91036eb9ee29ad305e41f10d0f", + "mtime": 1789266936.1947691, + "ast_hash": "51f406e95762c717c42d8dbb9c339b63", "semantic_hash": "" }, "D:\\Repositories\\server\\docs\\authentication.md": { - "mtime": 1788411558.9496932, - "ast_hash": "4bb9520f798f1e8099876c0a37b2e094", - "semantic_hash": "4bb9520f798f1e8099876c0a37b2e094" + "mtime": 1789266824.5593731, + "ast_hash": "49c929ebabc766625ade6dd121a02e00", + "semantic_hash": "" }, "D:\\Repositories\\server\\docs\\prometheus.md": { - "mtime": 1788411558.950699, - "ast_hash": "660fe9d73ed859b5519b8d101ab7e8c8", + "mtime": 1789266824.5603762, + "ast_hash": "8f58627eb4b1d6e8a58812524cc8b52b", "semantic_hash": "" }, "D:\\Repositories\\server\\docs\\scraper_b3.md": { - "mtime": 1788411558.9516976, - "ast_hash": "ccbb225536b4d4c360299cf8c78930b1", + "mtime": 1789266824.5613787, + "ast_hash": "e738bb4fb21995b73d648082cd771e05", "semantic_hash": "" }, "D:\\Repositories\\server\\docs\\stocks_api.md": { - "mtime": 1788411558.9516976, - "ast_hash": "6afe306d6f58a591bd485bfef2254450", + "mtime": 1789266824.5623827, + "ast_hash": "d7930d24514eda65501444d29b96ab9a", "semantic_hash": "" }, "D:\\Repositories\\server\\docs\\user.md": { - "mtime": 1788411558.9526975, - "ast_hash": "a747b8dce6f5be90f82ace23efd8961a", - "semantic_hash": "a747b8dce6f5be90f82ace23efd8961a" + "mtime": 1789266824.5653808, + "ast_hash": "fd513cedaa40e0d9719ff106ce363256", + "semantic_hash": "" }, "D:\\Repositories\\server\\docs\\superpowers\\plans\\2026-08-09-sse-resume.md": { "mtime": 1786286515.2616172, @@ -615,7 +615,7 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\docs\\superpowers\\specs\\2026-09-04-wallet-design.md": { - "mtime": 1788578240.0062113, + "mtime": 1789266824.564381, "ast_hash": "3ad505fd6016388f87bd14fa8da4f40e", "semantic_hash": "" }, diff --git a/main/app/prometheus/agent.py b/main/app/prometheus/agent.py index e6c18de..98f02a6 100644 --- a/main/app/prometheus/agent.py +++ b/main/app/prometheus/agent.py @@ -9,7 +9,6 @@ from google.genai import types import google.genai._mcp_utils as mcp - from main.models.prometheus import PrometheusSession from main.app.prometheus.memory import PrometheusMemory from main.app.prometheus.chat import PrometheusChatManager diff --git a/main/app/prometheus/mcp.py b/main/app/prometheus/mcp.py index a04d8f8..912a3b2 100644 --- a/main/app/prometheus/mcp.py +++ b/main/app/prometheus/mcp.py @@ -3,20 +3,8 @@ import time import asyncio -Client = None -StreamableHttpTransport = None - - -def ensureFastmcp(): - global Client, StreamableHttpTransport - if Client is None or StreamableHttpTransport is None: - from fastmcp import Client as FastmcpClient - from fastmcp.client.client import StreamableHttpTransport as FastmcpTransport - - Client = FastmcpClient - StreamableHttpTransport = FastmcpTransport - return Client, StreamableHttpTransport - +from fastmcp import Client +from fastmcp.client.client import StreamableHttpTransport logger = logging.getLogger(__name__) @@ -31,12 +19,11 @@ def ensureFastmcp(): def buildClient(server): - clientCls, transportCls = ensureFastmcp() url = server["url"] headers = server.get("headers", {}) if headers: - return clientCls(transport=transportCls(url, headers=headers)) - return clientCls(url) + return Client(transport=StreamableHttpTransport(url, headers=headers)) + return Client(url) class MCPClientPool: diff --git a/main/app/scraper_b3/scraper.py b/main/app/scraper_b3/scraper.py index 76bb8e7..7962d34 100644 --- a/main/app/scraper_b3/scraper.py +++ b/main/app/scraper_b3/scraper.py @@ -17,7 +17,7 @@ from sqlalchemy import text -from .xango import calculateInvestingScore +from xango import calculateInvestingScore JSON_COLUMNS = ("COTACAO 10Y PADRAO", "COTACAO 10Y AJUSTADA", "HISTORICO DIVIDENDOS", "NOTICIAS") From 64f735fcbbfccd02d1f3c81aede98dbbb954ca6c Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 02:26:46 -0300 Subject: [PATCH 21/57] make feather cache build reconnect safe on mysql lost connection retry transient 2013 mid-stream up to 3 attempts with backoff and engine dispose; keep fcntl plus subprocess isolation (multi-instance safe, builds idempotent via tmp plus atomic replace plus skip-if-locked) --- main/app/stocks_api/cache.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/main/app/stocks_api/cache.py b/main/app/stocks_api/cache.py index 22d9d57..ba341d0 100644 --- a/main/app/stocks_api/cache.py +++ b/main/app/stocks_api/cache.py @@ -9,6 +9,7 @@ import pyarrow as pa from sqlalchemy.engine import Engine +from sqlalchemy.exc import OperationalError import os import subprocess # nosec: B404 used only with constant args, see line 302 @@ -66,7 +67,7 @@ def arrowTypeFor(dbType: str): return pa.string() -def buildFeatherCache(engine: Engine | None = None): +def buildFeatherCache(engine: Engine | None = None, _attempt: int = 0): sampleCols = None sampleParts: dict[str, pd.Series] = {} compressor = zstd.ZstdCompressor(level=3) @@ -135,6 +136,17 @@ def buildFeatherCache(engine: Engine | None = None): result.close() except Exception: pass # nosec: B110 best-effort writer/sink close, retried next refresh + except OperationalError as e: + if _attempt >= 2: + raise + logger.warning(f"feather build lost connection (attempt {_attempt + 1}/3), retrying with fresh connection") + try: + resolvedEngine.dispose() + except Exception: + pass + time.sleep(2**_attempt) + buildFeatherCache(engine, _attempt + 1) + return finally: if writer is not None: writer.close() From 236df8cf9d074c8a2c0c7f02ea1f5e8ecb8e2502 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 02:28:18 -0300 Subject: [PATCH 22/57] delete write_bytes helper keeping write_file --- PONYTAIL.md | 90 +++++++++++++++++++++++++++++++++ main/app/prometheus/sandbox.py | 18 ++----- tests/test_sandbox_workspace.py | 8 +-- 3 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 PONYTAIL.md diff --git a/PONYTAIL.md b/PONYTAIL.md new file mode 100644 index 0000000..8b2e2b0 --- /dev/null +++ b/PONYTAIL.md @@ -0,0 +1,90 @@ +# PONYTAIL.md — proposed cuts, NOT applied. Approve before any edit. + +Status: PROPOSAL. Nothing below is cut. Reply approve (all / by line) or reject. +Format: ` . . [path]`. Ranked biggest cut first. + +## Proposed (awaiting approval) + +delete Merge test_prometheus_auth_coverage.py into resume/streammessage/controller/session tests; keep one file per area. [tests/test_prometheus_auth_coverage.py] (~450) +shrink Replace make_*_client helpers + per-test FastAPI builds with conftest fixtures. [tests/test_controllers_coverage.py] (~250) +shrink Collapse 5x make_manager/make_stocks_df helpers + overlapping query cases into shared helpers + parametrized cases. [tests/test_stocks_api_coverage.py] (~250) +shrink Parametrize single-assert guard classes into tables. [tests/test_stocks_compress.py] (~150) +delete Delete test_stocks_util.py; identical cases live in test_stocks_api_util_coverage.py. [tests/test_stocks_util.py] (~99) +stdlib Delete test_pagination.py dummy /items app; re-tests FastAPI validation, not app code. [tests/test_pagination.py] (~85) +shrink Extract repeated quota-update statement into one helper; 7 tests copy it. [tests/test_api_key_quota_atomic.py] (~80) +delete Delete TestMemoryToolFunctions/TestToolRegistry dupes; identical asserts in test_prometheus_tools.py. [tests/test_memory_tools_wiring.py] (~75) +shrink Parametrize decay-formula cases into one table. [tests/test_relevance_score.py] (~60) +shrink Parametrize one-liner mock chains via shared mockDb factory + tables. [tests/test_compact.py] (~55) +delete Merge TestConcurrentGetSession into TestGetSession; delete test_http_session_coverage.py. [tests/test_http_session_coverage.py] (~50) +shrink Triple appendHistory try/except; extract _persistEvent(db, sessionId, entry). [main/app/prometheus/agent.py] (~35) +stdlib logging.handlers QueueHandler/QueueListener replaces hand deque+Lock+Event+thread queue. [main/utils/logging_config.py] (~25) +shrink Move duplicated mock_forgevm() into conftest.py. [tests/test_sandbox.py] (~20) +delete Dual lru_cache getAbbr/getNest + rebuildAbbrevs + function-local import; compute inline. [main/app/stocks_api/compress.py] (~18) +stdlib Delete TestEbbinghausRetention; asserts math.exp() not app behavior. [tests/test_memory_maintenance.py] (~15) +delete CACHE_NESTED_PATH/sampleParts/sampleCols/nestedSample plumbing; sample the loaded frame. [main/app/stocks_api/cache.py] (~15) +shrink Duplicate existing/similar update blocks in upsertMemory; extract _touch helper. [main/app/prometheus/memory.py] (~14) +delete Lossy SUF suffixes + DF/DI year-stripping in compactValue; keep float rounding. [main/app/stocks_api/compress.py] (~14) +yagni Delete inspect.getsource text-scan test; asserts source absence not behavior. [tests/test_agent_sandbox_integration.py] (~13) +delete getHistoricalFields/getFundamentalColumns/invalidateFieldData; zero callers. [main/app/prometheus/compact.py] (~12) +shrink scoreRecency/scoreCandidates identical dict shape; extract _scoreRow. [main/app/prometheus/memory.py] (~12) +native Coverage-threshold inline XML parse; use coverage report --fail-under=80. [ci.ps1] (~12) +yagni StocksQueryManager single-instance class + snapshot() fallback; module functions suffice. [main/app/stocks_api/query.py] (~12) +delete getDeviceName + device/browser/os keys; createSession never populates them, always None. [main/app/authentication/session.py] (~11) +delete try/except ImportError fallback + comment block; raw import per project rule. [main/models/user.py:20-29] (~10) +yagni matrixKey/matrixUserTag single-use helpers; inline f-strings. [main/app/prometheus/memory.py] (~10, verify — may be gone post-P1) +stdlib parseDate/parseDateRange calendar logic; datetime.date.fromisoformat covers it. [main/app/stocks_api/util.py] (~10) +shrink Hand-rolled mypy capture block; use existing Run-Check. [ci.ps1] (~10) +shrink isSecureScheme try/except+split into one expression. [main/controller/authentication_controller.py] (~7) +shrink Logout token block; call extractTokenPayload. [main/controller/authentication_controller.py] (~7) +shrink Auto-fix triple ruff invocation; single ruff check --fix. [ci.ps1] (~8) +shrink loadFieldData isinstance branching; one-liner coercions. [main/app/prometheus/compact.py] (~8) +shrink Migrator chdir dance; pass cwd= to subprocess.run. [main/utils/migrator.py] (~6) +yagni FALLBACK_METRIC_RE + extractMetrics useRegistry param; sole caller passes True. [main/app/prometheus/compact.py] (~6) +delete forgevm.yaml defaults: block; app passes all four explicitly. [forgevm.yaml] (~6) +shrink initialize/reconnect duplicate steps; extract _connect. [main/app/prometheus/mcp.py] (~6) +stdlib orjson→json fallback + sniffing in deserializeJsonColumns; orjson-only. [main/app/stocks_api/query.py] (~6) +shrink buildTickerIndex loop + sortCacheFrame try/except; dict comprehension + single sort_values. [main/app/stocks_api/cache.py] (~6) +shrink createAccessToken tuple return; all callers discard 2nd element. [main/app/authentication/util.py] (~5) +delete decodeEmbeddings non-bytes branch; sole caller passes bytes only. [main/app/prometheus/vector.py] (~5) +delete exceptSessionId param + branch in revokeAllSessions; sole caller passes None. [main/app/authentication/session.py] (~4) +shrink checkServiceConnection double-except; collapse to one. [main/utils/connectivity.py] (~4) +shrink getMatrix redundant asyncio.run get after set; return fresh values. [main/app/prometheus/memory.py] (~4) +shrink countTokensCached one-line wrapper; inline. [main/app/prometheus/memory.py] (~4) +delete stocks-cache:/app/cache mount + volumes entry; .:/app bind covers it. [docker-compose.yml] (~3) +delete Unused StocksApiSettings KEY/DEFAULT_QUOTA/QUOTA_RESETDAYS fields. [config.py] (~3) - soon to be implemented, keep the KEY and consider removing the DEFAULT_QUOTA/QUOTA_RESETDAYS +delete includeInactive param + branch in getUserSessions; never True. [main/app/authentication/session.py] (~3) +shrink queryHistorical/queryFundamental/queryCotations triple blocks; one validateFields + envelope helper. [main/app/stocks_api/query.py] (~30) +delete TestSessionExpiryConfig; covered by TestSessionExpiration in test_sessions.py. [tests/test_auth_util.py] (~30) +delete --mount=type=cache paired with --no-cache-dir; keep one mechanism. [Dockerfile] (~2) +delete Unused import asyncio. [run.py] (~1) +delete mcp==1.29.0 pin; zero direct imports, transitive-only. [requirements.txt] (~1) + +Net proposed: ~2,200 lines + 1 dependency (mcp pin). + +## Disputed (already litigated — needs your ruling to proceed) + +shrink toColumnar/walk/fixHeaders generic h/d pipe-encoding; keep compactCotations nested h/d for cotation series (Alt C: gzip saves transport bytes, pipe-encoding saves LLM tokens — orthogonal). [main/app/stocks_api/compress.py] (~40) +delete sync_cache.py wrapper; use cashews @cache directly. [main/app/stocks_api/sync_cache.py] (~31) — you blessed shrink-only. (keep the decorator, refused or find a way to make @caceh async, dont create helper functions to make it work properly, the @cache should go above the controller func, not a different func at this case) +delete subprocess.run self-spawn + fcntl lock; direct build in thread. [main/app/stocks_api/cache.py] (~28) — restored deliberately (OOM risk). (building in the thread wouldnt stall the entire operation and also, if im running more than one instance of the server, they could clash or idk) +delete SandboxManager.write_bytes. [main/app/prometheus/sandbox.py] (~10) — restored, 3 workspace tests call it. (delete it, keep only write_file) +delete toVectorString/fromVectorString converters. [main/app/prometheus/vector.py] (~14) — kept for MySQL 9 compat read path. (consider making a plan to upgrade the mysql version in the container to 9 then afterwards, so we can properly replace it. keep for the last, after every change has been implemenmted) + +## Held out (your ignore rules — not proposed) + +shrink 10 repetitive try/except-nan blocks into one safe() helper. [main/app/scraper_b3/scraper.py] (~35) — scraper.py ignored. +delete historicalCotationProfits_Oceans14 + task slot. [main/app/scraper_b3/scraper.py] (~13) — scraper.py ignored. +shrink tagAlong triple-fallback regex into single pattern. [main/app/scraper_b3/scraper.py] (~6) — scraper.py ignored. + +## Refused + +delete Abbreviation engine autoAbbreviate/dedupAbbrev/generateAbbreviations/detectNestedFields; return full names, gzip covers size. [main/app/stocks_api/util.py] (~55) - the abbreviations serve the porpouse of compressing token outputs for ai agents that use the MCP for the stocks api +delete Manual pa.schema build + arrowTypeFor; pa.Table.from_pandas infers types. [main/app/stocks_api/cache.py] (~20) - possible negative performance outcomes +shrink search_memory/save_memory duplicate SessionLocal blocks; extract _withDb. [main/app/prometheus/tools.py] (~10) - bloated simplification +delete SessionManager.updateLastActive; zero callers. [main/app/authentication/session.py] (~8) - the api/frontend should log when a user is active and update this param so the /sessions track the current situation of user sessions +delete Manual Docker Compose curl-install; runners ship docker compose. [.github/workflows/ci.yml] (~5) - working well enough, dont change +shrink Single-entry strategy.matrix; hardcode python-version. [.github/workflows/ci.yml] (~4) - working well enough, dont change +shrink Two pip install steps in builder; merge into one. [Dockerfile] (~3) - working well enough, dont change +delete Duplicate Show API logs step; container-logs step covers it. [.github/workflows/ci.yml] (~3) - working well enough, dont change +delete DEVELOPER_STARTER/DEVELOPER_ENTERPRISE aliases; both equal USER, never assigned. [main/utils/roles.py] (~3) - keep, going to be implemented soon +delete Heredoc docker-compose.ci.yml; reuse root compose with env overrides. [.github/workflows/ci.yml] (~28) - working well enough, dont change +shrink Triple-3200 api port mappings; distinct defaults or one mapping. [docker-compose.yml] (~2) - working well enough, dont change \ No newline at end of file diff --git a/main/app/prometheus/sandbox.py b/main/app/prometheus/sandbox.py index c7f0c51..7beecbd 100644 --- a/main/app/prometheus/sandbox.py +++ b/main/app/prometheus/sandbox.py @@ -172,11 +172,14 @@ def read_file(userId: int, path: str) -> str: return host.read_text(encoding="utf-8") @staticmethod - def write_file(userId: int, path: str, content: str) -> bool: + def write_file(userId: int, path: str, content: str | bytes) -> bool: try: host = hostPath(userId, path) host.parent.mkdir(parents=True, exist_ok=True) - host.write_text(content, encoding="utf-8") + if isinstance(content, bytes): + host.write_bytes(content) + else: + host.write_text(content, encoding="utf-8") return True except Exception as e: logger.warning("Failed to write %s: %s", path, e) @@ -190,17 +193,6 @@ def list_files(userId: int, path: str = "/workspace") -> dict: entries = [str(sandboxPath(item, userId)) for item in sorted(host.rglob("*")) if item.is_file()] return {"entries": entries} - @staticmethod - def write_bytes(userId: int, path: str, content: bytes) -> bool: - try: - host = hostPath(userId, path) - host.parent.mkdir(parents=True, exist_ok=True) - host.write_bytes(content) - return True - except Exception as e: - logger.warning("Failed to write %s: %s", path, e) - return False - @staticmethod def delete_file(userId: int, path: str) -> bool: try: diff --git a/tests/test_sandbox_workspace.py b/tests/test_sandbox_workspace.py index 6fae6e1..4c53d88 100644 --- a/tests/test_sandbox_workspace.py +++ b/tests/test_sandbox_workspace.py @@ -1,4 +1,4 @@ -"""Tests for SandboxManager file mutation helpers (delete_file, write_bytes).""" +"""Tests for SandboxManager file mutation helpers (delete_file, write_file).""" from pathlib import Path from unittest.mock import patch @@ -17,17 +17,17 @@ def workspace(tmp_path, monkeypatch): class TestWriteBytes: def test_writes_binary_content(self, workspace): - ok = SandboxManager.write_bytes(1, "/workspace/data.bin", b"\x00\x01\x02") + ok = SandboxManager.write_file(1, "/workspace/data.bin", b"\x00\x01\x02") assert ok is True assert (workspace / "1" / "data.bin").read_bytes() == b"\x00\x01\x02" def test_creates_parent_dirs(self, workspace): - ok = SandboxManager.write_bytes(1, "/workspace/reports/q1.csv", b"a,b\n") + ok = SandboxManager.write_file(1, "/workspace/reports/q1.csv", b"a,b\n") assert ok is True assert (workspace / "1" / "reports" / "q1.csv").exists() def test_rejects_traversal(self, workspace): - ok = SandboxManager.write_bytes(1, "/workspace/../../evil.txt", b"x") + ok = SandboxManager.write_file(1, "/workspace/../../evil.txt", b"x") assert ok is False assert not (workspace / "evil.txt").exists() From 551242d4f4bd33cdf190159853f1b5d99ff07ee1 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 02:30:41 -0300 Subject: [PATCH 23/57] make sync cache decorator async capable --- main/app/stocks_api/sync_cache.py | 11 +++++++---- main/controller/stocksapi_controller.py | 10 +++++----- tests/test_sync_cache.py | 16 ++++++++-------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/main/app/stocks_api/sync_cache.py b/main/app/stocks_api/sync_cache.py index f52bde9..f625175 100644 --- a/main/app/stocks_api/sync_cache.py +++ b/main/app/stocks_api/sync_cache.py @@ -1,8 +1,9 @@ import asyncio +import inspect from functools import wraps from typing import Any, Callable, TypeVar -from cashews import cache +from cashews import cache as cashewsCache from cashews.key import get_cache_key MISS = object() @@ -10,18 +11,20 @@ F = TypeVar("F", bound=Callable[..., Any]) -def sync_cache(ttl: str, key: str) -> Callable[[F], F]: +def cache(ttl: str, key: str) -> Callable[[F], F]: def decorator(func: F) -> F: @wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: cache_key = get_cache_key(func, key, args, kwargs) async def cachedCall() -> Any: - cached = await cache.get(cache_key, default=MISS) + cached = await cashewsCache.get(cache_key, default=MISS) if cached is not MISS: return cached result = func(*args, **kwargs) - await cache.set(cache_key, result, expire=ttl) + if inspect.isawaitable(result): + result = await result + await cashewsCache.set(cache_key, result, expire=ttl) return result return asyncio.run(cachedCall()) diff --git a/main/controller/stocksapi_controller.py b/main/controller/stocksapi_controller.py index 0f73ba9..2b25bf1 100644 --- a/main/controller/stocksapi_controller.py +++ b/main/controller/stocksapi_controller.py @@ -10,7 +10,7 @@ from main.app.stocks_api.util import categorizeColumns, generateAbbreviations from main.app.stocks_api.compress import compressResponse, getNest from main.app.stocks_api.cache import stocksCache -from main.app.stocks_api.sync_cache import sync_cache +from main.app.stocks_api.sync_cache import cache logger = logging.getLogger(__name__) @@ -81,7 +81,7 @@ def listFields(): @router.get("/historical", operation_id="get_historical", response_class=ORJSONResponse) -@sync_cache(ttl="1h", key="stocks:historical:{search}:{fields}:{dates}:{orderBy}:{limit}:{compact}") +@cache(ttl="1h", key="stocks:historical:{search}:{fields}:{dates}:{orderBy}:{limit}:{compact}") def getHistorical( response: Response, search: str = Query(None, max_length=3780, pattern=r"^[A-Za-z0-9,\s]*$"), @@ -146,7 +146,7 @@ def getHistorical( @router.get("/fundamental", operation_id="get_fundamental", response_class=ORJSONResponse) -@sync_cache(ttl="5m", key="stocks:fundamental:{search}:{fields}:{dates}:{orderBy}:{limit}:{compact}") +@cache(ttl="5m", key="stocks:fundamental:{search}:{fields}:{dates}:{orderBy}:{limit}:{compact}") def getFundamental( response: Response, search: str = Query(None, max_length=3780, pattern=r"^[A-Za-z0-9,\s]*$"), @@ -216,7 +216,7 @@ def getFundamental( @router.get("/cotations", operation_id="get_cotations", response_class=ORJSONResponse) -@sync_cache(ttl="5m", key="stocks:cotations:{search}:{dates}:{adjusted}:{compact}") +@cache(ttl="5m", key="stocks:cotations:{search}:{dates}:{adjusted}:{compact}") def getCotations( response: Response, search: str = Query(..., min_length=1, max_length=3780, pattern=r"^[A-Za-z0-9,\s]*$"), @@ -272,7 +272,7 @@ def getCotations( @router.get("/cotations/live", operation_id="get_live_price", response_class=ORJSONResponse) -@sync_cache(ttl="15s", key="stocks:live:{search}:{compact}") +@cache(ttl="15s", key="stocks:live:{search}:{compact}") def getLiveCotation( response: Response, search: str = Query(..., min_length=1, max_length=7, pattern=r"^[A-Za-z0-9,\s]*$"), diff --git a/tests/test_sync_cache.py b/tests/test_sync_cache.py index 5565885..4256209 100644 --- a/tests/test_sync_cache.py +++ b/tests/test_sync_cache.py @@ -2,22 +2,22 @@ import orjson import pytest -from cashews import cache +from cashews import cache as cashewsCache -from main.app.stocks_api.sync_cache import sync_cache +from main.app.stocks_api.sync_cache import cache @pytest.fixture(scope="module", autouse=True) def setup_cache(): - cache.setup("mem://") + cashewsCache.setup("mem://") yield - asyncio.run(cache.clear()) + asyncio.run(cashewsCache.clear()) def test_hit_returns_cached_value_without_calling_func(): calls = [] - @sync_cache(ttl="1h", key="test:simple:{x}") + @cache(ttl="1h", key="test:simple:{x}") def fn(x): calls.append(x) return orjson.dumps({"x": x}) @@ -32,7 +32,7 @@ def fn(x): def test_distinct_args_get_distinct_cache_entries(): calls = [] - @sync_cache(ttl="1h", key="test:distinct:{x}") + @cache(ttl="1h", key="test:distinct:{x}") def fn(x): calls.append(x) return orjson.dumps({"x": x}) @@ -46,7 +46,7 @@ def fn(x): def test_params_not_in_template_are_excluded_from_key(): calls = [] - @sync_cache(ttl="1h", key="test:exclude:{x}") + @cache(ttl="1h", key="test:exclude:{x}") def fn(x, junk="ignored"): calls.append(x) return orjson.dumps({"x": x}) @@ -60,7 +60,7 @@ def fn(x, junk="ignored"): def test_exceptions_propagate_and_are_not_cached(): calls = [] - @sync_cache(ttl="1h", key="test:exc:{x}") + @cache(ttl="1h", key="test:exc:{x}") def fn(x): calls.append(x) raise ValueError("boom") From 5a7a72d545b29b5e9abbb44f1e538dc32aa74b2b Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 02:33:56 -0300 Subject: [PATCH 24/57] prune dead ci and docker config lines --- .github/workflows/ci.yml | 57 +++++++++++++++------------------------- Dockerfile | 3 +-- docker-compose.yml | 20 +++++++++----- 3 files changed, 35 insertions(+), 45 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad05334..05962e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -112,38 +112,23 @@ jobs: - name: Build Docker image run: docker build -t mansa-server:test . - - name: Create docker-compose.ci.yml for testing + - name: Export CI database credentials run: | - cat > docker-compose.ci.yml << 'EOF' - services: - db: - image: mysql:8.0 - environment: - MYSQL_ROOT_PASSWORD: ${{ secrets.USER_MYSQL_PASSWORD }} - MYSQL_DATABASE: ${{ secrets.USER_MYSQL_DATABASE }} - MYSQL_USER: ${{ secrets.USER_MYSQL_USER }} - MYSQL_PASSWORD: ${{ secrets.USER_MYSQL_PASSWORD }} - ports: - - "3306:3306" - - api: - image: mansa-server:test - ports: - - "8000:8000" - - "3200:3200" - environment: - USER_MYSQL_HOST: ${{ secrets.USER_MYSQL_HOST }} - USER_MYSQL_USER: ${{ secrets.USER_MYSQL_USER }} - USER_MYSQL_PASSWORD: ${{ secrets.USER_MYSQL_PASSWORD }} - USER_MYSQL_DATABASE: ${{ secrets.USER_MYSQL_DATABASE }} - STOCKS_MYSQL_HOST: ${{ secrets.STOCKS_MYSQL_HOST }} - STOCKS_MYSQL_USER: ${{ secrets.STOCKS_MYSQL_USER }} - STOCKS_MYSQL_PASSWORD: ${{ secrets.STOCKS_MYSQL_PASSWORD }} - STOCKS_MYSQL_DATABASE: ${{ secrets.STOCKS_MYSQL_DATABASE }} - DEBUG_MODE: "TRUE" - depends_on: - - db - EOF + echo "MYSQL_ROOT_PASSWORD=${{ secrets.USER_MYSQL_PASSWORD }}" >> $GITHUB_ENV + echo "MYSQL_DATABASE=${{ secrets.USER_MYSQL_DATABASE }}" >> $GITHUB_ENV + echo "MYSQL_USER=${{ secrets.USER_MYSQL_USER }}" >> $GITHUB_ENV + echo "MYSQL_PASSWORD=${{ secrets.USER_MYSQL_PASSWORD }}" >> $GITHUB_ENV + echo "USER_MYSQL_HOST=db" >> $GITHUB_ENV + echo "USER_MYSQL_USER=${{ secrets.USER_MYSQL_USER }}" >> $GITHUB_ENV + echo "USER_MYSQL_PASSWORD=${{ secrets.USER_MYSQL_PASSWORD }}" >> $GITHUB_ENV + echo "USER_MYSQL_DATABASE=${{ secrets.USER_MYSQL_DATABASE }}" >> $GITHUB_ENV + echo "STOCKS_MYSQL_HOST=db" >> $GITHUB_ENV + echo "STOCKS_MYSQL_USER=${{ secrets.STOCKS_MYSQL_USER }}" >> $GITHUB_ENV + echo "STOCKS_MYSQL_PASSWORD=${{ secrets.STOCKS_MYSQL_PASSWORD }}" >> $GITHUB_ENV + echo "STOCKS_MYSQL_DATABASE=${{ secrets.STOCKS_MYSQL_DATABASE }}" >> $GITHUB_ENV + echo "USER_PORT=3200" >> $GITHUB_ENV + echo "STOCKSAPI_PORT=3201" >> $GITHUB_ENV + echo "PROMETHEUS_PORT=3202" >> $GITHUB_ENV - name: Install Docker Compose run: | @@ -152,13 +137,13 @@ jobs: chmod +x ~/.docker/cli-plugins/docker-compose - name: Start services - run: docker compose -f docker-compose.ci.yml up -d + run: docker compose up -d db api - name: Wait for MySQL to be ready run: sleep 15 - name: Show container logs - run: docker compose -f docker-compose.ci.yml logs + run: docker compose logs - name: Check health endpoints run: | @@ -167,12 +152,12 @@ jobs: curl -f http://localhost:3200/user/health || echo "User health not available" - name: Show API logs (verify migrations ran) - run: docker compose -f docker-compose.ci.yml logs api + run: docker compose logs api - name: Show final container status if: always() - run: docker compose -f docker-compose.ci.yml ps + run: docker compose ps - name: Stop and remove containers if: always() - run: docker compose -f docker-compose.ci.yml down -v \ No newline at end of file + run: docker compose down -v \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index dad9443..08edd8c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,8 +8,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY requirements.txt . -RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --upgrade pip && \ +RUN pip install --upgrade pip && \ pip install --no-cache-dir --prefix=/install \ torch --index-url https://download.pytorch.org/whl/cpu && \ pip install --no-cache-dir --prefix=/install \ diff --git a/docker-compose.yml b/docker-compose.yml index 86dc99e..c3884fc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,10 +3,10 @@ services: image: mysql:8.0 restart: always environment: - MYSQL_ROOT_PASSWORD: password - MYSQL_DATABASE: mansa_db - MYSQL_USER: user - MYSQL_PASSWORD: password + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-password} + MYSQL_DATABASE: ${MYSQL_DATABASE:-mansa_db} + MYSQL_USER: ${MYSQL_USER:-user} + MYSQL_PASSWORD: ${MYSQL_PASSWORD:-password} ports: - "3306:3306" volumes: @@ -52,14 +52,20 @@ services: - DEBUG_MODE=TRUE - TZ=America/Sao_Paulo - FORGEVM_API_TOKEN=${FORGEVM_API_TOKEN:-} + - USER_MYSQL_HOST + - USER_MYSQL_USER + - USER_MYSQL_PASSWORD + - USER_MYSQL_DATABASE + - STOCKS_MYSQL_HOST + - STOCKS_MYSQL_USER + - STOCKS_MYSQL_PASSWORD + - STOCKS_MYSQL_DATABASE volumes: - .:/app - workspaces:/data/workspaces - - stocks-cache:/app/cache volumes: db_data: forgevm-data: - workspaces: - stocks-cache: \ No newline at end of file + workspaces: \ No newline at end of file From 12302b5a715445e236976749743ec4dc2a82f717 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 02:42:18 -0300 Subject: [PATCH 25/57] fix cache decorator shadowing cashews setup in stocks controller --- main/controller/stocksapi_controller.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/main/controller/stocksapi_controller.py b/main/controller/stocksapi_controller.py index 2b25bf1..26df5b2 100644 --- a/main/controller/stocksapi_controller.py +++ b/main/controller/stocksapi_controller.py @@ -10,7 +10,7 @@ from main.app.stocks_api.util import categorizeColumns, generateAbbreviations from main.app.stocks_api.compress import compressResponse, getNest from main.app.stocks_api.cache import stocksCache -from main.app.stocks_api.sync_cache import cache +from main.app.stocks_api.sync_cache import cache as endpointCache logger = logging.getLogger(__name__) @@ -81,7 +81,7 @@ def listFields(): @router.get("/historical", operation_id="get_historical", response_class=ORJSONResponse) -@cache(ttl="1h", key="stocks:historical:{search}:{fields}:{dates}:{orderBy}:{limit}:{compact}") +@endpointCache(ttl="1h", key="stocks:historical:{search}:{fields}:{dates}:{orderBy}:{limit}:{compact}") def getHistorical( response: Response, search: str = Query(None, max_length=3780, pattern=r"^[A-Za-z0-9,\s]*$"), @@ -146,7 +146,7 @@ def getHistorical( @router.get("/fundamental", operation_id="get_fundamental", response_class=ORJSONResponse) -@cache(ttl="5m", key="stocks:fundamental:{search}:{fields}:{dates}:{orderBy}:{limit}:{compact}") +@endpointCache(ttl="5m", key="stocks:fundamental:{search}:{fields}:{dates}:{orderBy}:{limit}:{compact}") def getFundamental( response: Response, search: str = Query(None, max_length=3780, pattern=r"^[A-Za-z0-9,\s]*$"), @@ -216,7 +216,7 @@ def getFundamental( @router.get("/cotations", operation_id="get_cotations", response_class=ORJSONResponse) -@cache(ttl="5m", key="stocks:cotations:{search}:{dates}:{adjusted}:{compact}") +@endpointCache(ttl="5m", key="stocks:cotations:{search}:{dates}:{adjusted}:{compact}") def getCotations( response: Response, search: str = Query(..., min_length=1, max_length=3780, pattern=r"^[A-Za-z0-9,\s]*$"), @@ -272,7 +272,7 @@ def getCotations( @router.get("/cotations/live", operation_id="get_live_price", response_class=ORJSONResponse) -@cache(ttl="15s", key="stocks:live:{search}:{compact}") +@endpointCache(ttl="15s", key="stocks:live:{search}:{compact}") def getLiveCotation( response: Response, search: str = Query(..., min_length=1, max_length=7, pattern=r"^[A-Za-z0-9,\s]*$"), From d75543495b943cf875475840947bf7324ab531e7 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 02:58:09 -0300 Subject: [PATCH 26/57] trim over-engineered prometheus helpers --- main/app/prometheus/agent.py | 73 ++++++++++++-------------- main/app/prometheus/compact.py | 31 ++--------- main/app/prometheus/mcp.py | 16 +++--- main/app/prometheus/memory.py | 95 +++++++++++++--------------------- main/utils/logging_config.py | 50 ++++++++---------- tests/test_compact.py | 14 +++-- 6 files changed, 117 insertions(+), 162 deletions(-) diff --git a/main/app/prometheus/agent.py b/main/app/prometheus/agent.py index 98f02a6..2f52cfc 100644 --- a/main/app/prometheus/agent.py +++ b/main/app/prometheus/agent.py @@ -28,6 +28,10 @@ def safeFilter(schema): return originalFilter(schema) +def persistEvent(db, sessionId, entry): + persistEvent(db, sessionId, {"type": "tool_result", "result": result}) + + mcp._filter_to_supported_schema = safeFilter logger = logging.getLogger(__name__) @@ -337,18 +341,15 @@ async def extract() -> None: yield {"type": "tool_call", "tool": fc.name, "args": fc.args or {}, "turn": turn} if sessionId: - try: - PrometheusChatManager.appendHistory( - db, - str(sessionId), - { - "role": "loop_event", - "eventType": "tool_call", - "metadata": {"toolName": fc.name, "args": fc.args or {}, "turn": turn}, - }, - ) - except Exception as e: - logger.error(f"Failed to persist tool_call event: {e}") + persistEvent( + db, + str(sessionId), + { + "role": "loop_event", + "eventType": "tool_call", + "metadata": {"toolName": fc.name, "args": fc.args or {}, "turn": turn}, + }, + ) if fc.name == "execute_code": try: @@ -376,18 +377,15 @@ async def extract() -> None: responses.append(types.Part.from_function_response(name=fc.name, response=result)) if sessionId: - try: - PrometheusChatManager.appendHistory( - db, - str(sessionId), - { - "role": "loop_event", - "eventType": "tool_result", - "metadata": {"toolName": fc.name, "result": result, "turn": turn}, - }, - ) - except Exception as e: - logger.error(f"Failed to persist tool_result event: {e}") + persistEvent( + db, + str(sessionId), + { + "role": "loop_event", + "eventType": "tool_result", + "metadata": {"toolName": fc.name, "result": result, "turn": turn}, + }, + ) history.append( { @@ -409,22 +407,19 @@ async def extract() -> None: } if sessionId: - try: - PrometheusChatManager.appendHistory( - db, - str(sessionId), - { - "role": "loop_event", - "eventType": "turn_end", - "metadata": { - "turnNumber": turn, - "durationMs": int(time.time() * 1000) - turn_start, - "toolsUsed": tools_used, - }, + persistEvent( + db, + str(sessionId), + { + "role": "loop_event", + "eventType": "turn_end", + "metadata": { + "turnNumber": turn, + "durationMs": int(time.time() * 1000) - turn_start, + "toolsUsed": tools_used, }, - ) - except Exception as e: - logger.error(f"Failed to persist turn_end event: {e}") + }, + ) turn += 1 stream = await chat.send_message_stream(responses) diff --git a/main/app/prometheus/compact.py b/main/app/prometheus/compact.py index fedcd5e..949a12e 100644 --- a/main/app/prometheus/compact.py +++ b/main/app/prometheus/compact.py @@ -18,8 +18,6 @@ FALLBACK_FIELDS = ("P/L", "P/VP", "ROE", "DY", "LPA", "VPA", "PRECO", "INVESTING SCORE") -FALLBACK_METRIC_RE = re.compile(r"\b(" + "|".join(re.escape(f) for f in FALLBACK_FIELDS) + r")\b") - DECISION_KEYWORDS = re.compile( r"(?:prefiro|prefere|quero|gostaria|sempre|nunca|quando|" r"não use|use ao invés|troque|prefira|defina|configure|" @@ -71,12 +69,7 @@ def loadFieldData() -> dict: response.raise_for_status() payload = response.json() historicalRaw = payload.get("historical", {}) - if isinstance(historicalRaw, dict): - historicalFields = list(historicalRaw.keys()) - elif isinstance(historicalRaw, list): - historicalFields = list(historicalRaw) - else: - historicalFields = [] + historicalFields = list(historicalRaw) if isinstance(historicalRaw, (dict, list)) else [] fundamentalRaw = payload.get("fundamental", []) fundamentalCols = list(fundamentalRaw) if isinstance(fundamentalRaw, list) else [] fieldData = {"historical": historicalFields, "fundamental": fundamentalCols} @@ -86,20 +79,6 @@ def loadFieldData() -> dict: return fieldData -def getHistoricalFields() -> list[str]: - return loadFieldData()["historical"] - - -def getFundamentalColumns() -> list[str]: - return loadFieldData()["fundamental"] - - -def invalidateFieldData(): - global fieldData, metricRegex - fieldData = None - metricRegex = None - - def getMetricRegex() -> re.Pattern: global metricRegex if metricRegex is None: @@ -122,10 +101,8 @@ def extractTickers(text: str) -> list[str]: return dedup(re.compile(r"\b([A-Z]{4}[0-9])\b").findall(text)) -def extractMetrics(text: str, useRegistry: bool = False) -> list[str]: - regex = getMetricRegex() if useRegistry else FALLBACK_METRIC_RE - - return dedup(regex.findall(text)) +def extractMetrics(text: str) -> list[str]: + return dedup(getMetricRegex().findall(text)) def extractDecisions(userMessages: list[dict]) -> list[str]: @@ -227,7 +204,7 @@ def extractEpisode(self, chunk: list[dict]) -> dict: allText = " ".join(m.get("content", "") for m in chunk if m.get("content")) tickers = extractTickers(allText) - metrics = extractMetrics(allText, useRegistry=True) + metrics = extractMetrics(allText) decisions = extractDecisions(userMessages) snapshots = extractSnapshots(toolResults) tools = extractToolCalls(loopEvents) diff --git a/main/app/prometheus/mcp.py b/main/app/prometheus/mcp.py index 912a3b2..c136732 100644 --- a/main/app/prometheus/mcp.py +++ b/main/app/prometheus/mcp.py @@ -26,6 +26,13 @@ def buildClient(server): return Client(url) +async def connect(server): + client = buildClient(server) + await client.__aenter__() + type(client.session).__deepcopy__ = lambda self, memo=None: self + return client + + class MCPClientPool: def __init__(self): self.clients = None @@ -37,10 +44,7 @@ async def initialize(self): for server in MCP_SERVERS: name = server["name"] try: - client = buildClient(server) - await client.__aenter__() - type(client.session).__deepcopy__ = lambda self, memo=None: self - clients[name] = client + clients[name] = await connect(server) logger.info("MCPClientPool: %s connected", name) except Exception as e: logger.error("MCPClientPool: %s connect failed: %s", name, e) @@ -77,9 +81,7 @@ async def reconnect(self, name): try: if name in self.clients: await self.clients[name].__aexit__(None, None, None) - new = buildClient(server) - await new.__aenter__() - type(new.session).__deepcopy__ = lambda self, memo=None: self + new = await connect(server) self.clients[name] = new logger.info("MCPClientPool: %s reconnected", name) except Exception as e: diff --git a/main/app/prometheus/memory.py b/main/app/prometheus/memory.py index 4709852..5bc0cf3 100644 --- a/main/app/prometheus/memory.py +++ b/main/app/prometheus/memory.py @@ -28,25 +28,18 @@ MATRIX_MISS = object() -def matrixKey(userId: Any) -> str: +def getMatrix(userId: Any, loader: Callable[[], tuple[list[int], np.ndarray]]) -> tuple[list[int], np.ndarray]: if isinstance(userId, tuple): uid, memoryType = userId - return f"matrix:{uid}:{memoryType}:v{1}" - return f"matrix:{userId}:v{1}" - - -def matrixUserTag(userId: Any) -> str: - uid = userId[0] if isinstance(userId, tuple) else userId - return f"matrix-user:{uid}" - - -def getMatrix(userId: Any, loader: Callable[[], tuple[list[int], np.ndarray]]) -> tuple[list[int], np.ndarray]: - cacheKey = matrixKey(userId) + cacheKey = f"matrix:{uid}:{memoryType}:v{1}" + else: + uid = userId + cacheKey = f"matrix:{userId}:v{1}" cached = asyncio.run(matrixCache.get(cacheKey, default=MATRIX_MISS)) if cached is not MATRIX_MISS: return cast(tuple[list[int], np.ndarray], cached) freshIds, freshMatrix = loader() - asyncio.run(matrixCache.set(cacheKey, (freshIds, freshMatrix), tags=("matrix", matrixUserTag(userId)))) + asyncio.run(matrixCache.set(cacheKey, (freshIds, freshMatrix), tags=("matrix", f"matrix-user:{uid}"))) return cast( tuple[list[int], np.ndarray], asyncio.run(matrixCache.get(cacheKey, default=(freshIds, freshMatrix))), @@ -127,20 +120,24 @@ def findSimilarKey(db: Session, userId: int, newKey: str, threshold: float = 0.8 return None +def scoreRow(m: Any, score: float, relevance: float, similarity: float) -> dict: + return { + "id": m.id, + "memoryKey": m.memoryKey, + "memoryValue": m.memoryValue, + "memoryType": m.memoryType, + "score": score, + "relevanceScore": relevance, + "similarity": similarity, + } + + def scoreRecency(candidateRows: list[Any], limit: int) -> list[dict]: now = datetime.now() - scored = [ - { - "id": m.id, - "memoryKey": m.memoryKey, - "memoryValue": m.memoryValue, - "memoryType": m.memoryType, - "score": getRelevanceScore(m, now), - "relevanceScore": getRelevanceScore(m, now), - "similarity": 0.0, - } - for m in candidateRows - ] + scored = [] + for m in candidateRows: + s = getRelevanceScore(m, now) + scored.append(scoreRow(m, s, s, 0.0)) scored.sort(key=lambda x: float(x["score"]), reverse=True) # type: ignore[arg-type] return scored[:limit] @@ -159,18 +156,7 @@ def scoreCandidates( f = 0.6 * v + 0.25 * ftRank.get(cast(int, m.id), 0.0) + 0.15 * rec fused.append((m, f, simById.get(cast(int, m.id), 0.0))) fused.sort(key=lambda p: p[1], reverse=True) - return [ - { - "id": m.id, - "memoryKey": m.memoryKey, - "memoryValue": m.memoryValue, - "memoryType": m.memoryType, - "score": f, - "relevanceScore": f, - "similarity": sim, - } - for m, f, sim in fused[:limit] - ] + return [scoreRow(m, f, f, sim) for m, f, sim in fused[:limit]] def sumTokens(texts: list[str], cache: dict | None) -> int: @@ -204,6 +190,17 @@ def countMemories(cls, db: Session, userId: int) -> int: .scalar() ) + @staticmethod + def touch(m: Any, value: str, memoryType: str, source: str, embedding: Any, newHash: str) -> None: + m.memoryValue = value # type: ignore[assignment] + m.memoryType = memoryType # type: ignore[assignment] + m.source = source # type: ignore[assignment] + m.contentHash = newHash # type: ignore[assignment] + m.embedding = embedding # type: ignore[assignment] + m.score = m.score * 1.1 # type: ignore[assignment] + m.accessCount += 1 # type: ignore[assignment] + m.lastAccessedAt = datetime.now() # type: ignore[assignment] + @classmethod def upsertMemory( cls, @@ -227,14 +224,7 @@ def upsertMemory( if existing.contentHash == newHash: return {"status": "unchanged", "memory": existing} - existing.memoryValue = value # type: ignore[assignment] - existing.memoryType = memoryType # type: ignore[assignment] - existing.source = source # type: ignore[assignment] - existing.contentHash = newHash # type: ignore[assignment] - existing.embedding = embedding # type: ignore[assignment] - existing.score = existing.score * 1.1 # type: ignore[assignment] - existing.accessCount += 1 # type: ignore[assignment] - existing.lastAccessedAt = datetime.now() # type: ignore[assignment] + cls.touch(existing, value, memoryType, source, embedding, newHash) db.commit() db.refresh(existing) @@ -244,14 +234,7 @@ def upsertMemory( similar = findSimilarKey(db, userId, key) if similar: - similar.memoryValue = value # type: ignore[assignment] - similar.memoryType = memoryType # type: ignore[assignment] - similar.source = source # type: ignore[assignment] - similar.contentHash = contentHash(value) # type: ignore[assignment] - similar.embedding = embedding # type: ignore[assignment] - similar.score = similar.score * 1.1 # type: ignore[assignment] - similar.accessCount += 1 # type: ignore[assignment] - similar.lastAccessedAt = datetime.now() # type: ignore[assignment] + cls.touch(similar, value, memoryType, source, embedding, contentHash(value)) db.commit() db.refresh(similar) @@ -446,10 +429,6 @@ def deleteMemory(cls, db: Session, userId: int, memoryId: int) -> bool: return True - @staticmethod - def countTokensCached(text: str, cache: dict | None) -> int: - return sumTokens([text], cache) - @staticmethod def extract( db: Session | None = None, userId=None, sessionId=None, userRoles=None, tokenCache: dict | None = None @@ -479,7 +458,7 @@ def extract( for msg in reversed(msgs): text = (msg.get("parts") or [{}])[0].get("text", "") acc.append(text) - tokens += PrometheusMemory.countTokensCached(text, tokenCache) + tokens += sumTokens([text], tokenCache) if tokens >= MEMORY_EXTRACTION_TOKEN_BUDGET: break diff --git a/main/utils/logging_config.py b/main/utils/logging_config.py index 78d4abf..b7bca33 100644 --- a/main/utils/logging_config.py +++ b/main/utils/logging_config.py @@ -1,8 +1,9 @@ import atexit import logging -import threading import time from collections import deque +from logging.handlers import QueueHandler, QueueListener +from queue import Queue import requests @@ -14,9 +15,7 @@ limiter = Limiter(key_func=get_remote_address) logger = logging.getLogger(__name__) -queue: deque[str] = deque() -lock = threading.Lock() -event = threading.Event() +discordQueue: Queue = Queue() def setupLogging(): @@ -35,6 +34,10 @@ def setupLogging(): class DiscordHandler(logging.Handler): + def __init__(self): + super().__init__() + self.recent: deque[str] = deque(maxlen=100) + def emit(self, record: logging.LogRecord): if record.levelno < logging.ERROR: return @@ -46,35 +49,28 @@ def emit(self, record: logging.LogRecord): if not Config.DISCORD.ENABLED or not Config.DISCORD.WEBHOOK_URL: return text = text[:1980] + "\n...[truncated]" if len(text) > 2000 else text - with lock: - if text not in queue: - queue.append(text) - event.set() + self.acquire() + try: + if text in self.recent: + return + self.recent.append(text) + finally: + self.release() + try: + requests.post(Config.DISCORD.WEBHOOK_URL, json={"content": text}, timeout=10) + except Exception: + pass # nosec: B110 per-message send failure swallowed, retried on next error + time.sleep(0.45) # ~5 msgs/2s, under discord rate limit def setupDiscordHandler(): if not (Config.DISCORD.ENABLED and Config.DISCORD.WEBHOOK_URL): return - def sender(): - while True: - event.wait() - event.clear() - while True: - with lock: - if not queue: - break - msg = queue.popleft() - try: - requests.post(Config.DISCORD.WEBHOOK_URL, json={"content": msg}, timeout=10) - except Exception: - pass # nosec: B110 per-message send failure swallowed, retried on next tick - time.sleep(0.45) # ~5 msgs/2s, under discord rate limit - - t = threading.Thread(target=sender, daemon=True, name="discord-sender") - t.start() - atexit.register(lambda: (event.set(), t.join(timeout=3))) - logging.getLogger().addHandler(DiscordHandler()) + listener = QueueListener(discordQueue, DiscordHandler()) + listener.start() + atexit.register(listener.stop) + logging.getLogger().addHandler(QueueHandler(discordQueue)) setupLogging() diff --git a/tests/test_compact.py b/tests/test_compact.py index 6aed002..824a6b7 100644 --- a/tests/test_compact.py +++ b/tests/test_compact.py @@ -51,7 +51,15 @@ def test_multiple_metrics(self): assert "DY" in result def test_cagr_metrics(self): - result = extractMetrics("INVESTING SCORE de 85 e DY de 12%") + oldField, oldRegex = compactMod.fieldData, compactMod.metricRegex + compactMod.fieldData = None + compactMod.metricRegex = None + with patch( + "main.app.prometheus.compact.loadFieldData", + return_value={"historical": [], "fundamental": []}, + ): + result = extractMetrics("INVESTING SCORE de 85 e DY de 12%") + compactMod.fieldData, compactMod.metricRegex = oldField, oldRegex assert "INVESTING SCORE" in result assert "DY" in result @@ -192,9 +200,7 @@ def test_extract_uses_field_registry(self): with patch("main.app.prometheus.compact.extractMetrics") as mockExtract: mockExtract.return_value = ["P/L", "ROE"] result = self.compactor.extractEpisode(chunk) - mockExtract.assert_called_once() - callArgs = mockExtract.call_args - assert callArgs[1].get("useRegistry") is True or callArgs[0][1] is True + mockExtract.assert_called_once_with("P/L de 5x e ROE 15%") def test_consolidate_under_cap(self): episodes = [{"id": f"ep_{i}", "summary": f"Episode {i}"} for i in range(5)] From 7e9e8da6ed1af7b1af919e51d5e3a842b439ba19 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 03:03:17 -0300 Subject: [PATCH 27/57] shrink cotation pipe-encoding to nested only --- main/app/stocks_api/compress.py | 47 ++++++------------- tests/test_stocks_compress.py | 80 +++------------------------------ 2 files changed, 20 insertions(+), 107 deletions(-) diff --git a/main/app/stocks_api/compress.py b/main/app/stocks_api/compress.py index dc7b041..09e3873 100644 --- a/main/app/stocks_api/compress.py +++ b/main/app/stocks_api/compress.py @@ -14,11 +14,11 @@ "PRECO MAXIMO": "PMX", "PRECO MEDIO": "PMD", } -COT = {"DATA": "D", "PRECO": "P"} SUF = [(1e12, "T"), (1e9, "B"), (1e6, "M"), (1e3, "K")] DF = re.compile(r"^\d{2}-\d{2}-(\d{4})$") DI = re.compile(r"^(\d{4})-\d{2}-\d{2}$") + @lru_cache(maxsize=1) def getAbbr() -> dict: if stocksCache.STOCKS_CACHE is not None: @@ -43,14 +43,6 @@ def rebuildAbbrevs() -> None: getNest.cache_clear() -def walk(data: Any, fn: Any) -> Any: - if isinstance(data, dict): - return {k: walk(v, fn) for k, v in data.items()} - if isinstance(data, list): - return [walk(item, fn) for item in data] - return fn(data) - - def compactValue(v: Any) -> Any: if isinstance(v, float): v = float(f"{v:.10g}") @@ -72,24 +64,6 @@ def compactValue(v: Any) -> Any: return v -def toColumnar(data: list) -> Any: - if len(data) < 2 or not isinstance(data[0], dict): - return data - keys = list(data[0].keys()) - if not all(list(row.keys()) == keys for row in data): - return data - return {"h": ",".join(keys), "d": ["|".join(str(row[k]) for k in keys) for row in data]} - - -def fixHeaders(obj: Any) -> None: - if isinstance(obj, dict): - for k, v in obj.items(): - if k == "h" and isinstance(v, str): - obj[k] = ",".join(COT.get(p.strip(), p.strip()) for p in v.split(",")) - elif isinstance(v, (dict, list)): - fixHeaders(v) - - def compactRow(row: dict, tool: str, abbrs: dict, nests: dict) -> dict: m, h, f = abbrs["meta"], abbrs["historical"], abbrs["fundamental"] out = {} @@ -124,12 +98,13 @@ def compactCotations(result: dict) -> dict: return result def toCol(cd: list) -> dict: + cot = {"DATA": "D", "PRECO": "P"} first = cd[0] if not isinstance(first, dict): return {"h": "v", "d": ["|".join(str(v) for v in x) for x in cd]} hdrs = list(first.keys()) return { - "h": ",".join(COT.get(h, h) for h in hdrs), + "h": ",".join(cot.get(h, h) for h in hdrs), "d": ["|".join(str(compactValue(x.get(h, ""))) for h in hdrs) for x in cd], } @@ -161,7 +136,7 @@ def compressResponse(raw: dict, tool: str, args: dict) -> dict: result.pop("type", None) if tool == "get_cotations": - result = compactCotations(result) + return compactCotations(result) elif tool == "get_live_price" and isinstance(result.get("data"), list): result["data"] = [ {PRICE.get(k, k): v for k, v in x.items()} if isinstance(x, dict) else x for x in result["data"] @@ -171,11 +146,15 @@ def compressResponse(raw: dict, tool: str, args: dict) -> dict: if isinstance(d, list) and d and isinstance(d[0], dict): abbrs, nests = getAbbr(), getNest() result["data"] = [compactRow(row, tool, abbrs, nests) for row in d] - result["data"] = walk(result["data"], compactValue) - if isinstance(result["data"], list) and result["data"]: - result["data"] = toColumnar(result["data"]) + + def compactLeaves(v: Any) -> Any: + if isinstance(v, dict): + return {k: compactLeaves(x) for k, x in v.items()} + if isinstance(v, list): + return [compactLeaves(x) for x in v] + return compactValue(v) + + result["data"] = compactLeaves(result["data"]) if isinstance(result["data"], list) and len(result["data"]) == 1: result["data"] = result["data"][0] - - fixHeaders(result) return result diff --git a/tests/test_stocks_compress.py b/tests/test_stocks_compress.py index d4f7a55..1a83df1 100644 --- a/tests/test_stocks_compress.py +++ b/tests/test_stocks_compress.py @@ -1,7 +1,7 @@ """Unit tests for main/app/stocks_api/compress.py. Covers the payload-compaction helpers used by the stocks MCP tools: -compactValue suffix/date logic, toColumnar, fixHeaders, compactRow, +compactValue suffix/date logic, compactRow, compactCotations, the compressResponse pipeline, and the lazy abbr/nest caches (getAbbr/getNest/rebuildAbbrevs). @@ -22,12 +22,9 @@ compactRow, compactValue, compressResponse, - fixHeaders, getAbbr, getNest, rebuildAbbrevs, - toColumnar, - walk, ) # Stub abbreviation/nesting tables for direct compactRow tests. @@ -99,71 +96,6 @@ def test_non_matching_string_unchanged(self): assert compactValue("15-06-202") == "15-06-202" -class TestWalk: - """walk: recursive dict/list transform.""" - - def test_recurses_dicts_and_lists(self): - assert walk({"a": [1, {"b": 2}], "c": 3}, lambda v: v * 2) == {"a": [2, {"b": 4}], "c": 6} - - def test_scalar_leaf(self): - assert walk("x", lambda v: v.upper()) == "X" - - -class TestToColumnar: - """toColumnar: passthrough guards + happy-path columnar output.""" - - def test_empty_list_unchanged(self): - assert toColumnar([]) == [] - - def test_single_row_unchanged(self): - data = [{"a": 1}] - assert toColumnar(data) == data - - def test_first_row_not_dict_unchanged(self): - data = [[1, 2], [3, 4]] - assert toColumnar(data) == data - - def test_mismatched_keys_unchanged(self): - data = [{"a": 1}, {"b": 2}] - assert toColumnar(data) == data - - def test_happy_path(self): - data = [{"a": 1, "b": "x"}, {"a": 2, "b": "y"}] - assert toColumnar(data) == {"h": "a,b", "d": ["1|x", "2|y"]} - - -class TestFixHeaders: - """fixHeaders: in-place COT remap of "h" headers.""" - - def test_remaps_cot_headers(self): - obj = {"h": "DATA,PRECO"} - fixHeaders(obj) - assert obj == {"h": "D,P"} - - def test_unknown_pieces_passthrough(self): - obj = {"h": "DATA,FOO"} - fixHeaders(obj) - assert obj == {"h": "D,FOO"} - - def test_nested_dict_value(self): - obj = {"inner": {"h": "PRECO"}} - fixHeaders(obj) - assert obj == {"inner": {"h": "P"}} - - def test_list_of_dicts_not_traversed(self): - # edge case: fixHeaders only recurses into dict values whose values - # are dicts; a list value is handed to fixHeaders, which is a no-op - # because the top-level isinstance(obj, dict) guard fails. - obj = {"rows": [{"h": "DATA"}]} - fixHeaders(obj) - assert obj == {"rows": [{"h": "DATA"}]} - - def test_non_str_h_value_untouched(self): - obj = {"h": 5} - fixHeaders(obj) - assert obj == {"h": 5} - - class TestCompactRow: """compactRow: meta/historical/fundamental abbreviation + nested handling.""" @@ -459,9 +391,11 @@ def test_get_live_price_data_not_list(self): raw = {"type": "get_live_price", "data": {"TICKER": "PETR4"}} assert compressResponse(raw, "get_live_price", {}) == {"data": {"TICKER": "PETR4"}} - def test_multi_row_columnar_with_fallback_abbrs(self): + def test_multi_row_list_of_dicts_with_fallback_abbrs(self): # cache absent: fallback abbrs have empty historical/fundamental, - # so "P/L" passes through unabbreviated. + # so "P/L" passes through unabbreviated. Multi-row results stay + # as a list of dicts (generic h/d pipe-encoding removed; only + # the nested cotation path uses h/d). raw = { "count": 2, "type": "get_fundamental", @@ -471,7 +405,7 @@ def test_multi_row_columnar_with_fallback_abbrs(self): ], } out = compressResponse(raw, "get_fundamental", {}) - assert out == {"data": {"h": "TK,P/L", "d": ["PETR4|5.2", "VALE3|6.5"]}} + assert out == {"data": [{"TK": "PETR4", "P/L": 5.2}, {"TK": "VALE3", "P/L": 6.5}]} def test_single_row_unwrapped_with_cache_abbrevs(self): df = pd.DataFrame({"TICKER": ["PETR4"], "P/L": [5.2]}) @@ -509,7 +443,7 @@ def test_get_historical_year_cols_with_cache_abbrevs(self): with patch.object(stocksCache, "STOCKS_CACHE", df): rebuildAbbrevs() out = compressResponse(raw, "get_historical", {"search": "PETR4", "dates": "2023,2024"}) - # note: walk(compactValue) suffixes int leaves, so year values become "50K"/"100K"; + # note: leaf compaction suffixes int leaves, so year values become "50K"/"100K"; # the single row is unwrapped from a list but stays under the "data" key assert out == { "data": { From d8595341d5f896190c7d1b587143f1385bd4e48f Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 03:52:27 -0300 Subject: [PATCH 28/57] trim over-engineered api auth and util helpers --- main/app/authentication/session.py | 19 +- main/app/authentication/util.py | 2 +- main/app/prometheus/agent.py | 9 +- main/app/stocks_api/query.py | 596 +++++++++---------- main/app/stocks_api/util.py | 5 +- main/controller/authentication_controller.py | 2 +- main/controller/stocksapi_controller.py | 10 +- main/controller/user_controller.py | 5 +- main/utils/connectivity.py | 6 +- main/utils/migrator.py | 8 +- run.py | 1 - tests/conftest.py | 108 ++++ tests/test_auth_util.py | 193 +++++- tests/test_controllers_coverage.py | 111 +--- tests/test_logout_cookie_domain.py | 2 +- tests/test_oauth_cookie_security.py | 2 +- tests/test_prometheus_auth_coverage.py | 22 +- tests/test_query_search_dates.py | 18 +- tests/test_query_snapshot.py | 21 +- tests/test_sessions.py | 268 +++++++-- tests/test_sso_state_cookie.py | 49 +- tests/test_stocks_api_coverage.py | 314 +++++----- tests/test_stocks_presorted.py | 14 +- 23 files changed, 1084 insertions(+), 701 deletions(-) diff --git a/main/app/authentication/session.py b/main/app/authentication/session.py index 82ef237..5c5b901 100644 --- a/main/app/authentication/session.py +++ b/main/app/authentication/session.py @@ -10,14 +10,6 @@ class SessionManager: - @staticmethod - def getDeviceName(session) -> str: - if session.browser and session.operatingSystem: - return f"{session.browser} on {session.operatingSystem}" - elif session.accessTokenHash: - return f"Device {session.accessTokenHash[:8]}" - return "Unknown Device" - @staticmethod def createSession( db: Session, @@ -50,10 +42,8 @@ def createSession( return session @staticmethod - def getUserSessions(db: Session, userId: int, includeInactive: bool = False, limit: int = 50) -> list[UserSession]: - query = db.query(UserSession).filter(UserSession.userId == userId) - if not includeInactive: - query = query.filter(UserSession.isActive) + def getUserSessions(db: Session, userId: int, limit: int = 50) -> list[UserSession]: + query = db.query(UserSession).filter(UserSession.userId == userId, UserSession.isActive) return query.order_by(UserSession.lastActivityAt.desc()).limit(limit).all() @staticmethod @@ -88,15 +78,12 @@ def revokeSession(db: Session, sessionId: str, userId: int) -> bool: return True @staticmethod - def revokeAllSessions(db: Session, userId: int, exceptSessionId: str | None = None) -> int: + def revokeAllSessions(db: Session, userId: int) -> int: query = db.query(UserSession).filter( UserSession.userId == userId, UserSession.isActive, ) - if exceptSessionId: - query = query.filter(UserSession.sessionId != exceptSessionId) - count = query.update({UserSession.isActive: False}, synchronize_session=False) db.commit() diff --git a/main/app/authentication/util.py b/main/app/authentication/util.py index 082b2a8..c6b6f93 100644 --- a/main/app/authentication/util.py +++ b/main/app/authentication/util.py @@ -38,7 +38,7 @@ def createAccessToken(data: dict | None, expiresDelta: timedelta | None = None): payload["exp"] = datetime.now(timezone.utc) + expiresDelta token = jwt.encode(payload, Config.USER.JWT_SECRET_KEY, algorithm="HS256") - return token, expiresDelta + return token def verifyAccessToken(token: str) -> dict: diff --git a/main/app/prometheus/agent.py b/main/app/prometheus/agent.py index 2f52cfc..94a9532 100644 --- a/main/app/prometheus/agent.py +++ b/main/app/prometheus/agent.py @@ -29,7 +29,10 @@ def safeFilter(schema): def persistEvent(db, sessionId, entry): - persistEvent(db, sessionId, {"type": "tool_result", "result": result}) + try: + PrometheusChatManager.appendHistory(db, str(sessionId), entry) + except Exception as e: + logger.error(f"Failed to persist event: {e}") mcp._filter_to_supported_schema = safeFilter @@ -430,8 +433,6 @@ async def extract() -> None: finally: if fullText: try: - PrometheusChatManager.appendHistory( - db, str(sessionId), {"role": "assistant", "content": fullText} - ) + PrometheusChatManager.appendHistory(db, str(sessionId), {"role": "assistant", "content": fullText}) except Exception as e: logger.error("Failed to persist assistant message: %s", e) diff --git a/main/app/stocks_api/query.py b/main/app/stocks_api/query.py index 7f07d72..05b6338 100644 --- a/main/app/stocks_api/query.py +++ b/main/app/stocks_api/query.py @@ -2,7 +2,6 @@ import zstandard as zstd from fastapi import HTTPException import pandas as pd -import json import orjson from main.utils.http_session import getSession @@ -51,315 +50,312 @@ def filterCotationColumn(series: pd.Series, startDate, endDate) -> pd.Series: return base -class StocksQueryManager: - def __init__(self, cacheManager): - self.cacheManager = cacheManager +def baseFrame(cacheManager=None): + cm = cacheManager if cacheManager is not None else stocksCache + snap = getattr(cm, "snapshot", None) + pair = snap() if callable(snap) else None + if isinstance(pair, tuple): + df, tickerIndex = pair + else: + df, tickerIndex = cm.STOCKS_CACHE, cm.tickerIndex + if df is None: + raise HTTPException(status_code=503, detail="Cache not initialized") + return df, tickerIndex + + +def validateFields(requested: str | None, available: list, typeName: str) -> list: + if not requested: + return list(available) + wanted = [f.strip() for f in requested.split(",") if f.strip()] + invalid = [f for f in wanted if f not in available] + if invalid: + raise HTTPException( + status_code=400, + detail=f"Invalid fields: {invalid}. Use /stocks/fields to discover available names.", + ) + return wanted + + +def envelope(search, fields, dates, typeName, df: pd.DataFrame): + return { + "search": search or "all", + "fields": fields, + "dates": dates, + "type": typeName, + "count": len(df), + "data": sanitizeNanValues(df.to_dict(orient="records")), + } + + +def finalize( + df: pd.DataFrame, + tickerIndex, + search: str | None, + orderBy: str | None, + limit: int | None, + cols: list[str] | None, + fields, + dates, + typeName: str, + dedupTickers: bool = False, + cotationCol: str | None = None, +): + if search: + df = filterBySearchTerms(df, search, tickerIndex) + if orderBy and orderBy in df.columns: + df = df.sort_values(by=orderBy, ascending=False) + if limit: + df = df.head(limit) + if cols is not None: + df = df[[c for c in cols if c in df.columns]] + if dedupTickers: + df = df.drop_duplicates(subset=["TICKER"], keep="first") + df = deserializeJsonColumns(df) + if "TIME" in df.columns: + df["TIME"] = pd.to_datetime(df["TIME"]).dt.strftime("%Y-%m-%d") + if cotationCol and cotationCol in df.columns: + startDate, endDate = parseDateRange(dates) + if startDate and endDate: + df[cotationCol] = filterCotationColumn(df[cotationCol], startDate, endDate) + return envelope(search, fields, dates, typeName, df) + + +def deserializeJsonColumns(df: pd.DataFrame) -> pd.DataFrame: + if df.empty: + return df - def baseFrame(self): - snap = getattr(self.cacheManager, "snapshot", None) - pair = snap() if callable(snap) else None - if isinstance(pair, tuple): - df, tickerIndex = pair - else: - df, tickerIndex = self.cacheManager.STOCKS_CACHE, self.cacheManager.tickerIndex - if df is None: - raise HTTPException(status_code=503, detail="Cache not initialized") - return df, tickerIndex - - def finalize( - self, - df: pd.DataFrame, - tickerIndex, - search: str | None, - orderBy: str | None, - limit: int | None, - cols: list[str] | None, - fields, - dates, - typeName: str, - dedupTickers: bool = False, - cotationCol: str | None = None, - ): - if search: - df = self.filterBySearchTerms(df, search, tickerIndex) - if orderBy and orderBy in df.columns: - df = df.sort_values(by=orderBy, ascending=False) - if limit: - df = df.head(limit) - if cols is not None: - df = df[[c for c in cols if c in df.columns]] - if dedupTickers: - df = df.drop_duplicates(subset=["TICKER"], keep="first") - df = self.deserializeJsonColumns(df) - if "TIME" in df.columns: - df["TIME"] = pd.to_datetime(df["TIME"]).dt.strftime("%Y-%m-%d") - if cotationCol and cotationCol in df.columns: - startDate, endDate = parseDateRange(dates) - if startDate and endDate: - df[cotationCol] = filterCotationColumn(df[cotationCol], startDate, endDate) - return { - "search": search or "all", - "fields": fields, - "dates": dates, - "type": typeName, - "count": len(df), - "data": sanitizeNanValues(df.to_dict(orient="records")), - } - - def deserializeJsonColumns(self, df: pd.DataFrame) -> pd.DataFrame: - if df.empty: - return df - - df = df.copy() - - def parseJSON(x, decompressor): - if isinstance(x, bytes): - x = decompressor.decompress(x).decode("utf-8") - try: - return orjson.loads(x) - except (ValueError, TypeError): - return json.loads(x) - - decompressor = zstd.ZstdDecompressor() - for col in df.columns: - if col in JSON_COLUMNS and (df[col].dtype == "object" or pd.api.types.is_string_dtype(df[col])): - df[col] = df[col].apply( - lambda x: ( - sanitizeNanValues(parseJSON(x, decompressor)) - if (isinstance(x, str) and x.startswith(("{", "["))) or isinstance(x, bytes) - else sanitizeNanValues(x) - ) + df = df.copy() + + def parseJSON(x, decompressor): + if isinstance(x, bytes): + x = decompressor.decompress(x).decode("utf-8") + try: + return orjson.loads(x) + except (ValueError, TypeError): + return x + + decompressor = zstd.ZstdDecompressor() + for col in df.columns: + if col in JSON_COLUMNS and (df[col].dtype == "object" or pd.api.types.is_string_dtype(df[col])): + df[col] = df[col].apply( + lambda x: ( + sanitizeNanValues(parseJSON(x, decompressor)) + if (isinstance(x, str) and x.startswith(("{", "["))) or isinstance(x, bytes) + else sanitizeNanValues(x) ) + ) + + return df + +def filterBySearchTerms(df: pd.DataFrame, search: str, index: dict | None = None) -> pd.DataFrame: + if not search: return df - def filterBySearchTerms(self, df: pd.DataFrame, search: str, index: dict | None = None) -> pd.DataFrame: - if not search: - return df - - searchTerms = [s.strip().upper() for s in search.split(",") if s.strip()] - if not searchTerms: - return df - - lookup = index if index is not None else self.cacheManager.tickerIndex - upperTickers = df["TICKER"].str.upper() - exactSet = {t for t in searchTerms if lookup and t in lookup} - prefixTerms = tuple(t for t in searchTerms if t not in exactSet) - exactMask = upperTickers.isin(exactSet) - if prefixTerms: - return df[exactMask | upperTickers.str.startswith(prefixTerms)] - return df[exactMask] - - def queryHistorical( - self, - search: str | None = None, - fields: str | None = None, - dates: str | None = None, - orderBy: str | None = None, - limit: int | None = None, - ): - if not (search or fields or dates): - raise HTTPException(status_code=400, detail="at least one of search/fields/dates required") - df, tickerIndex = self.baseFrame() + searchTerms = [s.strip().upper() for s in search.split(",") if s.strip()] + if not searchTerms: + return df - try: - availableColumns = df.columns.tolist() - availableColumnsSet = set(availableColumns) - historicalFields, _ = categorizeColumns(availableColumns) - - if not historicalFields: - raise HTTPException(status_code=400, detail="No historical data available in cache") - - fieldListAvailable = sorted(historicalFields.keys()) - if fields: - requested = [f.strip() for f in fields.split(",") if f.strip()] - invalid = [f for f in requested if f not in fieldListAvailable] - if invalid: - raise HTTPException( - status_code=400, - detail=f"Invalid fields: {invalid}. Use /stocks/fields to discover available names.", - ) - fieldList = requested - else: - fieldList = fieldListAvailable - - availableYears = sorted(set(year for field in fieldList for year in historicalFields[field])) - if dates: - startDate, endDate = parseDateRange(dates) - if startDate is None or endDate is None: - raise ValueError(f"Invalid date range: {dates}") - yearStart, yearEnd = startDate.year, endDate.year - else: - yearStart, yearEnd = availableYears[0], availableYears[-1] - - cols = ["TICKER", "NOME"] + [ - f"{field} {year}" - for field in fieldList - for year in range(yearEnd, yearStart - 1, -1) - if f"{field} {year}" in availableColumnsSet + lookup = index if index is not None else stocksCache.tickerIndex + upperTickers = df["TICKER"].str.upper() + exactSet = {t for t in searchTerms if lookup and t in lookup} + prefixTerms = tuple(t for t in searchTerms if t not in exactSet) + exactMask = upperTickers.isin(exactSet) + if prefixTerms: + return df[exactMask | upperTickers.str.startswith(prefixTerms)] + return df[exactMask] + + +def queryHistorical( + search: str | None = None, + fields: str | None = None, + dates: str | None = None, + orderBy: str | None = None, + limit: int | None = None, + cacheManager=None, +): + if not (search or fields or dates): + raise HTTPException(status_code=400, detail="at least one of search/fields/dates required") + df, tickerIndex = baseFrame(cacheManager) + + try: + availableColumns = df.columns.tolist() + availableColumnsSet = set(availableColumns) + historicalFields, _ = categorizeColumns(availableColumns) + + if not historicalFields: + raise HTTPException(status_code=400, detail="No historical data available in cache") + + fieldList = validateFields(fields, sorted(historicalFields.keys()), "historical") + + availableYears = sorted(set(year for field in fieldList for year in historicalFields[field])) + if dates: + startDate, endDate = parseDateRange(dates) + if startDate is None or endDate is None: + raise ValueError(f"Invalid date range: {dates}") + yearStart, yearEnd = startDate.year, endDate.year + else: + yearStart, yearEnd = availableYears[0], availableYears[-1] + + cols = ["TICKER", "NOME"] + [ + f"{field} {year}" + for field in fieldList + for year in range(yearEnd, yearStart - 1, -1) + if f"{field} {year}" in availableColumnsSet + ] + + return finalize( + df, + tickerIndex, + search, + orderBy, + limit, + cols, + sorted(fieldList), + [yearStart, yearEnd], + "historical", + dedupTickers=True, + ) + except HTTPException: + raise + except Exception: + logger.exception("Cached historical query failed") + raise HTTPException(status_code=500, detail="Internal server error while processing historical data") + + +def queryFundamental( + search: str | None = None, + fields: str | None = None, + dates: str | None = None, + orderBy: str | None = None, + limit: int | None = None, + cacheManager=None, +): + if not (search or fields or dates): + raise HTTPException(status_code=400, detail="at least one of search/fields/dates required") + df, tickerIndex = baseFrame(cacheManager) + + try: + availableColumns = df.columns.tolist() + availableColumnsSet = set(availableColumns) + _, fundamentalCols = categorizeColumns(availableColumns) + + fundamentalColsFiltered = [ + c for c in fundamentalCols if c not in ("COTACAO 10Y PADRAO", "COTACAO 10Y AJUSTADA") + ] + fieldList = ( + [ + f + for f in validateFields(fields, fundamentalCols, "fundamental") + if f not in ("COTACAO 10Y PADRAO", "COTACAO 10Y AJUSTADA") ] + if fields + else fundamentalColsFiltered + ) + cols = ["TICKER", "NOME", "TIME"] + [field for field in fieldList if field in availableColumnsSet] - return self.finalize( - df, - tickerIndex, - search, - orderBy, - limit, - cols, - sorted(fieldList), - [yearStart, yearEnd], - "historical", - dedupTickers=True, - ) - except HTTPException: - raise - except Exception as e: - logger.exception("Cached historical query failed") - raise HTTPException(status_code=500, detail="Internal server error while processing historical data") - - def queryFundamental( - self, - search: str | None = None, - fields: str | None = None, - dates: str | None = None, - orderBy: str | None = None, - limit: int | None = None, - ): - if not (search or fields or dates): - raise HTTPException(status_code=400, detail="at least one of search/fields/dates required") - df, tickerIndex = self.baseFrame() + if search: + df = filterBySearchTerms(df, search, tickerIndex) - try: - availableColumns = df.columns.tolist() - availableColumnsSet = set(availableColumns) - _, fundamentalCols = categorizeColumns(availableColumns) + if "TIME" in df.columns and dates: + timeCol = pd.to_datetime(df["TIME"]) + try: + startDate, endDate = parseDateRange(dates) + isRange = "," in dates + if isRange: + mask = (timeCol.dt.date >= startDate) & (timeCol.dt.date <= endDate) + df = df[mask] + else: + targetTs = pd.Timestamp(endDate) + diffs = (timeCol - targetTs).abs() + minDiffPerTicker = diffs.groupby(df["TICKER"]).transform("min") + mask = diffs == minDiffPerTicker + df = df[mask] + except Exception: + logger.exception("Date parsing failed") + raise HTTPException(status_code=400, detail="Invalid date format. Use YYYY-MM-DD") + + if not search or search.strip() == "": + df = df.drop_duplicates(subset=["TICKER"], keep="first") - fundamentalColsFiltered = [ - c for c in fundamentalCols if c not in ("COTACAO 10Y PADRAO", "COTACAO 10Y AJUSTADA") - ] - if fields: - requested = [f.strip() for f in fields.split(",") if f.strip()] - invalid = [f for f in requested if f not in fundamentalCols] - if invalid: - raise HTTPException( - status_code=400, - detail=f"Invalid fields: {invalid}. Use /stocks/fields to discover available names.", - ) - fieldList = [f for f in requested if f not in ("COTACAO 10Y PADRAO", "COTACAO 10Y AJUSTADA")] - else: - fieldList = fundamentalColsFiltered - cols = ["TICKER", "NOME", "TIME"] + [field for field in fieldList if field in availableColumnsSet] - - if search: - df = self.filterBySearchTerms(df, search, tickerIndex) - - if "TIME" in df.columns and dates: - timeCol = pd.to_datetime(df["TIME"]) - try: - startDate, endDate = parseDateRange(dates) - isRange = "," in dates - if isRange: - mask = (timeCol.dt.date >= startDate) & (timeCol.dt.date <= endDate) - df = df[mask] - else: - targetTs = pd.Timestamp(endDate) - diffs = (timeCol - targetTs).abs() - minDiffPerTicker = diffs.groupby(df["TICKER"]).transform("min") - mask = diffs == minDiffPerTicker - df = df[mask] - except Exception as e: - logger.exception("Date parsing failed") - raise HTTPException(status_code=400, detail="Invalid date format. Use YYYY-MM-DD") - - if not search or search.strip() == "": - df = df.drop_duplicates(subset=["TICKER"], keep="first") - - return self.finalize(df, tickerIndex, search, orderBy, limit, cols, fieldList, dates, "fundamental") - except HTTPException: - raise - except Exception as e: - logger.exception("Cached fundamental query failed") - raise HTTPException(status_code=500, detail="Internal server error while processing fundamental data") - - def queryCotations( - self, - search: str | None = None, - dates: str | None = None, - adjusted: bool = False, - ): - df, tickerIndex = self.baseFrame() + return finalize(df, tickerIndex, search, orderBy, limit, cols, fieldList, dates, "fundamental") + except HTTPException: + raise + except Exception: + logger.exception("Cached fundamental query failed") + raise HTTPException(status_code=500, detail="Internal server error while processing fundamental data") - try: - targetCol = "COTACAO 10Y AJUSTADA" if adjusted else "COTACAO 10Y PADRAO" - responseFields = [targetCol] - - if targetCol not in df.columns: - return { - "search": search or "all", - "fields": responseFields, - "dates": dates, - "type": "cotations", - "count": 0, - "data": [], - } - - if search: - df = self.filterBySearchTerms(df, search, tickerIndex) - - if "TIME" in df.columns: - df = df.sort_values(by="TIME", ascending=False, kind="mergesort") - df = df.drop_duplicates(subset=["TICKER"], keep="first") - return self.finalize( - df, - tickerIndex, - search, - None, - None, - ["TICKER", "NOME", "TIME", targetCol], - responseFields, - dates, - "cotations", - cotationCol=targetCol, - ) - except HTTPException: - raise - except Exception: - logger.exception("Cached cotations query failed") - raise HTTPException(status_code=500, detail="Internal server error while processing cotations data") +def queryCotations( + search: str | None = None, + dates: str | None = None, + adjusted: bool = False, + cacheManager=None, +): + df, tickerIndex = baseFrame(cacheManager) - def queryLiveCotation(self, search: str): - try: - resp = getSession().get( - f"https://cotacao.b3.com.br/mds/api/v1/instrumentQuotation/{search.upper()}", - timeout=5, - ) - resp.raise_for_status() - payload = resp.json() - except Exception: - raise HTTPException(503, detail="B3 realtime unavailable") - - if payload.get("BizSts", {}).get("cd") != "OK" or not payload.get("Trad"): - raise HTTPException(404, detail=f"Ticker {search.upper()} not found") - - dtTm = payload["Msg"]["dtTm"] - raw = payload["Trad"][0]["scty"]["SctyQtn"] - data = { - "TICKER": payload["Trad"][0]["scty"]["symb"], - "PRECO ATUAL": raw.get("curPrc"), - "PRECO ORIGINAL": raw.get("opngPric"), - "PRECO MINIMO": raw.get("minPric"), - "PRECO MAXIMO": raw.get("maxPric"), - "PRECO MEDIO": raw.get("avrgPric"), - } - - return { - "search": search.upper(), - "type": "realtime-cotation", - "timestamp": dtTm, - "count": 1, - "data": [data], - } - - -stocksQuery = StocksQueryManager(stocksCache) + try: + targetCol = "COTACAO 10Y AJUSTADA" if adjusted else "COTACAO 10Y PADRAO" + responseFields = [targetCol] + + if targetCol not in df.columns: + return envelope(search, responseFields, dates, "cotations", df.iloc[0:0]) + + if search: + df = filterBySearchTerms(df, search, tickerIndex) + + if "TIME" in df.columns: + df = df.sort_values(by="TIME", ascending=False, kind="mergesort") + df = df.drop_duplicates(subset=["TICKER"], keep="first") + + return finalize( + df, + tickerIndex, + search, + None, + None, + ["TICKER", "NOME", "TIME", targetCol], + responseFields, + dates, + "cotations", + cotationCol=targetCol, + ) + except HTTPException: + raise + except Exception: + logger.exception("Cached cotations query failed") + raise HTTPException(status_code=500, detail="Internal server error while processing cotations data") + + +def queryLiveCotation(search: str): + try: + resp = getSession().get( + f"https://cotacao.b3.com.br/mds/api/v1/instrumentQuotation/{search.upper()}", + timeout=5, + ) + resp.raise_for_status() + payload = resp.json() + except Exception: + raise HTTPException(503, detail="B3 realtime unavailable") + + if payload.get("BizSts", {}).get("cd") != "OK" or not payload.get("Trad"): + raise HTTPException(404, detail=f"Ticker {search.upper()} not found") + + dtTm = payload["Msg"]["dtTm"] + raw = payload["Trad"][0]["scty"]["SctyQtn"] + data = { + "TICKER": payload["Trad"][0]["scty"]["symb"], + "PRECO ATUAL": raw.get("curPrc"), + "PRECO ORIGINAL": raw.get("opngPric"), + "PRECO MINIMO": raw.get("minPric"), + "PRECO MAXIMO": raw.get("maxPric"), + "PRECO MEDIO": raw.get("avrgPric"), + } + + return { + "search": search.upper(), + "type": "realtime-cotation", + "timestamp": dtTm, + "count": 1, + "data": [data], + } diff --git a/main/app/stocks_api/util.py b/main/app/stocks_api/util.py index 74cf6be..77c5528 100644 --- a/main/app/stocks_api/util.py +++ b/main/app/stocks_api/util.py @@ -5,12 +5,9 @@ from datetime import date from typing import Any -import orjson from fastapi import HTTPException import pandas as pd -# Mirrors JSON_COLUMNS in main/app/scraper_b3/scraper.py — duplicated by -# design (no shared/ kernel). Keep both tuples in sync. JSON_COLUMNS = ("COTACAO 10Y PADRAO", "COTACAO 10Y AJUSTADA", "HISTORICO DIVIDENDOS", "NOTICIAS") PREPOSITIONS = frozenset({"DE", "DO", "DA", "DOS", "DAS", "E", "O", "A", "EM", "COM", "POR", "PARA"}) @@ -82,7 +79,7 @@ def parseDate(dateStr: str, end: bool = False) -> date: if end: return date(y, m, calendar.monthrange(y, m)[1]) return date(y, m, 1) - return pd.to_datetime(dateStr).date() + return date.fromisoformat(dateStr) def parseDateRange(dates: str | None) -> tuple[date | None, date | None]: diff --git a/main/controller/authentication_controller.py b/main/controller/authentication_controller.py index c9a0340..5862041 100644 --- a/main/controller/authentication_controller.py +++ b/main/controller/authentication_controller.py @@ -46,7 +46,7 @@ def issueSessionCookie(response, request, db, user) -> str: userAgent = request.headers.get("User-Agent", "") expiresAt = datetime.now(timezone.utc) + timedelta(hours=TOKEN_EXPIRY_HOURS) session = SessionManager.createSession(db, user["userId"], userAgent, expiresAt) - accessToken, _ = createAccessToken(data={"userId": str(user["userId"]), "sessionId": str(session.sessionId)}) + accessToken = createAccessToken(data={"userId": str(user["userId"]), "sessionId": str(session.sessionId)}) cookieDomain = resolveCookieDomain(request) diff --git a/main/controller/stocksapi_controller.py b/main/controller/stocksapi_controller.py index 26df5b2..8bdfea9 100644 --- a/main/controller/stocksapi_controller.py +++ b/main/controller/stocksapi_controller.py @@ -5,7 +5,7 @@ from fastapi import APIRouter, Depends, Query, HTTPException, Response from fastapi.responses import ORJSONResponse -from main.app.stocks_api.query import stocksQuery +from main.app.stocks_api.query import queryCotations, queryFundamental, queryHistorical, queryLiveCotation from main.app.stocks_api.key import verifyAPIKey from main.app.stocks_api.util import categorizeColumns, generateAbbreviations from main.app.stocks_api.compress import compressResponse, getNest @@ -139,7 +139,7 @@ def getHistorical( - Get all revenue data for VALE3: search="VALE3", fields="RECEITA LIQUIDA" - Compare top 10 by EBITDA: fields="EBITDA", orderBy="EBITDA", limit=10""" response.headers["Cache-Control"] = "public, max-age=300" - result = stocksQuery.queryHistorical(search, fields, dates, orderBy, limit) + result = queryHistorical(search, fields, dates, orderBy, limit) if compact: result = compressResponse(result, "get_historical", {"search": search, "fields": fields, "dates": dates}) return result @@ -209,7 +209,7 @@ def getFundamental( - Compare P/L across tickers: search="PETR4,VALE3,ITUB4", fields="P/L", orderBy="P/L" - Q1 2024 fundamental snapshot: fields="P/L,ROE", dates="2024-01-01,2024-03-31" """ response.headers["Cache-Control"] = "public, max-age=300" - result = stocksQuery.queryFundamental(search, fields, dates, orderBy, limit) + result = queryFundamental(search, fields, dates, orderBy, limit) if compact: result = compressResponse(result, "get_fundamental", {"search": search, "fields": fields, "dates": dates}) return result @@ -265,7 +265,7 @@ def getCotations( - Get PETR4 + VALE3 2023 prices: search="PETR4,VALE3", dates="2023-01-01,2023-12-31" - Get inflation-adjusted prices: search="ITUB4", adjusted=true""" response.headers["Cache-Control"] = "public, max-age=300" - result = stocksQuery.queryCotations(search, dates, adjusted) + result = queryCotations(search, dates, adjusted) if compact: result = compressResponse(result, "get_cotations", {"search": search, "dates": dates}) return result @@ -310,7 +310,7 @@ def getLiveCotation( - Real-time data is only available during B3 market hours (10:00-17:30 BRT). - Outside market hours, returns the last available closing price.""" response.headers["Cache-Control"] = "public, max-age=15" - result = stocksQuery.queryLiveCotation(search) + result = queryLiveCotation(search) if compact: result = compressResponse(result, "get_live_price", {"search": search}) return result diff --git a/main/controller/user_controller.py b/main/controller/user_controller.py index 9c608b8..637e60d 100644 --- a/main/controller/user_controller.py +++ b/main/controller/user_controller.py @@ -16,9 +16,6 @@ def sessionToDict(s, isCurrent=False): return { "sessionId": s.sessionId, - "deviceName": SessionManager.getDeviceName(s), - "browser": s.browser, - "os": s.operatingSystem, "deviceType": s.deviceType, "lastActiveAt": s.lastActivityAt.isoformat() if s.lastActivityAt else None, "createdAt": s.createdAt.isoformat() if s.createdAt else None, @@ -112,7 +109,7 @@ def revokeAllSessions( ): logger.info(f"User {currentUser['userId']} requesting revoke-all for all sessions") - revokedCount = SessionManager.revokeAllSessions(db, currentUser["userId"], exceptSessionId=None) + revokedCount = SessionManager.revokeAllSessions(db, currentUser["userId"]) logger.info(f"Revoked {revokedCount} sessions for user {currentUser['userId']}") return {"message": "All sessions revoked successfully", "revokedCount": revokedCount} diff --git a/main/utils/connectivity.py b/main/utils/connectivity.py index b030a2c..9257176 100644 --- a/main/utils/connectivity.py +++ b/main/utils/connectivity.py @@ -1,6 +1,5 @@ import logging import time -from requests.exceptions import ConnectionError, Timeout, RequestException from main.utils.http_session import getSession from sqlalchemy import text @@ -58,9 +57,6 @@ def checkServiceConnection(service: str): if response.status_code == 200: logger.info(f"{service} connected ({latency:.2f}ms)") return True - except (ConnectionError, Timeout, RequestException) as e: - logger.error(f"{service} connection failed: {e}") - return False except Exception as e: - logger.error(f"{service} unexpected error: {e}") + logger.error(f"{service} connection failed: {e}") return False diff --git a/main/utils/migrator.py b/main/utils/migrator.py index afcd773..737df81 100644 --- a/main/utils/migrator.py +++ b/main/utils/migrator.py @@ -10,13 +10,15 @@ def runMigrations(): rootPath = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) if os.path.exists(os.path.join(rootPath, "alembic.ini")): - os.chdir(rootPath) - elif not os.path.exists("alembic.ini"): + cwd = rootPath + elif os.path.exists("alembic.ini"): + cwd = os.getcwd() + else: logger.error(f"alembic.ini not found in {os.getcwd()} or {rootPath}") return result = subprocess.run( # nosec: B607, B603 - ["alembic", "upgrade", "head"], capture_output=True, text=True, env=os.environ.copy() + ["alembic", "upgrade", "head"], capture_output=True, text=True, env=os.environ.copy(), cwd=cwd ) if result.returncode == 0: diff --git a/run.py b/run.py index b113496..ebe0f68 100644 --- a/run.py +++ b/run.py @@ -3,7 +3,6 @@ from fastapi import FastAPI, BackgroundTasks from contextlib import asynccontextmanager -import asyncio from tenacity import AsyncRetrying, RetryError, stop_after_attempt, wait_fixed diff --git a/tests/conftest.py b/tests/conftest.py index de9d5ac..ea2c736 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,9 @@ import pytest import sys import os +from unittest.mock import AsyncMock, MagicMock +from fastapi import FastAPI +from fastapi.testclient import TestClient from sqlalchemy import create_engine from sqlalchemy.pool import StaticPool from sqlalchemy.orm import sessionmaker @@ -164,3 +167,108 @@ def mock_get_current_user(): with TestClient(testApp, raise_server_exceptions=False) as c: yield c + + +def mock_forgevm(mock_cls): + """Wire up mock forgevm AsyncClient that returns sandbox with all methods. + + Shared helper (superset of the former per-file copies): includes + extend_ttl + glob_files so persistence tests work unchanged. + Call as ``mock_client, mock_sandbox = mock_forgevm(mock_get_client)``. + """ + mock_client = AsyncMock() + mock_sandbox = AsyncMock() + mock_sandbox.id = "sb-mock-123" + mock_sandbox.exec = AsyncMock(return_value=MagicMock(stdout="Hello\n", stderr="")) + mock_sandbox.read_file = AsyncMock(return_value="file contents") + mock_sandbox.write_file = AsyncMock() + mock_sandbox.list_files = AsyncMock(return_value=[{"path": "/workspace/data.csv", "size": 100, "is_dir": False}]) + mock_sandbox.destroy = AsyncMock() + mock_sandbox.extend_ttl = AsyncMock() + mock_sandbox.glob_files = AsyncMock(return_value=[]) + mock_client.spawn = AsyncMock(return_value=mock_sandbox) + mock_client.get = AsyncMock(return_value=mock_sandbox) + mock_client.close = AsyncMock() + mock_cls.return_value = mock_client + return mock_client, mock_sandbox + + +# --------------------------------------------------------------------------- +# Shared controller TestClient builders (moved from test_controllers_coverage.py +# so all controller test files reuse one copy). Each returns (client, app, +# mock_session); call sites unpack only what they need. +# --------------------------------------------------------------------------- +def make_auth_client(): + """Return (client, app) with auth + user routers and mocked getSession.""" + from main.controller.authentication_controller import router as authRouter + from main.controller.user_controller import router as userRouter + from main.utils.errors import registerErrorHandlers + + app = FastAPI() + app.include_router(authRouter) + app.include_router(userRouter) + registerErrorHandlers(app) + + mock_session = MagicMock() + app.dependency_overrides[__import__("config", fromlist=["getSession"]).getSession] = lambda: mock_session + return TestClient(app, raise_server_exceptions=False), app, mock_session + + +def make_user_client(mock_current_user=None): + """Return (client, app) with user router and mocked deps.""" + from main.controller.user_controller import router as userRouter + from main.utils.errors import registerErrorHandlers + from main.app.user.user import UserManager + + app = FastAPI() + app.include_router(userRouter) + registerErrorHandlers(app) + + mock_session = MagicMock() + app.dependency_overrides[__import__("config", fromlist=["getSession"]).getSession] = lambda: mock_session + + if mock_current_user is not None: + app.dependency_overrides[UserManager.getCurrentUser] = lambda: mock_current_user + + return TestClient(app, raise_server_exceptions=False), app, mock_session + + +def make_prometheus_client(mock_current_user=None, mock_permission_user=None): + """Return (client, app) with prometheus router and mocked deps.""" + from main.controller.prometheus_controller import router as promRouter + from main.utils.errors import registerErrorHandlers + from main.app.user.user import UserManager + + app = FastAPI() + app.include_router(promRouter) + registerErrorHandlers(app) + + mock_session = MagicMock() + app.dependency_overrides[__import__("config", fromlist=["getSession"]).getSession] = lambda: mock_session + + user = mock_current_user or {"userId": 1, "username": "testuser", "roles": ["PREMIUM"]} + # ponytail: per-call Roles.requirePermission returns a fresh callable; + # override key never matches the actual dep, so the line is a no-op. Skip. + app.dependency_overrides[UserManager.getCurrentUser] = lambda: user + + return TestClient(app, raise_server_exceptions=False), app, mock_session + + +def make_stocksapi_client(mock_api_key=None): + """Return (client, app) with stocks router and mocked deps.""" + from main.controller.stocksapi_controller import router as stocksRouter + from main.utils.errors import registerErrorHandlers + + app = FastAPI() + app.include_router(stocksRouter) + registerErrorHandlers(app) + + mock_session = MagicMock() + app.dependency_overrides[__import__("config", fromlist=["getSession"]).getSession] = lambda: mock_session + + if mock_api_key is not None: + from main.app.stocks_api.key import verifyAPIKey + + app.dependency_overrides[verifyAPIKey] = lambda: mock_api_key + + return TestClient(app, raise_server_exceptions=False), app, mock_session diff --git a/tests/test_auth_util.py b/tests/test_auth_util.py index f36a559..a32325c 100644 --- a/tests/test_auth_util.py +++ b/tests/test_auth_util.py @@ -7,6 +7,7 @@ from main.app.authentication.util import hashPassword, verifyPassword, createAccessToken from main.app.authentication.constants import SESSION_EXPIRY_DAYS from datetime import timedelta, datetime +from unittest.mock import MagicMock, patch import jwt @@ -41,7 +42,7 @@ def test_verify_password_empty_password(self): assert verifyPassword("", hashed) is False def test_create_access_token_default_expiry(self): - token, _ = createAccessToken({"userId": "123"}) + token = createAccessToken({"userId": "123"}) decoded = jwt.decode(token, options={"verify_signature": False}) assert "exp" in decoded @@ -49,7 +50,7 @@ def test_create_access_token_default_expiry(self): def test_create_access_token_custom_expiry(self): customDelta = timedelta(hours=48) - token, _ = createAccessToken({"userId": "123"}, expiresDelta=customDelta) + token = createAccessToken({"userId": "123"}, expiresDelta=customDelta) decoded = jwt.decode(token, options={"verify_signature": False}) expTime = datetime.fromtimestamp(decoded["exp"]) @@ -60,7 +61,7 @@ def test_create_access_token_custom_expiry(self): def test_create_access_token_contains_data(self): data = {"userId": "456", "username": "testuser"} - token, _ = createAccessToken(data) + token = createAccessToken(data) decoded = jwt.decode(token, options={"verify_signature": False}) assert decoded["userId"] == "456" @@ -76,7 +77,7 @@ def test_session_expiry_hours_calculation(self): assert TOKEN_EXPIRY_HOURS == SESSION_EXPIRY_DAYS * 24 def test_default_token_expiry_equals_30_days(self): - token, _ = createAccessToken({"userId": "123"}) + token = createAccessToken({"userId": "123"}) decoded = jwt.decode(token, options={"verify_signature": False}) expTime = datetime.fromtimestamp(decoded["exp"]) @@ -101,13 +102,193 @@ def test_verify_password_both_none(self): assert result is False def test_create_access_token_with_empty_data(self): - token, _ = createAccessToken({}) + token = createAccessToken({}) decoded = jwt.decode(token, options={"verify_signature": False}) assert "exp" in decoded def test_create_access_token_with_none_data(self): - token, _ = createAccessToken(None) + token = createAccessToken(None) decoded = jwt.decode(token, options={"verify_signature": False}) assert "exp" in decoded + + +# ---- moved from test_prometheus_auth_coverage.py (TestAuthenticationManager) ---- + + +class TestAuthenticationManager: + """Cover all methods in authentication.py (lines 13-75).""" + + @patch("main.app.authentication.authentication.hashPassword") + def test_create_user_account_success(self, mock_hash): + from main.app.authentication.authentication import AuthenticationManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = None + mock_hash.return_value = "hashed_pw" + + result = AuthenticationManager.createUserAccount(mock_db, "newuser", "new@example.com", password="pass123") + assert result is True + mock_db.add.assert_called_once() + mock_db.commit.assert_called_once() + + def test_create_user_account_no_password_no_google(self): + from main.app.authentication.authentication import AuthenticationManager + from fastapi import HTTPException + + mock_db = MagicMock() + + with pytest.raises(HTTPException) as exc_info: + AuthenticationManager.createUserAccount(mock_db, "user", "e@e.com") + assert exc_info.value.status_code == 400 + assert "password" in exc_info.value.detail.lower() + + def test_create_user_account_username_taken(self): + from main.app.authentication.authentication import AuthenticationManager + from fastapi import HTTPException + + mock_db = MagicMock() + existing = MagicMock() + existing.username = "taken" + mock_db.query.return_value.filter.return_value.first.return_value = existing + + with pytest.raises(HTTPException) as exc_info: + AuthenticationManager.createUserAccount(mock_db, "taken", "e@e.com", password="pass") + assert exc_info.value.status_code == 400 + assert "Username already taken" in exc_info.value.detail + + def test_create_user_account_email_taken(self): + from main.app.authentication.authentication import AuthenticationManager + from fastapi import HTTPException + + mock_db = MagicMock() + existing = MagicMock() + existing.username = "other" + mock_db.query.return_value.filter.return_value.first.return_value = existing + + with pytest.raises(HTTPException) as exc_info: + AuthenticationManager.createUserAccount(mock_db, "newuser", "taken@example.com", password="pass") + assert exc_info.value.status_code == 400 + assert "Email already registered" in exc_info.value.detail + + @patch("main.app.authentication.authentication.hashPassword") + def test_create_user_account_db_exception(self, mock_hash): + from main.app.authentication.authentication import AuthenticationManager + from fastapi import HTTPException + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = None + mock_db.commit.side_effect = Exception("DB error") + mock_hash.return_value = "hashed" + + with pytest.raises(HTTPException) as exc_info: + AuthenticationManager.createUserAccount(mock_db, "user", "e@e.com", password="pass") + assert exc_info.value.status_code == 500 + mock_db.rollback.assert_called() + + def test_create_user_account_with_google_id(self): + from main.app.authentication.authentication import AuthenticationManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = None + + result = AuthenticationManager.createUserAccount(mock_db, "googleuser", "g@g.com", googleId="google-123") + assert result is True + + def test_authenticate_google_user_found(self): + from main.app.authentication.authentication import AuthenticationManager + + mock_db = MagicMock() + mock_user = MagicMock() + mock_user.userId = 1 + mock_user.username = "testuser" + mock_user.getRolesList.return_value = ["USER"] + mock_db.query.return_value.filter.return_value.first.return_value = mock_user + + result = AuthenticationManager.authenticateGoogleUser(mock_db, "google-123") + assert result is not None + assert result["userId"] == 1 + assert result["username"] == "testuser" + + def test_authenticate_google_user_not_found(self): + from main.app.authentication.authentication import AuthenticationManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = None + + result = AuthenticationManager.authenticateGoogleUser(mock_db, "nonexistent") + assert result is None + + def test_authenticate_google_user_exception(self): + from main.app.authentication.authentication import AuthenticationManager + + mock_db = MagicMock() + mock_db.query.side_effect = Exception("DB error") + + result = AuthenticationManager.authenticateGoogleUser(mock_db, "google-123") + assert result is None + + @patch("main.app.authentication.authentication.verifyPassword") + def test_authenticate_user_success(self, mock_verify): + from main.app.authentication.authentication import AuthenticationManager + + mock_db = MagicMock() + mock_user = MagicMock() + mock_user.userId = 1 + mock_user.username = "testuser" + mock_user.passwordHash = "hashed" + mock_user.getRolesList.return_value = ["USER"] + mock_db.query.return_value.filter.return_value.first.return_value = mock_user + mock_verify.return_value = True + + result = AuthenticationManager.authenticateUser(mock_db, "testuser", "pass123") + assert result is not None + assert result["userId"] == 1 + + @patch("main.app.authentication.authentication.verifyPassword") + def test_authenticate_user_wrong_password(self, mock_verify): + from main.app.authentication.authentication import AuthenticationManager + + mock_db = MagicMock() + mock_user = MagicMock() + mock_user.passwordHash = "hashed" + mock_db.query.return_value.filter.return_value.first.return_value = mock_user + mock_verify.return_value = False + + result = AuthenticationManager.authenticateUser(mock_db, "testuser", "wrong") + assert result is None + + def test_authenticate_user_not_found(self): + from main.app.authentication.authentication import AuthenticationManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = None + + result = AuthenticationManager.authenticateUser(mock_db, "nobody", "pass") + assert result is None + + def test_authenticate_user_no_password_hash(self): + from main.app.authentication.authentication import AuthenticationManager + + mock_db = MagicMock() + mock_user = MagicMock() + mock_user.passwordHash = None + mock_db.query.return_value.filter.return_value.first.return_value = mock_user + + result = AuthenticationManager.authenticateUser(mock_db, "testuser", "pass") + assert result is None + + def test_authenticate_user_exception(self): + from main.app.authentication.authentication import AuthenticationManager + + mock_db = MagicMock() + mock_db.query.side_effect = Exception("DB error") + + result = AuthenticationManager.authenticateUser(mock_db, "testuser", "pass") + assert result is None + + +# --------------------------------------------------------------------------- +# SessionManager (session.py) +# --------------------------------------------------------------------------- diff --git a/tests/test_controllers_coverage.py b/tests/test_controllers_coverage.py index 0cb04bf..da37857 100644 --- a/tests/test_controllers_coverage.py +++ b/tests/test_controllers_coverage.py @@ -15,84 +15,20 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +# Shared controller TestClient builders live in conftest (single copy reused by +# all controller test files): make_auth_client, make_user_client, +# make_prometheus_client, make_stocksapi_client. +from tests.conftest import ( + make_auth_client, + make_user_client, + make_prometheus_client, + make_stocksapi_client, +) + # --------------------------------------------------------------------------- -# Helper: build a minimal TestClient for auth_controller with a mock DB dep +# Shared builders imported from conftest (see import above). # --------------------------------------------------------------------------- -def make_auth_client(): - """Return (client, app) with auth + user routers and mocked getSession.""" - from main.controller.authentication_controller import router as authRouter - from main.controller.user_controller import router as userRouter - from main.utils.errors import registerErrorHandlers - - app = FastAPI() - app.include_router(authRouter) - app.include_router(userRouter) - registerErrorHandlers(app) - - mock_session = MagicMock() - app.dependency_overrides[__import__("config", fromlist=["getSession"]).getSession] = lambda: mock_session - return TestClient(app, raise_server_exceptions=False), app, mock_session - - -def make_user_client(mock_current_user=None): - """Return (client, app) with user router and mocked deps.""" - from main.controller.user_controller import router as userRouter - from main.utils.errors import registerErrorHandlers - from main.app.user.user import UserManager - - app = FastAPI() - app.include_router(userRouter) - registerErrorHandlers(app) - - mock_session = MagicMock() - app.dependency_overrides[__import__("config", fromlist=["getSession"]).getSession] = lambda: mock_session - - if mock_current_user is not None: - app.dependency_overrides[UserManager.getCurrentUser] = lambda: mock_current_user - - return TestClient(app, raise_server_exceptions=False), app, mock_session - - -def make_prometheus_client(mock_current_user=None, mock_permission_user=None): - """Return (client, app) with prometheus router and mocked deps.""" - from main.controller.prometheus_controller import router as promRouter - from main.utils.errors import registerErrorHandlers - from main.app.user.user import UserManager - - app = FastAPI() - app.include_router(promRouter) - registerErrorHandlers(app) - - mock_session = MagicMock() - app.dependency_overrides[__import__("config", fromlist=["getSession"]).getSession] = lambda: mock_session - - user = mock_current_user or {"userId": 1, "username": "testuser", "roles": ["PREMIUM"]} - # ponytail: per-call Roles.requirePermission returns a fresh callable; - # override key never matches the actual dep, so the line is a no-op. Skip. - app.dependency_overrides[UserManager.getCurrentUser] = lambda: user - - return TestClient(app, raise_server_exceptions=False), app, mock_session - - -def make_stocksapi_client(mock_api_key=None): - """Return (client, app) with stocks router and mocked deps.""" - from main.controller.stocksapi_controller import router as stocksRouter - from main.utils.errors import registerErrorHandlers - - app = FastAPI() - app.include_router(stocksRouter) - registerErrorHandlers(app) - - mock_session = MagicMock() - app.dependency_overrides[__import__("config", fromlist=["getSession"]).getSession] = lambda: mock_session - - if mock_api_key is not None: - from main.app.stocks_api.key import verifyAPIKey - - app.dependency_overrides[verifyAPIKey] = lambda: mock_api_key - - return TestClient(app, raise_server_exceptions=False), app, mock_session # ========================================================================= @@ -156,7 +92,7 @@ def test_register_success(self, mock_auth_mgr, mock_create_token, mock_session_m mock_session.sessionId = "sess-123" mock_session_mgr.createSession.return_value = mock_session - mock_create_token.return_value = ("jwt-token-abc", timedelta(hours=720)) + mock_create_token.return_value = "jwt-token-abc" response = client.post( "/auth/register", @@ -223,7 +159,7 @@ def test_login_success(self, mock_auth_mgr, mock_create_token, mock_session_mgr) mock_session.sessionId = "sess-456" mock_session_mgr.createSession.return_value = mock_session - mock_create_token.return_value = ("jwt-token-xyz", timedelta(hours=720)) + mock_create_token.return_value = "jwt-token-xyz" response = client.post( "/auth/login", @@ -415,7 +351,7 @@ def test_callback_new_user(self, mock_auth_mgr, mock_get_sso, mock_create_token, mock_session = MagicMock() mock_session.sessionId = "gsess-123" mock_session_mgr.createSession.return_value = mock_session - mock_create_token.return_value = ("google-jwt-abc", timedelta(hours=720)) + mock_create_token.return_value = "google-jwt-abc" response = client.get("/auth/callback", follow_redirects=False) assert response.status_code == 200 @@ -446,7 +382,7 @@ def test_callback_existing_user(self, mock_auth_mgr, mock_get_sso, mock_create_t mock_session = MagicMock() mock_session.sessionId = "gsess-456" mock_session_mgr.createSession.return_value = mock_session - mock_create_token.return_value = ("google-jwt-def", timedelta(hours=720)) + mock_create_token.return_value = "google-jwt-def" response = client.get("/auth/callback", follow_redirects=False) assert response.status_code == 200 @@ -489,7 +425,7 @@ def test_callback_with_state_redirect(self, mock_auth_mgr, mock_get_sso, mock_cr mock_session = MagicMock() mock_session.sessionId = "gsess-789" mock_session_mgr.createSession.return_value = mock_session - mock_create_token.return_value = ("google-jwt-ghi", timedelta(hours=720)) + mock_create_token.return_value = "google-jwt-ghi" # State IS the redirect URL directly (no encoding needed) redirect_url = "http://localhost:3000/dashboard" @@ -574,7 +510,6 @@ def test_get_sessions(self): """Covers lines 66, 68-72, 74: full sessions listing.""" mock_session_1 = MagicMock() mock_session_1.sessionId = "sess-1" - mock_session_1.getDeviceName.return_value = "Chrome on Windows" mock_session_1.browser = "Chrome" mock_session_1.operatingSystem = "Windows" mock_session_1.deviceType = "desktop" @@ -584,7 +519,6 @@ def test_get_sessions(self): mock_session_2 = MagicMock() mock_session_2.sessionId = "sess-2" - mock_session_2.getDeviceName.return_value = "Safari on macOS" mock_session_2.browser = "Safari" mock_session_2.operatingSystem = "macOS" mock_session_2.deviceType = "mobile" @@ -628,7 +562,6 @@ def test_get_current_session_found(self): """Covers lines 100-104, 106: session found.""" mock_session = MagicMock() mock_session.sessionId = "current-sess" - mock_session.getDeviceName.return_value = "Chrome on Windows" mock_session.browser = "Chrome" mock_session.operatingSystem = "Windows" mock_session.deviceType = "desktop" @@ -1104,13 +1037,13 @@ class TestStocksApiHistorical: def test_get_historical(self): """Covers line 35.""" - with patch("main.controller.stocksapi_controller.stocksQuery") as mock_query: - mock_query.queryHistorical = MagicMock(return_value={"data": [{"ticker": "PETR4", "price": 30.0}]}) + with patch("main.controller.stocksapi_controller.queryHistorical") as mock_query_fn: + mock_query_fn.return_value = {"data": [{"ticker": "PETR4", "price": 30.0}]} client, _, _ = make_stocksapi_client(mock_api_key="key") resp = client.get("/stocks/historical?search=PETR4&limit=10") assert resp.status_code == 200 - mock_query.queryHistorical.assert_called_once() + mock_query_fn.assert_called_once() class TestStocksApiFundamental: @@ -1118,13 +1051,13 @@ class TestStocksApiFundamental: def test_get_fundamental(self): """Covers line 47.""" - with patch("main.controller.stocksapi_controller.stocksQuery") as mock_query: - mock_query.queryFundamental = MagicMock(return_value={"data": [{"ticker": "VALE3", "pl": 5.0}]}) + with patch("main.controller.stocksapi_controller.queryFundamental") as mock_query_fn: + mock_query_fn.return_value = {"data": [{"ticker": "VALE3", "pl": 5.0}]} client, _, _ = make_stocksapi_client(mock_api_key="key") resp = client.get("/stocks/fundamental?search=VALE3&limit=5") assert resp.status_code == 200 - mock_query.queryFundamental.assert_called_once() + mock_query_fn.assert_called_once() # ========================================================================= diff --git a/tests/test_logout_cookie_domain.py b/tests/test_logout_cookie_domain.py index 449581c..a7382b2 100644 --- a/tests/test_logout_cookie_domain.py +++ b/tests/test_logout_cookie_domain.py @@ -47,7 +47,7 @@ def test_logout_clears_cookie_with_matching_domain(self, mock_auth_mgr, mock_cre mock_session = MagicMock() mock_session.sessionId = "sess-123" mock_session_mgr.createSession.return_value = mock_session - mock_create_token.return_value = ("jwt-token-abc", timedelta(hours=720)) + mock_create_token.return_value = "jwt-token-abc" login = client.post("/auth/login", json={"username": "bob", "password": "secret123"}) assert login.status_code == 200 diff --git a/tests/test_oauth_cookie_security.py b/tests/test_oauth_cookie_security.py index cf90407..9596286 100644 --- a/tests/test_oauth_cookie_security.py +++ b/tests/test_oauth_cookie_security.py @@ -50,7 +50,7 @@ def setup_callback_mocks( mock_session = MagicMock() mock_session.sessionId = f"sess-{user_id}" mock_session_mgr.createSession.return_value = mock_session - mock_create_token.return_value = (f"jwt-token-{user_id}", timedelta(hours=720)) + mock_create_token.return_value = f"jwt-token-{user_id}" class TestOAuthCallbackTokenNotInURL: diff --git a/tests/test_prometheus_auth_coverage.py b/tests/test_prometheus_auth_coverage.py index 82e1701..e893579 100644 --- a/tests/test_prometheus_auth_coverage.py +++ b/tests/test_prometheus_auth_coverage.py @@ -322,9 +322,7 @@ def test_save_message_history_none(self): mock_session.history = None mock_db.query.return_value.filter.return_value.first.return_value = mock_session - PrometheusChatManager.appendHistory( - mock_db, "sess-123", {"role": "assistant", "content": "Reply"} - ) + PrometheusChatManager.appendHistory(mock_db, "sess-123", {"role": "assistant", "content": "Reply"}) assert mock_session.history == [ { @@ -341,9 +339,7 @@ def test_save_message_not_found(self): mock_db.query.return_value.filter.return_value.first.return_value = None # Should not raise - PrometheusChatManager.appendHistory( - mock_db, "nonexistent", {"role": "user", "content": "Hello"} - ) + PrometheusChatManager.appendHistory(mock_db, "nonexistent", {"role": "user", "content": "Hello"}) def test_get_history_with_messages(self): from main.app.prometheus.chat import PrometheusChatManager @@ -665,14 +661,14 @@ def test_get_user_sessions_active_only(self): # Should have .filter().filter().order_by().limit().all() query.filter.return_value.order_by.return_value.limit.return_value.all.assert_called_once() - def test_get_user_sessions_include_inactive(self): + def test_get_user_sessions_active_only(self): from main.app.authentication.session import SessionManager mock_db = MagicMock() - SessionManager.getUserSessions(mock_db, userId=1, includeInactive=True) + SessionManager.getUserSessions(mock_db, userId=1) - # When includeInactive=True, only one filter is applied + # Active-only filter is always applied in a single filter call mock_db.query.return_value.filter.return_value.order_by.return_value.limit.return_value.all.assert_called_once() def test_get_session_by_id(self): @@ -736,14 +732,14 @@ def test_revoke_all_sessions(self): assert count == 5 mock_db.commit.assert_called_once() - def test_revoke_all_sessions_with_except(self): + def test_revoke_all_sessions_revokes_everything(self): from main.app.authentication.session import SessionManager mock_db = MagicMock() - # revokeAllSessions: db.query(...).filter(userId, isActive).filter(except).update(...) - mock_db.query.return_value.filter.return_value.filter.return_value.update.return_value = 3 + # revokeAllSessions: db.query(...).filter(userId, isActive).update(...) + mock_db.query.return_value.filter.return_value.update.return_value = 3 - count = SessionManager.revokeAllSessions(mock_db, userId=1, exceptSessionId="keep-this") + count = SessionManager.revokeAllSessions(mock_db, userId=1) assert count == 3 def test_update_last_active_found(self): diff --git a/tests/test_query_search_dates.py b/tests/test_query_search_dates.py index 4465faf..040b6a6 100644 --- a/tests/test_query_search_dates.py +++ b/tests/test_query_search_dates.py @@ -6,7 +6,7 @@ import pandas as pd from main.app.stocks_api.cache import StocksCacheManager, buildTickerIndex -from main.app.stocks_api.query import StocksQueryManager +from main.app.stocks_api.query import filterBySearchTerms, queryFundamental def make_multi_df(): @@ -30,35 +30,35 @@ def make_manager(df, index): def test_exact_search_returns_all_snapshot_rows(): df = make_multi_df() - query = StocksQueryManager(make_manager(df, buildTickerIndex(df))) + manager = make_manager(df, buildTickerIndex(df)) - filtered = query.filterBySearchTerms(df, "PETR4", buildTickerIndex(df)) + filtered = filterBySearchTerms(df, "PETR4", buildTickerIndex(df)) assert filtered["TICKER"].tolist() == ["PETR4", "PETR4", "PETR4"] def test_exact_search_with_dates_returns_matching_rows(): df = make_multi_df() - query = StocksQueryManager(make_manager(df, buildTickerIndex(df))) + manager = make_manager(df, buildTickerIndex(df)) - result = query.queryFundamental(search="PETR4", fields="P/L", dates="2024-01-01,2024-02-15") + result = queryFundamental(search="PETR4", fields="P/L", dates="2024-01-01,2024-02-15", cacheManager=manager) assert result["count"] == 2 def test_mixed_search_returns_exact_and_prefix(): df = make_multi_df() - query = StocksQueryManager(make_manager(df, buildTickerIndex(df))) + manager = make_manager(df, buildTickerIndex(df)) - filtered = query.filterBySearchTerms(df, "PETR4,VALE", buildTickerIndex(df)) + filtered = filterBySearchTerms(df, "PETR4,VALE", buildTickerIndex(df)) assert set(filtered["TICKER"].tolist()) == {"PETR4", "VALE3"} def test_trailing_comma_does_not_match_everything(): df = make_multi_df() - query = StocksQueryManager(make_manager(df, buildTickerIndex(df))) + manager = make_manager(df, buildTickerIndex(df)) - filtered = query.filterBySearchTerms(df, "PETR4,", buildTickerIndex(df)) + filtered = filterBySearchTerms(df, "PETR4,", buildTickerIndex(df)) assert filtered["TICKER"].tolist() == ["PETR4", "PETR4", "PETR4"] diff --git a/tests/test_query_snapshot.py b/tests/test_query_snapshot.py index 8e35cea..370aa7a 100644 --- a/tests/test_query_snapshot.py +++ b/tests/test_query_snapshot.py @@ -8,7 +8,8 @@ from fastapi import HTTPException from main.app.stocks_api.cache import StocksCacheManager -from main.app.stocks_api.query import StocksQueryManager +from main.app.stocks_api import query as queryModule +from main.app.stocks_api.query import filterBySearchTerms def make_df(tickers): @@ -43,7 +44,7 @@ def swappingSnapshot(): return pair manager.snapshot = swappingSnapshot - return StocksQueryManager(manager), manager + return manager class TestPairedSnapshot: @@ -59,9 +60,9 @@ def test_query_methods_filter_with_snapshot_pair_only(self): ("queryCotations", {"search": "AAA1"}), ) for methodName, kwargs in calls: - query, manager = make_swapping_query(df_v1, idx_v1, df_v2, idx_v2) + manager = make_swapping_query(df_v1, idx_v1, df_v2, idx_v2) - result = getattr(query, methodName)(**kwargs) + result = getattr(queryModule, methodName)(cacheManager=manager, **kwargs) assert result["data"][0]["TICKER"] == "AAA1", methodName # swap fired after the snapshot; the result must still be built from the v1 pair @@ -70,10 +71,10 @@ def test_query_methods_filter_with_snapshot_pair_only(self): def test_query_raises_503_against_snapshot_frame_not_post_swap_state(self): df_v2 = make_df(["AAA1"]) - query, _ = make_swapping_query(None, {}, df_v2, {"AAA1": 0}) + manager = make_swapping_query(None, {}, df_v2, {"AAA1": 0}) with pytest.raises(HTTPException) as excinfo: - query.queryCotations(search="AAA1") + queryModule.queryCotations(search="AAA1", cacheManager=manager) assert excinfo.value.status_code == 503 @@ -81,17 +82,15 @@ class TestFilterBySearchTermsIndex: def test_passed_index_wins_over_manager_global(self): df = make_df(["AAA1", "BBB1"]) manager = make_manager(df, {"AAA1": 1}) # decoy global: points AAA1 at the BBB1 row - query = StocksQueryManager(manager) - filtered = query.filterBySearchTerms(df, "AAA1", {"AAA1": 0}) + filtered = filterBySearchTerms(df, "AAA1", {"AAA1": 0}) assert filtered["TICKER"].tolist() == ["AAA1"] - def test_default_falls_back_to_manager_index(self): + def test_explicit_manager_index_used(self): df = make_df(["AAA1", "BBB1"]) manager = make_manager(df, {"AAA1": 1}) - query = StocksQueryManager(manager) - filtered = query.filterBySearchTerms(df, "AAA1") + filtered = filterBySearchTerms(df, "AAA1", manager.tickerIndex) assert filtered["TICKER"].tolist() == ["AAA1"] diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 7207196..6c0257c 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -2,6 +2,8 @@ import sys import os from datetime import datetime, timedelta +from unittest.mock import MagicMock, patch +from zoneinfo import ZoneInfo sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) @@ -11,58 +13,6 @@ class TestUserSessionModel: - def test_getDeviceName_with_browser_and_os(self): - session = UserSession( - sessionId="test-123", - userId=1, - browser="Chrome", - operatingSystem="Windows", - isActive=True, - ) - - name = SessionManager.getDeviceName(session) - - assert name == "Chrome on Windows" - - def test_getDeviceName_with_fingerprint_only(self): - session = UserSession( - sessionId="test-123", - userId=1, - accessTokenHash="abc123def456", - isActive=True, - ) - - name = SessionManager.getDeviceName(session) - - assert name == "Device abc123de" - - def test_getDeviceName_fallback(self): - session = UserSession( - sessionId="test-123", - userId=1, - browser="", - operatingSystem="", - isActive=True, - ) - - name = SessionManager.getDeviceName(session) - - assert name == "Unknown Device" - - def test_getDeviceName_empty_strings(self): - session = UserSession( - sessionId="test-123", - userId=1, - browser="", - operatingSystem="", - accessTokenHash="", - isActive=True, - ) - - name = SessionManager.getDeviceName(session) - - assert name == "Unknown Device" - def test_isActive_default(self): session = UserSession(sessionId="test-123", userId=1, accessTokenHash="abc", isActive=True) assert session.isActive is True @@ -137,3 +87,217 @@ def test_created_at_future_date(self): ) assert session.createdAt > datetime.now() + + +# ---- moved from test_prometheus_auth_coverage.py (TestSessionManager) ---- + + +class TestSessionManager: + """Cover all methods in session.py (lines 14-154).""" + + @patch("main.app.authentication.session.datetime") + @patch("main.app.authentication.session.secrets") + def test_create_session(self, mock_secrets, mock_datetime): + from main.app.authentication.session import SessionManager + + mock_secrets.token_urlsafe.return_value = "session-id-123" + mock_secrets.token_hex.return_value = "a" * 64 + + mock_now = datetime(2026, 3, 23, 12, 0, 0, tzinfo=ZoneInfo("America/Sao_Paulo")) + mock_datetime.now.return_value = mock_now + + mock_db = MagicMock() + + result = SessionManager.createSession(mock_db, userId=1, userAgent="Mozilla/5.0") + + mock_db.add.assert_called_once() + mock_db.commit.assert_called_once() + assert result.sessionId == "session-id-123" + + @patch("main.app.authentication.session.datetime") + @patch("main.app.authentication.session.secrets") + def test_create_session_custom_expiry(self, mock_secrets, mock_datetime): + from main.app.authentication.session import SessionManager + + mock_secrets.token_urlsafe.return_value = "session-id-456" + mock_secrets.token_hex.return_value = "b" * 64 + + mock_now = datetime(2026, 3, 23, 12, 0, 0, tzinfo=ZoneInfo("America/Sao_Paulo")) + mock_datetime.now.return_value = mock_now + + custom_expiry = mock_now + timedelta(days=7) + mock_db = MagicMock() + + result = SessionManager.createSession(mock_db, userId=2, userAgent="Safari", expiresAt=custom_expiry) + assert result.expiresAt == custom_expiry + + def test_get_user_sessions_active_only(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + + SessionManager.getUserSessions(mock_db, userId=1) + + query = mock_db.query.return_value.filter.return_value + # Single .filter(userId, isActive).order_by().limit().all() + query.order_by.return_value.limit.return_value.all.assert_called_once() + + def test_get_session_by_id(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + + SessionManager.getSessionById(mock_db, "sess-123", userId=1) + + query_filter = mock_db.query.return_value.filter.return_value + query_filter.filter.return_value.first.assert_called_once() + + def test_get_session_by_id_no_user_id(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + + SessionManager.getSessionById(mock_db, "sess-123") + + # With no userId, only one filter is applied + mock_db.query.return_value.filter.return_value.first.assert_called_once() + + def test_get_current_session(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + + result = SessionManager.getCurrentSession(mock_db, userId=1) + + mock_db.query.return_value.filter.return_value.order_by.return_value.first.assert_called_once() + + def test_revoke_session_found(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session + + result = SessionManager.revokeSession(mock_db, "sess-123", userId=1) + assert result is True + assert mock_session.isActive is False + mock_db.commit.assert_called_once() + + def test_revoke_session_not_found(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = None + + result = SessionManager.revokeSession(mock_db, "nonexistent", userId=1) + assert result is False + + def test_revoke_all_sessions(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + # revokeAllSessions: db.query(...).filter(userId, isActive).update(...) + mock_db.query.return_value.filter.return_value.update.return_value = 5 + + count = SessionManager.revokeAllSessions(mock_db, userId=1) + assert count == 5 + mock_db.commit.assert_called_once() + + def test_update_last_active_found(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = mock_session + + result = SessionManager.updateLastActive(mock_db, "sess-123") + assert result is True + mock_db.commit.assert_called_once() + + def test_update_last_active_not_found(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = None + + result = SessionManager.updateLastActive(mock_db, "nonexistent") + assert result is False + + def test_validate_session_active(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_session.isActive = True + mock_session.expiresAt = datetime(2026, 12, 31, tzinfo=ZoneInfo("America/Sao_Paulo")) + mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session + + result = SessionManager.validateSession(mock_db, "sess-123", userId=1) + assert result is True + + def test_validate_session_not_found(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = None + + result = SessionManager.validateSession(mock_db, "nonexistent", userId=1) + assert result is False + + def test_validate_session_inactive(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_session.isActive = False + mock_session.expiresAt = datetime(2026, 12, 31, tzinfo=ZoneInfo("America/Sao_Paulo")) + mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session + + result = SessionManager.validateSession(mock_db, "sess-123", userId=1) + assert result is False + + def test_validate_session_expired(self): + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_session.isActive = True + mock_session.expiresAt = datetime(2020, 1, 1, tzinfo=ZoneInfo("America/Sao_Paulo")) + mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session + + result = SessionManager.validateSession(mock_db, "sess-123", userId=1) + assert result is False + assert mock_session.isActive is False + mock_db.commit.assert_called_once() + + def test_validate_session_expired_naive_tz(self): + """Exercises the tzinfo-is-None branch (line 144-148).""" + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_session.isActive = True + # Naive datetime (no timezone) + mock_session.expiresAt = datetime(2020, 1, 1) + mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session + + result = SessionManager.validateSession(mock_db, "sess-123", userId=1) + assert result is False + + def test_validate_session_no_expiry(self): + """Exercises the expiresAt-is-None branch (line 143).""" + from main.app.authentication.session import SessionManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_session.isActive = True + mock_session.expiresAt = None + mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session + + result = SessionManager.validateSession(mock_db, "sess-123", userId=1) + assert result is True + + +# --------------------------------------------------------------------------- +# SSO (sso.py) +# --------------------------------------------------------------------------- diff --git a/tests/test_sso_state_cookie.py b/tests/test_sso_state_cookie.py index 70b7d67..2840111 100644 --- a/tests/test_sso_state_cookie.py +++ b/tests/test_sso_state_cookie.py @@ -133,7 +133,7 @@ def test_redirects_to_url_in_state(self): patch("main.controller.authentication_controller.getGoogleSSO", return_value=mock_sso), patch("main.controller.authentication_controller.AuthenticationManager") as mock_auth_mgr, patch("main.controller.authentication_controller.SessionManager") as mock_session_mgr, - patch("main.controller.authentication_controller.createAccessToken", return_value=("jwt-test", None)), + patch("main.controller.authentication_controller.createAccessToken", return_value="jwt-test"), ): mock_auth_mgr.authenticateGoogleUser.return_value = { "userId": 1, @@ -177,7 +177,7 @@ def test_returns_json_when_no_redirect_in_state(self): patch("main.controller.authentication_controller.getGoogleSSO", return_value=mock_sso), patch("main.controller.authentication_controller.AuthenticationManager") as mock_auth_mgr, patch("main.controller.authentication_controller.SessionManager") as mock_session_mgr, - patch("main.controller.authentication_controller.createAccessToken", return_value=("jwt-none", None)), + patch("main.controller.authentication_controller.createAccessToken", return_value="jwt-none"), ): mock_auth_mgr.authenticateGoogleUser.return_value = { "userId": 2, @@ -244,3 +244,48 @@ def test_url_in_state_survives_round_trip(self): encoded = urlencode({"state": state}) decoded = parse_qs(encoded).get("state", [None])[0] assert decoded == state + + +# ---- moved from test_prometheus_auth_coverage.py (TestSSO) ---- + + +class TestSSO: + """Cover getGoogleSSO (lines 6-14).""" + + @patch("main.app.authentication.sso.Config") + @patch("main.app.authentication.sso.GoogleSSO") + def test_get_google_sso_with_redirect(self, mock_google_sso, mock_config): + from main.app.authentication.sso import getGoogleSSO + + mock_config.USER = MagicMock( + GOOGLE_CLIENT_ID="cid", + GOOGLE_CLIENT_SECRET="csecret", + GOOGLE_REDIRECT_URI="http://callback", + ) + + result = getGoogleSSO(redirectUri="http://custom-callback") + + mock_google_sso.assert_called_once_with( + client_id="cid", + client_secret="csecret", + redirect_uri="http://custom-callback", + ) + + @patch("main.app.authentication.sso.Config") + @patch("main.app.authentication.sso.GoogleSSO") + def test_get_google_sso_default_redirect(self, mock_google_sso, mock_config): + from main.app.authentication.sso import getGoogleSSO + + mock_config.USER = MagicMock( + GOOGLE_CLIENT_ID="cid", + GOOGLE_CLIENT_SECRET="csecret", + GOOGLE_REDIRECT_URI="http://default-callback", + ) + + result = getGoogleSSO() + + mock_google_sso.assert_called_once_with( + client_id="cid", + client_secret="csecret", + redirect_uri="http://default-callback", + ) diff --git a/tests/test_stocks_api_coverage.py b/tests/test_stocks_api_coverage.py index 9ab05bc..6df33d9 100644 --- a/tests/test_stocks_api_coverage.py +++ b/tests/test_stocks_api_coverage.py @@ -14,6 +14,8 @@ import pandas as pd import numpy as np +from main.app.stocks_api import query as queryModule + @pytest.fixture(autouse=True) def clear_cashews_cache(): @@ -47,6 +49,16 @@ def make_stocks_df(rows=3): return pd.DataFrame(data) +def make_query_manager(cache_df=None): + """Single shared query helper (mock cache + optional data).""" + from main.app.stocks_api.cache import StocksCacheManager + + mock_cache = MagicMock(spec=StocksCacheManager) + mock_cache.STOCKS_CACHE = cache_df + mock_cache.tickerIndex = {} + return mock_cache + + # =========================================================================== # Tests for cache.py – StocksCacheManager # =========================================================================== @@ -276,84 +288,82 @@ def test_verify_api_key_generic_exception_rollback(self, mock_config): # =========================================================================== -# Tests for query.py – StocksQueryManager +# Tests for query.py – module query functions # =========================================================================== class TestDeserializeJsonColumns: """Tests covering query.py lines 22-48.""" def make_manager(self): - from main.app.stocks_api.cache import StocksCacheManager - - mock_cache = MagicMock(spec=StocksCacheManager) - from main.app.stocks_api.query import StocksQueryManager - - return StocksQueryManager(mock_cache) + return make_query_manager() def test_deserialize_empty_df(self): mgr = self.make_manager() df = pd.DataFrame() - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) assert result.empty def test_deserialize_returns_copy(self): mgr = self.make_manager() df = pd.DataFrame({"PRECO": [10.0]}) - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) assert result is not df def test_deserialize_json_dict_in_special_col(self): mgr = self.make_manager() json_str = json.dumps({"key": "value", "nested": {"a": 1}}) df = pd.DataFrame({"COTACAO 10Y PADRAO": [json_str], "TICKER": ["A"]}) - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) assert result["COTACAO 10Y PADRAO"].iloc[0] == {"key": "value", "nested": {"a": 1}} def test_deserialize_json_list_in_special_col(self): mgr = self.make_manager() json_str = json.dumps([1, 2, 3]) df = pd.DataFrame({"HISTORICO DIVIDENDOS": [json_str], "TICKER": ["A"]}) - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) assert result["HISTORICO DIVIDENDOS"].iloc[0] == [1, 2, 3] def test_deserialize_nan_in_dict_replaced(self): mgr = self.make_manager() - json_str = json.dumps({"key": float("nan")}) - df = pd.DataFrame({"NOTICIAS": [json_str], "TICKER": ["A"]}) - result = mgr.deserializeJsonColumns(df) + df = pd.DataFrame({"NOTICIAS": [[{"key": float("nan")}][0]], "TICKER": ["A"]}) + result = queryModule.deserializeJsonColumns(df) assert result["NOTICIAS"].iloc[0]["key"] is None def test_deserialize_nan_in_list_replaced(self): mgr = self.make_manager() - json_str = json.dumps([float("nan"), "ok"]) - df = pd.DataFrame({"NOTICIAS": [json_str], "TICKER": ["A"]}) - result = mgr.deserializeJsonColumns(df) + df = pd.DataFrame({"NOTICIAS": [[[float("nan"), "ok"]][0]], "TICKER": ["A"]}) + result = queryModule.deserializeJsonColumns(df) assert result["NOTICIAS"].iloc[0][0] is None assert result["NOTICIAS"].iloc[0][1] == "ok" def test_deserialize_nested_nan_in_dict(self): mgr = self.make_manager() - json_str = json.dumps({"outer": {"inner": float("nan")}}) - df = pd.DataFrame({"COTACAO 10Y AJUSTADA": [json_str], "TICKER": ["A"]}) - result = mgr.deserializeJsonColumns(df) + df = pd.DataFrame({"COTACAO 10Y AJUSTADA": [[{"outer": {"inner": float("nan")}}][0]], "TICKER": ["A"]}) + result = queryModule.deserializeJsonColumns(df) assert result["COTACAO 10Y AJUSTADA"].iloc[0]["outer"]["inner"] is None + def test_deserialize_invalid_json_passes_through(self): + mgr = self.make_manager() + df = pd.DataFrame({"NOTICIAS": ['{"key": NaN}'], "TICKER": ["A"]}) + result = queryModule.deserializeJsonColumns(df) + assert result["NOTICIAS"].iloc[0] == '{"key": NaN}' + def test_deserialize_non_special_col_not_parsed(self): mgr = self.make_manager() json_str = json.dumps({"key": "value"}) df = pd.DataFrame({"PRECO": [json_str], "TICKER": ["A"]}) - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) assert result["PRECO"].iloc[0] == json_str def test_deserialize_non_string_value_not_parsed(self): mgr = self.make_manager() df = pd.DataFrame({"NOTICIAS": [12345], "TICKER": ["A"]}) - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) assert result["NOTICIAS"].iloc[0] == 12345 def test_deserialize_string_not_json_not_parsed(self): mgr = self.make_manager() df = pd.DataFrame({"NOTICIAS": ["just text"], "TICKER": ["A"]}) - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) assert result["NOTICIAS"].iloc[0] == "just text" def test_deserialize_float_nan_direct(self): @@ -361,7 +371,7 @@ def test_deserialize_float_nan_direct(self): mgr = self.make_manager() json_str = json.dumps(float("nan")) df = pd.DataFrame({"NOTICIAS": [json_str], "TICKER": ["A"]}) - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) # json.loads of "NaN" produces float nan; the value doesn't start with { or [ # so it stays as-is (the string "NaN" in JSON, loaded as float nan) # Actually json.dumps(float("nan")) -> "NaN" which is not valid JSON but Python produces it @@ -375,7 +385,7 @@ def test_deserialize_non_nan_float(self): mgr = self.make_manager() json_str = json.dumps(3.14) # "3.14" df = pd.DataFrame({"NOTICIAS": [json_str], "TICKER": ["A"]}) - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) # "3.14" doesn't start with { or [, so lambda returns x as-is (string) assert result["NOTICIAS"].iloc[0] == "3.14" @@ -383,7 +393,7 @@ def test_deserialize_pd_na_value(self): """pd.NA is not a string, so lambda returns it unchanged.""" mgr = self.make_manager() df = pd.DataFrame({"NOTICIAS": [pd.NA], "TICKER": ["A"]}) - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) # pd.NA is not a string, so lambda returns x unchanged # The replaceNan function is never called assert result is not None @@ -403,7 +413,7 @@ def test_deserialize_mixed_string_none_parses_json(self): "TICKER": ["AALR3", "VALE3"], } ) - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) # Row with JSON string should be parsed into a list of dicts assert isinstance(result["COTACAO 10Y PADRAO"].iloc[0], list) assert result["COTACAO 10Y PADRAO"].iloc[0][0]["DATA"] == "01-12-2016" @@ -424,7 +434,7 @@ def test_deserialize_multiple_special_cols_with_none(self): "TICKER": ["AALR3", "VALE3"], } ) - result = mgr.deserializeJsonColumns(df) + result = queryModule.deserializeJsonColumns(df) # Each SPECIAL_COL with data should be parsed assert isinstance(result["COTACAO 10Y PADRAO"].iloc[0], list) assert isinstance(result["COTACAO 10Y AJUSTADA"].iloc[1], list) @@ -439,82 +449,60 @@ class TestFilterBySearchTerms: """Tests covering query.py lines 50-67.""" def make_manager(self): - from main.app.stocks_api.cache import StocksCacheManager - - mock_cache = MagicMock(spec=StocksCacheManager) - from main.app.stocks_api.query import StocksQueryManager - - return StocksQueryManager(mock_cache) + return make_query_manager() def test_filter_empty_search_returns_all(self): mgr = self.make_manager() df = pd.DataFrame({"TICKER": ["A", "B"]}) - result = mgr.filterBySearchTerms(df, "") - assert len(result) == 2 - - def test_filter_ticker_index_hit(self): - mgr = self.make_manager() - mgr.cacheManager.tickerIndex = {"PETR4": 0, "VALE3": 2} - df = pd.DataFrame({"TICKER": ["PETR4", "ITUB4", "VALE3"]}) - result = mgr.filterBySearchTerms(df, "PETR4") - assert len(result) == 1 - assert result.iloc[0]["TICKER"] == "PETR4" - - def test_filter_multiple_terms_index(self): - mgr = self.make_manager() - mgr.cacheManager.tickerIndex = {"PETR4": 0, "VALE3": 2} - df = pd.DataFrame({"TICKER": ["PETR4", "ITUB4", "VALE3"]}) - result = mgr.filterBySearchTerms(df, "PETR4, VALE3") + result = queryModule.filterBySearchTerms(df, "") assert len(result) == 2 - def test_filter_no_index_match_fallback_to_str(self): - mgr = self.make_manager() - mgr.cacheManager.tickerIndex = {} + @pytest.mark.parametrize( + "search,expected", + [ + ("PETR4", ["PETR4"]), + ("PETR4, VALE3", ["PETR4", "VALE3"]), + ], + ) + def test_filter_ticker_index(self, search, expected): df = pd.DataFrame({"TICKER": ["PETR4", "ITUB4", "VALE3"]}) - result = mgr.filterBySearchTerms(df, "PET") - assert len(result) == 1 - assert result.iloc[0]["TICKER"] == "PETR4" - - def test_filter_fallback_multiple_terms(self): + result = queryModule.filterBySearchTerms(df, search, {"PETR4": 0, "VALE3": 2}) + assert result["TICKER"].tolist() == expected + + @pytest.mark.parametrize( + "tickers,search,expected", + [ + (["PETR4", "ITUB4", "VALE3"], "PET", ["PETR4"]), + (["PETR4", "PETR3", "VALE3"], "PETR", ["PETR4", "PETR3"]), + (["PETR4"], "petr", ["PETR4"]), + ], + ) + def test_filter_fallback_str_match(self, tickers, search, expected): mgr = self.make_manager() - mgr.cacheManager.tickerIndex = {} - df = pd.DataFrame({"TICKER": ["PETR4", "PETR3", "VALE3"]}) - result = mgr.filterBySearchTerms(df, "PETR") - assert len(result) == 2 - - def test_filter_case_insensitive(self): - mgr = self.make_manager() - mgr.cacheManager.tickerIndex = {} - df = pd.DataFrame({"TICKER": ["PETR4"]}) - result = mgr.filterBySearchTerms(df, "petr") - assert len(result) == 1 + mgr.tickerIndex = {} + df = pd.DataFrame({"TICKER": tickers}) + result = queryModule.filterBySearchTerms(df, search) + assert result["TICKER"].tolist() == expected class TestQueryHistorical: """Tests covering query.py lines 77-132.""" def make_manager(self, cache_df=None): - from main.app.stocks_api.cache import StocksCacheManager - - mock_cache = MagicMock(spec=StocksCacheManager) - mock_cache.STOCKS_CACHE = cache_df - mock_cache.tickerIndex = {} - from main.app.stocks_api.query import StocksQueryManager - - return StocksQueryManager(mock_cache) + return make_query_manager(cache_df) def test_cache_not_initialized_raises_503(self): mgr = self.make_manager(cache_df=None) from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryHistorical(search="TEST0") + queryModule.queryHistorical(cacheManager=mgr, search="TEST0") assert exc_info.value.status_code == 503 def test_basic_historical_query(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryHistorical(search="TEST0") + result = queryModule.queryHistorical(cacheManager=mgr, search="TEST0") assert result["type"] == "historical" assert result["count"] > 0 assert "data" in result @@ -523,8 +511,8 @@ def test_basic_historical_query(self): def test_historical_with_search(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - mgr.cacheManager.tickerIndex = {"TEST0": 0} - result = mgr.queryHistorical(search="TEST0") + mgr.tickerIndex = {"TEST0": 0} + result = queryModule.queryHistorical(cacheManager=mgr, search="TEST0") assert result["search"] == "TEST0" assert result["count"] == 1 @@ -533,25 +521,25 @@ def test_historical_with_fields(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) # categorizeColumns returns key="LUCRO LIQUIDO", not "LUCRO LIQUIDO 2023" - result = mgr.queryHistorical(fields="LUCRO LIQUIDO") + result = queryModule.queryHistorical(cacheManager=mgr, fields="LUCRO LIQUIDO") assert "LUCRO LIQUIDO" in result["fields"] def test_historical_with_dates(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryHistorical(dates="2023") + result = queryModule.queryHistorical(cacheManager=mgr, dates="2023") assert result["dates"] == [2023, 2023] def test_historical_with_order_by(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryHistorical(search="TEST0", orderBy="PRECO") + result = queryModule.queryHistorical(cacheManager=mgr, search="TEST0", orderBy="PRECO") assert result["type"] == "historical" def test_historical_with_limit(self): df = make_stocks_df(rows=5) mgr = self.make_manager(cache_df=df) - result = mgr.queryHistorical(search="TEST", limit=2) + result = queryModule.queryHistorical(cacheManager=mgr, search="TEST", limit=2) assert result["count"] == 2 def test_historical_no_historical_fields(self): @@ -561,21 +549,21 @@ def test_historical_no_historical_fields(self): from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryHistorical(search="TEST0") + queryModule.queryHistorical(cacheManager=mgr, search="TEST0") # HTTPException raised inside try is re-raised as-is (client error, not 500) assert exc_info.value.status_code == 400 def test_historical_sorts_by_time(self): df = make_stocks_df(rows=3) mgr = self.make_manager(cache_df=df) - result = mgr.queryHistorical(search="TEST0") + result = queryModule.queryHistorical(cacheManager=mgr, search="TEST0") assert result["type"] == "historical" def test_historical_deduplicates_by_ticker(self): df = make_stocks_df(rows=3) df = pd.concat([df, df.iloc[[0]]], ignore_index=True) mgr = self.make_manager(cache_df=df) - result = mgr.queryHistorical(search="TEST0") + result = queryModule.queryHistorical(cacheManager=mgr, search="TEST0") tickers = [d["TICKER"] for d in result["data"]] assert len(tickers) == len(set(tickers)) @@ -590,11 +578,11 @@ class ExplodingDf: def columns(self): raise Exception("simulated failure") - mgr.cacheManager.STOCKS_CACHE = ExplodingDf() + mgr.STOCKS_CACHE = ExplodingDf() from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryHistorical(search="TEST0") + queryModule.queryHistorical(cacheManager=mgr, search="TEST0") assert exc_info.value.status_code == 500 def test_historical_with_invalid_dates(self): @@ -604,13 +592,13 @@ def test_historical_with_invalid_dates(self): from fastapi import HTTPException with pytest.raises(HTTPException): - mgr.queryHistorical(dates="2020,2021,2022") + queryModule.queryHistorical(cacheManager=mgr, dates="2020,2021,2022") def test_historical_search_with_no_results(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - mgr.cacheManager.tickerIndex = {} - result = mgr.queryHistorical(search="ZZZZ") + mgr.tickerIndex = {} + result = queryModule.queryHistorical(cacheManager=mgr, search="ZZZZ") assert result["count"] == 0 def test_historical_no_fields_collected(self): @@ -620,22 +608,22 @@ def test_historical_no_fields_collected(self): from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryHistorical(fields="NONEXISTENT_FIELD") + queryModule.queryHistorical(cacheManager=mgr, fields="NONEXISTENT_FIELD") assert exc_info.value.status_code == 400 def test_historical_with_date_range(self): """Historical query with a year range.""" df = make_stocks_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryHistorical(dates="2022,2023") + result = queryModule.queryHistorical(cacheManager=mgr, dates="2022,2023") assert result["dates"] == [2022, 2023] def test_historical_search_multiple_terms_index(self): """Multiple search terms, all found in tickerIndex.""" df = make_stocks_df(rows=5) mgr = self.make_manager(cache_df=df) - mgr.cacheManager.tickerIndex = {"TEST0": 0, "TEST2": 2, "TEST4": 4} - result = mgr.queryHistorical(search="TEST0,TEST2,TEST4") + mgr.tickerIndex = {"TEST0": 0, "TEST2": 2, "TEST4": 4} + result = queryModule.queryHistorical(cacheManager=mgr, search="TEST0,TEST2,TEST4") assert result["count"] == 3 def test_historical_requires_search_fields_or_dates(self): @@ -645,7 +633,9 @@ def test_historical_requires_search_fields_or_dates(self): from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryHistorical() + queryModule.queryHistorical( + cacheManager=mgr, + ) assert exc_info.value.status_code == 400 @@ -653,27 +643,20 @@ class TestQueryFundamental: """Tests covering query.py lines 142-202.""" def make_manager(self, cache_df=None): - from main.app.stocks_api.cache import StocksCacheManager - - mock_cache = MagicMock(spec=StocksCacheManager) - mock_cache.STOCKS_CACHE = cache_df - mock_cache.tickerIndex = {} - from main.app.stocks_api.query import StocksQueryManager - - return StocksQueryManager(mock_cache) + return make_query_manager(cache_df) def test_cache_not_initialized_raises_503(self): mgr = self.make_manager(cache_df=None) from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryFundamental(search="TEST0") + queryModule.queryFundamental(cacheManager=mgr, search="TEST0") assert exc_info.value.status_code == 503 def test_basic_fundamental_query(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(search="TEST0") + result = queryModule.queryFundamental(cacheManager=mgr, search="TEST0") assert result["type"] == "fundamental" assert result["count"] > 0 assert "data" in result @@ -681,26 +664,26 @@ def test_basic_fundamental_query(self): def test_fundamental_with_search(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - mgr.cacheManager.tickerIndex = {"TEST0": 0} - result = mgr.queryFundamental(search="TEST0") + mgr.tickerIndex = {"TEST0": 0} + result = queryModule.queryFundamental(cacheManager=mgr, search="TEST0") assert result["search"] == "TEST0" def test_fundamental_with_fields(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(fields="PRECO,P/L") + result = queryModule.queryFundamental(cacheManager=mgr, fields="PRECO,P/L") assert "PRECO" in result["fields"] def test_fundamental_with_date_range(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(dates="2024-01-01,2024-12-31") + result = queryModule.queryFundamental(cacheManager=mgr, dates="2024-01-01,2024-12-31") assert result["type"] == "fundamental" def test_fundamental_with_single_date(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(dates="2024-01-15") + result = queryModule.queryFundamental(cacheManager=mgr, dates="2024-01-15") assert result["type"] == "fundamental" def test_fundamental_with_invalid_date(self): @@ -710,33 +693,33 @@ def test_fundamental_with_invalid_date(self): from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryFundamental(dates="not-a-date,also-not-a-date") + queryModule.queryFundamental(cacheManager=mgr, dates="not-a-date,also-not-a-date") assert exc_info.value.status_code == 400 def test_fundamental_with_order_by(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(search="TEST0", orderBy="PRECO") + result = queryModule.queryFundamental(cacheManager=mgr, search="TEST0", orderBy="PRECO") assert result["type"] == "fundamental" def test_fundamental_with_limit(self): df = make_stocks_df(rows=5) mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(fields="PRECO", limit=2) + result = queryModule.queryFundamental(cacheManager=mgr, fields="PRECO", limit=2) assert result["count"] == 2 def test_fundamental_deduplicates_without_search(self): df = make_stocks_df(rows=3) df = pd.concat([df, df.iloc[[0]]], ignore_index=True) mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(fields="PRECO") + result = queryModule.queryFundamental(cacheManager=mgr, fields="PRECO") tickers = [d["TICKER"] for d in result["data"]] assert len(tickers) == len(set(tickers)) def test_fundamental_with_search_no_dedup(self): df = make_stocks_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(search="TEST") + result = queryModule.queryFundamental(cacheManager=mgr, search="TEST") assert result["type"] == "fundamental" def test_fundamental_exception_returns_500(self): @@ -749,11 +732,11 @@ class ExplodingDf: def columns(self): raise Exception("simulated failure") - mgr.cacheManager.STOCKS_CACHE = ExplodingDf() + mgr.STOCKS_CACHE = ExplodingDf() from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryFundamental(search="TEST0") + queryModule.queryFundamental(cacheManager=mgr, search="TEST0") assert exc_info.value.status_code == 500 def test_fundamental_empty_search_string_no_dedup(self): @@ -761,7 +744,7 @@ def test_fundamental_empty_search_string_no_dedup(self): df = make_stocks_df(rows=3) df = pd.concat([df, df.iloc[[0]]], ignore_index=True) mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(search=" ") + result = queryModule.queryFundamental(cacheManager=mgr, search=" ") tickers = [d["TICKER"] for d in result["data"]] assert len(tickers) == len(set(tickers)) @@ -775,7 +758,7 @@ def test_fundamental_no_time_column(self): } ) mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(search="TEST0") + result = queryModule.queryFundamental(cacheManager=mgr, search="TEST0") assert result["type"] == "fundamental" def test_fundamental_date_range_two_dates(self): @@ -789,7 +772,7 @@ def test_fundamental_date_range_two_dates(self): } ) mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(dates="2024-01-01,2024-06-30") + result = queryModule.queryFundamental(cacheManager=mgr, dates="2024-01-01,2024-06-30") assert result["count"] >= 1 def test_fundamental_with_invalid_single_date(self): @@ -799,7 +782,7 @@ def test_fundamental_with_invalid_single_date(self): from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryFundamental(dates="not-a-date") + queryModule.queryFundamental(cacheManager=mgr, dates="not-a-date") assert exc_info.value.status_code == 400 def test_fundamental_fields_not_in_columns(self): @@ -814,7 +797,7 @@ def test_fundamental_fields_not_in_columns(self): ) mgr = self.make_manager(cache_df=df) with pytest.raises(HTTPException) as exc_info: - mgr.queryFundamental(fields="NONEXISTENT,P/L") + queryModule.queryFundamental(cacheManager=mgr, fields="NONEXISTENT,P/L") assert exc_info.value.status_code == 400 assert "NONEXISTENT" in exc_info.value.detail assert "/stocks/fields" in exc_info.value.detail @@ -823,16 +806,16 @@ def test_fundamental_search_multiple_terms(self): """Multiple search terms with tickerIndex.""" df = make_stocks_df(rows=5) mgr = self.make_manager(cache_df=df) - mgr.cacheManager.tickerIndex = {"TEST0": 0, "TEST3": 3} - result = mgr.queryFundamental(search="TEST0,TEST3") + mgr.tickerIndex = {"TEST0": 0, "TEST3": 3} + result = queryModule.queryFundamental(cacheManager=mgr, search="TEST0,TEST3") assert result["count"] == 2 def test_fundamental_search_fallback_string_match(self): """Search with no index match falls back to string startswith.""" df = make_stocks_df(rows=3) mgr = self.make_manager(cache_df=df) - mgr.cacheManager.tickerIndex = {} - result = mgr.queryFundamental(search="TEST") + mgr.tickerIndex = {} + result = queryModule.queryFundamental(cacheManager=mgr, search="TEST") assert result["count"] == 3 def test_fundamental_dates_one_date(self): @@ -846,7 +829,7 @@ def test_fundamental_dates_one_date(self): } ) mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(dates="2024-01-15") + result = queryModule.queryFundamental(cacheManager=mgr, dates="2024-01-15") # Per-ticker: each gets its closest snapshot (A→2024-01-15, B→2024-06-15) assert result["count"] == 2 @@ -870,7 +853,7 @@ def test_fundamental_excludes_cotacao_10y(self): } ) mgr = self.make_manager(cache_df=df) - result = mgr.queryFundamental(search="TEST0") + result = queryModule.queryFundamental(cacheManager=mgr, search="TEST0") assert "COTACAO 10Y PADRAO" not in result["fields"] assert "COTACAO 10Y AJUSTADA" not in result["fields"] for d in result["data"]: @@ -882,7 +865,6 @@ def test_fundamental_does_not_mutate_cache_time_dtype(self): Bug at line 243: df["TIME"] = ... on a view of STOCKS_CACHE converted datetime64 -> object strings on first call, breaking /cotations sort.""" from main.app.stocks_api.cache import StocksCacheManager - from main.app.stocks_api.query import StocksQueryManager cache = MagicMock(spec=StocksCacheManager) cache.STOCKS_CACHE = pd.DataFrame( @@ -894,10 +876,10 @@ def test_fundamental_does_not_mutate_cache_time_dtype(self): } ) cache.tickerIndex = {} - mgr = StocksQueryManager(cache) + mgr = cache original_dtype = cache.STOCKS_CACHE["TIME"].dtype - mgr.queryFundamental(search="TEST0") + queryModule.queryFundamental(cacheManager=mgr, search="TEST0") assert cache.STOCKS_CACHE["TIME"].dtype == original_dtype def test_fundamental_requires_search_fields_or_dates(self): @@ -906,7 +888,9 @@ def test_fundamental_requires_search_fields_or_dates(self): from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryFundamental() + queryModule.queryFundamental( + cacheManager=mgr, + ) assert exc_info.value.status_code == 400 @@ -925,12 +909,11 @@ class TestQueryCotations: def make_manager(self, cache_df=None): from main.app.stocks_api.cache import StocksCacheManager - from main.app.stocks_api.query import StocksQueryManager mock_cache = MagicMock(spec=StocksCacheManager) mock_cache.STOCKS_CACHE = cache_df mock_cache.tickerIndex = {} - return StocksQueryManager(mock_cache) + return mock_cache def make_cotations_df(self, with_padrao=True, with_ajustada=True): """2 tickers x 2 rows. Rows 0,2 are 2024-01-15; rows 1,3 are 2024-06-15. @@ -954,14 +937,14 @@ def test_cotations_cache_not_initialized_raises_503(self): from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryCotations(adjusted=False) + queryModule.queryCotations(cacheManager=mgr, adjusted=False) assert exc_info.value.status_code == 503 # --- adjusted=False -> PADRAO --- def test_cotations_adjusted_false_returns_padrao(self): df = self.make_cotations_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryCotations(adjusted=False) + result = queryModule.queryCotations(cacheManager=mgr, adjusted=False) assert result["type"] == "cotations" assert result["fields"] == ["COTACAO 10Y PADRAO"] assert "COTACAO 10Y PADRAO" in result["data"][0] @@ -971,7 +954,7 @@ def test_cotations_adjusted_false_returns_padrao(self): def test_cotations_adjusted_true_returns_ajustada(self): df = self.make_cotations_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryCotations(adjusted=True) + result = queryModule.queryCotations(cacheManager=mgr, adjusted=True) assert result["type"] == "cotations" assert result["fields"] == ["COTACAO 10Y AJUSTADA"] assert "COTACAO 10Y AJUSTADA" in result["data"][0] @@ -982,7 +965,7 @@ def test_cotations_returns_most_recent_per_ticker(self): """4 rows for 2 tickers -> 2 results, one per ticker, both with latest TIME.""" df = self.make_cotations_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryCotations(adjusted=False) + result = queryModule.queryCotations(cacheManager=mgr, adjusted=False) assert result["count"] == 2 tickers = {d["TICKER"] for d in result["data"]} assert tickers == {"TEST0", "TEST1"} @@ -994,7 +977,7 @@ def test_cotations_dates_filter_inner_json_data(self): """dates="2016-12-02" should keep only the 02-12-2016 entry in each JSON list.""" df = self.make_cotations_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryCotations(adjusted=False, dates="2016-12-02,2016-12-02") + result = queryModule.queryCotations(cacheManager=mgr, adjusted=False, dates="2016-12-02,2016-12-02") assert result["count"] == 2 for d in result["data"]: cotation = d["COTACAO 10Y PADRAO"] @@ -1005,7 +988,7 @@ def test_cotations_dates_filter_inner_json_data(self): def test_cotations_dates_range_keeps_all_inner_entries(self): df = self.make_cotations_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryCotations(adjusted=False, dates="2016-12-01,2016-12-31") + result = queryModule.queryCotations(cacheManager=mgr, adjusted=False, dates="2016-12-01,2016-12-31") assert result["count"] == 2 for d in result["data"]: assert len(d["COTACAO 10Y PADRAO"]) == 2 @@ -1013,7 +996,7 @@ def test_cotations_dates_range_keeps_all_inner_entries(self): def test_cotations_no_dates_keeps_all_inner_entries(self): df = self.make_cotations_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryCotations(adjusted=False) + result = queryModule.queryCotations(cacheManager=mgr, adjusted=False) for d in result["data"]: assert len(d["COTACAO 10Y PADRAO"]) == 2 @@ -1021,8 +1004,8 @@ def test_cotations_no_dates_keeps_all_inner_entries(self): def test_cotations_with_search_filter(self): df = self.make_cotations_df() mgr = self.make_manager(cache_df=df) - mgr.cacheManager.tickerIndex = {"TEST0": 0, "TEST1": 2} - result = mgr.queryCotations(adjusted=False, search="TEST0") + mgr.tickerIndex = {"TEST0": 0, "TEST1": 2} + result = queryModule.queryCotations(cacheManager=mgr, adjusted=False, search="TEST0") assert result["search"] == "TEST0" assert result["count"] == 1 assert result["data"][0]["TICKER"] == "TEST0" @@ -1030,15 +1013,15 @@ def test_cotations_with_search_filter(self): def test_cotations_with_search_multiple_terms(self): df = self.make_cotations_df() mgr = self.make_manager(cache_df=df) - mgr.cacheManager.tickerIndex = {"TEST0": 0, "TEST1": 2} - result = mgr.queryCotations(adjusted=True, search="TEST0,TEST1") + mgr.tickerIndex = {"TEST0": 0, "TEST1": 2} + result = queryModule.queryCotations(cacheManager=mgr, adjusted=True, search="TEST0,TEST1") assert result["count"] == 2 # --- missing column -> empty --- def test_cotations_missing_column_returns_empty(self): df = self.make_cotations_df(with_padrao=False, with_ajustada=False) mgr = self.make_manager(cache_df=df) - result = mgr.queryCotations(adjusted=False) + result = queryModule.queryCotations(cacheManager=mgr, adjusted=False) assert result["count"] == 0 assert result["data"] == [] assert result["fields"] == ["COTACAO 10Y PADRAO"] @@ -1048,20 +1031,20 @@ def test_cotations_missing_column_returns_empty(self): def test_cotations_dates_param_stored(self): df = self.make_cotations_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryCotations(adjusted=False, dates="2020-01-01,2024-12-31") + result = queryModule.queryCotations(cacheManager=mgr, adjusted=False, dates="2020-01-01,2024-12-31") assert result["dates"] == "2020-01-01,2024-12-31" def test_cotations_dates_default_none(self): df = self.make_cotations_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryCotations(adjusted=False) + result = queryModule.queryCotations(cacheManager=mgr, adjusted=False) assert result["dates"] is None # --- default search --- def test_cotations_default_search_all(self): df = self.make_cotations_df() mgr = self.make_manager(cache_df=df) - result = mgr.queryCotations(adjusted=False) + result = queryModule.queryCotations(cacheManager=mgr, adjusted=False) assert result["search"] == "all" # --- exception -> 500 --- @@ -1072,19 +1055,19 @@ def test_cotations_exception_returns_500(self): from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: - mgr.queryCotations(adjusted=False) + queryModule.queryCotations(cacheManager=mgr, adjusted=False) assert exc_info.value.status_code == 500 # --- HTTP integration: /stocks/cotations route (one test, parametrized conceptually) --- def test_cotations_http_route(self, stocks_http_client): """Hit the actual /stocks/cotations HTTP endpoint with adjusted=false.""" - from main.app.stocks_api.query import stocksQuery + from main.app.stocks_api.cache import stocksCache - original_cache = stocksQuery.cacheManager.STOCKS_CACHE - original_index = stocksQuery.cacheManager.tickerIndex + original_cache = stocksCache.STOCKS_CACHE + original_index = stocksCache.tickerIndex try: - stocksQuery.cacheManager.STOCKS_CACHE = self.make_cotations_df() - stocksQuery.cacheManager.tickerIndex = {"TEST0": 0, "TEST1": 2} + stocksCache.STOCKS_CACHE = self.make_cotations_df() + stocksCache.tickerIndex = {"TEST0": 0, "TEST1": 2} resp = stocks_http_client.get("/stocks/cotations?adjusted=false&dates=2016-12-02,2016-12-02&search=TEST0") assert resp.status_code == 200 body = resp.json() @@ -1096,8 +1079,8 @@ def test_cotations_http_route(self, stocks_http_client): assert len(d["COTACAO 10Y PADRAO"]) == 1 assert d["COTACAO 10Y PADRAO"][0]["DATA"] == "02-12-2016" finally: - stocksQuery.cacheManager.STOCKS_CACHE = original_cache - stocksQuery.cacheManager.tickerIndex = original_index + stocksCache.STOCKS_CACHE = original_cache + stocksCache.tickerIndex = original_index # =========================================================================== @@ -1108,12 +1091,11 @@ class TestQueryLiveCotation: def make_manager(self): from main.app.stocks_api.cache import StocksCacheManager - from main.app.stocks_api.query import StocksQueryManager mock_cache = MagicMock(spec=StocksCacheManager) mock_cache.STOCKS_CACHE = pd.DataFrame() mock_cache.tickerIndex = {} - return StocksQueryManager(mock_cache) + return mock_cache def mock_b3_response(self): return { @@ -1154,7 +1136,7 @@ def patch_session(self, response=None, side_effect=None): def test_success_returns_correct_shape(self): mgr = self.make_manager() with self.patch_session(): - result = mgr.queryLiveCotation("WEGE3") + result = queryModule.queryLiveCotation("WEGE3") assert result["type"] == "realtime-cotation" assert result["search"] == "WEGE3" assert result["count"] == 1 @@ -1171,7 +1153,7 @@ def test_success_returns_correct_shape(self): def test_lowercase_ticker_uppercased(self): mgr = self.make_manager() with self.patch_session(): - result = mgr.queryLiveCotation("wege3") + result = queryModule.queryLiveCotation("wege3") assert result["search"] == "WEGE3" assert result["data"][0]["TICKER"] == "WEGE3" @@ -1216,7 +1198,7 @@ def test_b3_unavailable_returns_503(self): mgr = self.make_manager() with self.patch_session(side_effect=Exception("connection refused")): with pytest.raises(HTTPException) as exc_info: - mgr.queryLiveCotation("WEGE3") + queryModule.queryLiveCotation("WEGE3") assert exc_info.value.status_code == 503 def test_b3_bad_status_returns_404(self): @@ -1226,7 +1208,7 @@ def test_b3_bad_status_returns_404(self): payload = {"BizSts": {"cd": "ERR"}, "Trad": []} with self.patch_session(response=payload): with pytest.raises(HTTPException) as exc_info: - mgr.queryLiveCotation("WEGE3") + queryModule.queryLiveCotation("WEGE3") assert exc_info.value.status_code == 404 def test_http_route_returns_200(self, stocks_http_client): diff --git a/tests/test_stocks_presorted.py b/tests/test_stocks_presorted.py index 636b579..85d5eaa 100644 --- a/tests/test_stocks_presorted.py +++ b/tests/test_stocks_presorted.py @@ -14,7 +14,7 @@ import zstandard as zstd from main.app.stocks_api.cache import buildTickerIndex, sortCacheFrame -from main.app.stocks_api.query import StocksQueryManager +from main.app.stocks_api.query import queryCotations, queryFundamental, queryHistorical def makeFrame(): @@ -42,7 +42,7 @@ def makeFrame(): def makeManager(df): df = sortCacheFrame(df) - return StocksQueryManager(SimpleNamespace(STOCKS_CACHE=df, tickerIndex=buildTickerIndex(df))) + return SimpleNamespace(STOCKS_CACHE=df, tickerIndex=buildTickerIndex(df)) class TestSortCacheFrame: @@ -82,7 +82,7 @@ def test_index_points_at_most_recent_row(self): class TestPresortedQueryBehavior: def test_historical_keeps_most_recent_per_ticker(self): qm = makeManager(makeFrame()) - res = qm.queryHistorical(fields="PRECO") + res = queryHistorical(fields="PRECO", cacheManager=qm) assert res["count"] == 2 assert [r["TICKER"] for r in res["data"]] == ["AAA", "ZZZ"] assert res["data"][0]["PRECO 2023"] == 30.0 @@ -90,14 +90,14 @@ def test_historical_keeps_most_recent_per_ticker(self): def test_fundamental_range_keeps_latest_and_formats_time(self): qm = makeManager(makeFrame()) - res = qm.queryFundamental(fields="P/L", dates="2024-01-01,2024-12-31") + res = queryFundamental(fields="P/L", dates="2024-01-01,2024-12-31", cacheManager=qm) assert res["count"] == 2 assert [r["TIME"] for r in res["data"]] == ["2024-06-01"] * 2 assert [r["P/L"] for r in res["data"]] == [8.0, 8.0] def test_cotations_keeps_most_recent_per_ticker(self): qm = makeManager(makeFrame()) - res = qm.queryCotations(search="AAA,ZZZ") + res = queryCotations(search="AAA,ZZZ", cacheManager=qm) assert res["count"] == 2 assert res["data"][0]["COTACAO 10Y PADRAO"] == "cot-AAA-2024-06-01" assert res["data"][1]["COTACAO 10Y PADRAO"] == "cot-ZZZ-2024-06-01" @@ -124,11 +124,11 @@ def test_before_after_shape_timing_print_only(self, capsys): qm = makeManager(pd.DataFrame(rows)) start = time.perf_counter() - resHist = qm.queryHistorical(fields="PRECO") + resHist = queryHistorical(fields="PRECO", cacheManager=qm) histElapsed = time.perf_counter() - start start = time.perf_counter() - resCot = qm.queryCotations(search="T0001") + resCot = queryCotations(search="T0001", cacheManager=qm) cotElapsed = time.perf_counter() - start assert resHist["count"] == 120 From d12f65817d569b67f0dc5e0d2fef4c6df46faa20 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 13:25:08 -0300 Subject: [PATCH 29/57] trim redundant test helpers and duplicate coverage --- tests/test_api_key_quota_atomic.py | 113 +--- tests/test_compact.py | 160 ++--- tests/test_memory_maintenance.py | 16 - tests/test_memory_tools_wiring.py | 9 - tests/test_pagination.py | 90 --- tests/test_prometheus_agent_context.py | 219 +++++- tests/test_prometheus_auth_coverage.py | 884 ------------------------- tests/test_prometheus_resume.py | 210 ++++++ tests/test_relevance_score.py | 58 +- tests/test_sandbox.py | 18 +- tests/test_sandbox_persistence.py | 20 +- tests/test_stocks_api_coverage.py | 5 +- tests/test_stocks_cache_zstd.py | 5 +- tests/test_stocks_compress.py | 318 +++++---- tests/test_stocks_util.py | 99 --- tests/test_thread_safety.py | 153 +++-- 16 files changed, 779 insertions(+), 1598 deletions(-) delete mode 100644 tests/test_pagination.py delete mode 100644 tests/test_prometheus_auth_coverage.py delete mode 100644 tests/test_stocks_util.py diff --git a/tests/test_api_key_quota_atomic.py b/tests/test_api_key_quota_atomic.py index 4ccd4ce..25c779c 100644 --- a/tests/test_api_key_quota_atomic.py +++ b/tests/test_api_key_quota_atomic.py @@ -14,6 +14,20 @@ from main.models.stocksapi_key import StocksAPIKey from main.app.stocks_api.key import verifyAPIKey +TEST_KEY_HASH = hashlib.sha256("test_key_12345".encode()).hexdigest() + + +def quotaUpdate(dbSession, apiKey): + """Run the atomic quota-increment UPDATE; return affected rowcount.""" + result = dbSession.execute( + update(StocksAPIKey) + .where(StocksAPIKey.apiKey == apiKey) + .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) + .values(currentUsage=StocksAPIKey.currentUsage + 1) + ) + dbSession.commit() + return result.rowcount + @pytest.fixture def sampleKeyData(): @@ -35,18 +49,9 @@ def test_normal_quota_check_works(self, dbSession, sampleKeyData): mock_config.STOCKS_API = MagicMock(KEY_SYSTEM=True) # Run the atomic increment - from sqlalchemy import update - - result = dbSession.execute( - update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) - .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) - .values(currentUsage=StocksAPIKey.currentUsage + 1) - ) - dbSession.commit() + assert quotaUpdate(dbSession, TEST_KEY_HASH) == 1 # Verify increment happened - assert result.rowcount == 1 dbSession.refresh(key) assert key.currentUsage == 1 @@ -57,30 +62,16 @@ def test_atomic_increment_prevents_overuse(self, dbSession, sampleKeyData): dbSession.add(key) dbSession.commit() - from sqlalchemy import update - # First request should succeed (99 -> 100) - result1 = dbSession.execute( - update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) - .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) - .values(currentUsage=StocksAPIKey.currentUsage + 1) - ) + assert quotaUpdate(dbSession, TEST_KEY_HASH) == 1 dbSession.commit() - assert result1.rowcount == 1 dbSession.refresh(key) assert key.currentUsage == 100 # Second request should fail (100 is not < 100) - result2 = dbSession.execute( - update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) - .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) - .values(currentUsage=StocksAPIKey.currentUsage + 1) - ) + assert quotaUpdate(dbSession, TEST_KEY_HASH) == 0 dbSession.commit() - assert result2.rowcount == 0 # Usage should still be 100 dbSession.refresh(key) @@ -98,30 +89,15 @@ def test_concurrent_requests_serialized_at_db_level(self, dbSession, sampleKeyDa dbSession.add(key) dbSession.commit() - from sqlalchemy import update - # Simulate two concurrent requests # Both should succeed because 98 < 100 and 99 < 100 - result1 = dbSession.execute( - update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) - .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) - .values(currentUsage=StocksAPIKey.currentUsage + 1) - ) + assert quotaUpdate(dbSession, TEST_KEY_HASH) == 1 dbSession.commit() - result2 = dbSession.execute( - update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) - .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) - .values(currentUsage=StocksAPIKey.currentUsage + 1) - ) + assert quotaUpdate(dbSession, TEST_KEY_HASH) == 1 dbSession.commit() # Both should succeed - assert result1.rowcount == 1 - assert result2.rowcount == 1 - dbSession.refresh(key) assert key.currentUsage == 100 @@ -132,36 +108,18 @@ def test_request_at_exact_quota_limit(self, dbSession, sampleKeyData): dbSession.add(key) dbSession.commit() - from sqlalchemy import update - # Request should fail (100 is not < 100) - result = dbSession.execute( - update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) - .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) - .values(currentUsage=StocksAPIKey.currentUsage + 1) - ) + assert quotaUpdate(dbSession, TEST_KEY_HASH) == 0 dbSession.commit() - assert result.rowcount == 0 - dbSession.refresh(key) assert key.currentUsage == 100 def test_invalid_api_key_returns_zero_rows(self, dbSession): """Test that invalid API key returns zero rows affected.""" - from sqlalchemy import update - - result = dbSession.execute( - update(StocksAPIKey) - .where(StocksAPIKey.apiKey == "nonexistent_key") - .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) - .values(currentUsage=StocksAPIKey.currentUsage + 1) - ) + assert quotaUpdate(dbSession, "nonexistent_key") == 0 dbSession.commit() - assert result.rowcount == 0 - def test_multiple_keys_independent_quotas(self, dbSession): """Test that multiple API keys have independent quotas.""" key1 = StocksAPIKey(apiKey="key1", userId=1, requestLimit=100, currentUsage=99) @@ -169,27 +127,13 @@ def test_multiple_keys_independent_quotas(self, dbSession): dbSession.add_all([key1, key2]) dbSession.commit() - from sqlalchemy import update - # Increment key1 (should succeed: 99 -> 100) - result1 = dbSession.execute( - update(StocksAPIKey) - .where(StocksAPIKey.apiKey == "key1") - .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) - .values(currentUsage=StocksAPIKey.currentUsage + 1) - ) + assert quotaUpdate(dbSession, "key1") == 1 dbSession.commit() - assert result1.rowcount == 1 # Increment key2 (should succeed: 50 -> 51) - result2 = dbSession.execute( - update(StocksAPIKey) - .where(StocksAPIKey.apiKey == "key2") - .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) - .values(currentUsage=StocksAPIKey.currentUsage + 1) - ) + assert quotaUpdate(dbSession, "key2") == 1 dbSession.commit() - assert result2.rowcount == 1 # Verify independent increments dbSession.refresh(key1) @@ -203,17 +147,8 @@ def test_increment_from_zero(self, dbSession, sampleKeyData): dbSession.add(key) dbSession.commit() - from sqlalchemy import update - - result = dbSession.execute( - update(StocksAPIKey) - .where(StocksAPIKey.apiKey == hashlib.sha256("test_key_12345".encode()).hexdigest()) - .where(StocksAPIKey.currentUsage < StocksAPIKey.requestLimit) - .values(currentUsage=StocksAPIKey.currentUsage + 1) - ) - dbSession.commit() + assert quotaUpdate(dbSession, TEST_KEY_HASH) == 1 - assert result.rowcount == 1 dbSession.refresh(key) assert key.currentUsage == 1 diff --git a/tests/test_compact.py b/tests/test_compact.py index 824a6b7..c7b4a7a 100644 --- a/tests/test_compact.py +++ b/tests/test_compact.py @@ -19,36 +19,44 @@ ) -class TestExtractTickers: - def test_single_ticker(self): - assert extractTickers("Análise de PETR4") == ["PETR4"] - - def test_multiple_tickers(self): - result = extractTickers("PETR4 e VALE3 e ITUB4") - assert result == ["PETR4", "VALE3", "ITUB4"] - - def test_no_tickers(self): - assert extractTickers("nenhum ticker aqui") == [] +def mockDbFactory(first=None): + """Return a MagicMock db whose query chain resolves first() to `first`.""" + mockDb = MagicMock() + mockDb.query.return_value.filter.return_value.first.return_value = first + return mockDb - def test_deduplication(self): - assert extractTickers("PETR4 e depois PETR4") == ["PETR4"] - def test_does_not_match_4_letter_words(self): - assert extractTickers("HIGH e LOW") == [] - - def test_ticker_in_context(self): - text = "O P/L da PETR4 está abaixo de VALE3" - assert extractTickers(text) == ["PETR4", "VALE3"] +class TestExtractTickers: + @pytest.mark.parametrize( + "text,expected", + [ + ("Análise de PETR4", ["PETR4"]), + ("PETR4 e VALE3 e ITUB4", ["PETR4", "VALE3", "ITUB4"]), + ("PETR4 e depois PETR4", ["PETR4"]), + ("O P/L da PETR4 está abaixo de VALE3", ["PETR4", "VALE3"]), + ], + ) + def test_ticker_cases(self, text, expected): + assert extractTickers(text) == expected + + @pytest.mark.parametrize("text", ["nenhum ticker aqui", "HIGH e LOW"]) + def test_no_tickers_found(self, text): + assert extractTickers(text) == [] class TestExtractMetrics: - def test_single_metric(self): - assert "P/L" in extractMetrics("O P/L está em 5.2x") - - def test_multiple_metrics(self): - result = extractMetrics("ROE de 15% e DY de 8%") - assert "ROE" in result - assert "DY" in result + @pytest.mark.parametrize( + "text,expected", + [ + ("O P/L está em 5.2x", ["P/L"]), + ("ROE de 15% e DY de 8%", ["ROE", "DY"]), + ("P/L de 5x", ["P/L"]), + ], + ) + def test_metric_cases(self, text, expected): + result = extractMetrics(text) + for metric in expected: + assert metric in result def test_cagr_metrics(self): oldField, oldRegex = compactMod.fieldData, compactMod.metricRegex @@ -66,22 +74,20 @@ def test_cagr_metrics(self): def test_no_metrics(self): assert extractMetrics("texto sem métricas") == [] - def test_uses_fallback_when_no_registry(self): - result = extractMetrics("P/L de 5x") - assert "P/L" in result - class TestExtractDecisions: - def test_preference(self): - msgs = [{"content": "Prefiro ações de dividendos"}] - result = extractDecisions(msgs) - assert len(result) >= 1 - assert "dividendos" in result[0].lower() - - def test_always_keyword(self): - msgs = [{"content": "Sempre use P/VP abaixo de 1.0"}] - result = extractDecisions(msgs) + @pytest.mark.parametrize( + "content,keyword", + [ + ("Prefiro ações de dividendos", "dividendos"), + ("Sempre use P/VP abaixo de 1.0", None), + ], + ) + def test_decision_cases(self, content, keyword): + result = extractDecisions([{"content": content}]) assert len(result) >= 1 + if keyword is not None: + assert keyword in result[0].lower() def test_no_decisions(self): msgs = [{"content": "Qual é o P/L da PETR4?"}] @@ -92,15 +98,21 @@ def test_empty_messages(self): class TestExtractToolCalls: - def test_tool_with_ticker(self): - events = [{"eventType": "tool_call", "metadata": {"toolName": "get_fundamental", "args": {"search": "PETR4"}}}] - result = extractToolCalls(events) - assert "get_fundamental(PETR4)" in result - - def test_tool_without_ticker(self): - events = [{"eventType": "tool_call", "metadata": {"toolName": "list_fields", "args": {}}}] - result = extractToolCalls(events) - assert "list_fields" in result + @pytest.mark.parametrize( + "event,expected", + [ + ( + {"eventType": "tool_call", "metadata": {"toolName": "get_fundamental", "args": {"search": "PETR4"}}}, + "get_fundamental(PETR4)", + ), + ( + {"eventType": "tool_call", "metadata": {"toolName": "list_fields", "args": {}}}, + "list_fields", + ), + ], + ) + def test_tool_cases(self, event, expected): + assert expected in extractToolCalls([event]) def test_skips_non_tool_events(self): events = [{"eventType": "turn_end", "metadata": {}}] @@ -222,47 +234,24 @@ def test_consolidate_preserves_decisions(self): assert len(merged["keyDecisions"]) == 5 def test_get_episodes_empty_session(self): - mockDb = MagicMock() - mockDb.query.return_value.filter.return_value.first.return_value = None - assert self.compactor.getEpisodes(mockDb, "sid1") == [] - - def test_get_episodes_empty_summary(self): - session = MagicMock() - session.summary = None - mockDb = MagicMock() - mockDb.query.return_value.filter.return_value.first.return_value = session - assert self.compactor.getEpisodes(mockDb, "sid1") == [] + assert self.compactor.getEpisodes(mockDbFactory(None), "sid1") == [] - def test_get_episodes_corrupt_json(self): + @pytest.mark.parametrize("summary", [None, "{invalid json", '"just a string"']) + def test_get_episodes_invalid_summary(self, summary): session = MagicMock() - session.summary = "{invalid json" - mockDb = MagicMock() - mockDb.query.return_value.filter.return_value.first.return_value = session - assert self.compactor.getEpisodes(mockDb, "sid1") == [] - - def test_get_episodes_non_list_json(self): - session = MagicMock() - session.summary = '"just a string"' - mockDb = MagicMock() - mockDb.query.return_value.filter.return_value.first.return_value = session - assert self.compactor.getEpisodes(mockDb, "sid1") == [] + session.summary = summary + assert self.compactor.getEpisodes(mockDbFactory(session), "sid1") == [] def test_get_episodes_valid(self): session = MagicMock() session.summary = '[{"id": "ep_1", "summary": "test"}]' - mockDb = MagicMock() - mockDb.query.return_value.filter.return_value.first.return_value = session - result = self.compactor.getEpisodes(mockDb, "sid1") + result = self.compactor.getEpisodes(mockDbFactory(session), "sid1") assert len(result) == 1 assert result[0]["id"] == "ep_1" - def test_get_compactable_chunk_no_episodes(self): - history = [{"role": "user", "content": "msg1"}] - assert self.compactor.getCompactableChunk(history, []) == history - - def test_get_compactable_chunk_no_last_ep_time(self): + @pytest.mark.parametrize("episodes", [[], [{"id": "ep_1"}]]) + def test_get_compactable_chunk_no_usable_episodes(self, episodes): history = [{"role": "user", "content": "msg1"}] - episodes = [{"id": "ep_1"}] assert self.compactor.getCompactableChunk(history, episodes) == history def test_get_compactable_chunk_filters_by_timestamp(self): @@ -283,31 +272,24 @@ def test_get_compactable_chunk_fallback_last_10(self): assert result[0]["content"] == "msg10" def test_compact_returns_none_no_session(self): - mockDb = MagicMock() - mockDb.query.return_value.filter.return_value.first.return_value = None - assert self.compactor.compact(mockDb, "sid1") is None + assert self.compactor.compact(mockDbFactory(None), "sid1") is None def test_compact_returns_none_no_history(self): session = MagicMock() session.history = [] - mockDb = MagicMock() - mockDb.query.return_value.filter.return_value.first.return_value = session - assert self.compactor.compact(mockDb, "sid1") is None + assert self.compactor.compact(mockDbFactory(session), "sid1") is None def test_compact_returns_none_below_budget(self): session = MagicMock() session.history = [{"role": "user", "content": "short"}] session.summary = None - mockDb = MagicMock() - mockDb.query.return_value.filter.return_value.first.return_value = session - assert self.compactor.compact(mockDb, "sid1") is None + assert self.compactor.compact(mockDbFactory(session), "sid1") is None def test_compact_creates_episode_above_budget(self): session = MagicMock() session.history = [{"role": "user", "content": "x" * 40000}] session.summary = None - mockDb = MagicMock() - mockDb.query.return_value.filter.return_value.first.return_value = session + mockDb = mockDbFactory(session) result = self.compactor.compact(mockDb, "sid1") assert result is not None assert result["id"].startswith("ep_") diff --git a/tests/test_memory_maintenance.py b/tests/test_memory_maintenance.py index 58c47c6..a4b515b 100644 --- a/tests/test_memory_maintenance.py +++ b/tests/test_memory_maintenance.py @@ -1,4 +1,3 @@ -import math import pytest from datetime import datetime, timedelta from unittest.mock import patch, MagicMock @@ -35,21 +34,6 @@ def create(userId, key, score=7.0, daysOld=0, accessCount=0): return create -class TestEbbinghausRetention: - def test_retention_formula(self): - """Verify R = e^(-t/S) produces expected values.""" - assert math.exp(-0 / 7.0) == pytest.approx(1.0, abs=1e-6) - assert math.exp(-1 / 7.0) == pytest.approx(0.8669, abs=1e-3) - assert math.exp(-7 / 7.0) == pytest.approx(0.3679, abs=1e-3) - assert math.exp(-30 / 7.0) == pytest.approx(0.0131, abs=1e-3) - - def test_high_stability_forgotten_slowly(self): - """High stability (S=14) retains more than low stability (S=3) at same age.""" - s_high = math.exp(-7 / 14.0) # ~0.607 - s_low = math.exp(-7 / 3.0) # ~0.097 - assert s_high > s_low - - class TestArchive: def test_dead_memory_archived(self, dbSession, create_memories): """Retention below threshold + accessCount=0 → archived.""" diff --git a/tests/test_memory_tools_wiring.py b/tests/test_memory_tools_wiring.py index c339eae..996c64a 100644 --- a/tests/test_memory_tools_wiring.py +++ b/tests/test_memory_tools_wiring.py @@ -51,15 +51,6 @@ def test_save_memory_has_type_hints(self): hints = save_memory.__annotations__ assert "return" in hints - def test_memory_tools_is_list_of_callables(self): - assert isinstance(TOOL_REGISTRY, dict) - assert len(TOOL_REGISTRY) >= 4 - for name, fn in TOOL_REGISTRY.items(): - assert callable(fn) - - def test_memory_tool_names_unchanged(self): - assert {"search_memory", "save_memory"}.issubset(set(TOOL_REGISTRY.keys())) - class TestToolRegistry: """TOOL_REGISTRY pattern must work correctly.""" diff --git a/tests/test_pagination.py b/tests/test_pagination.py deleted file mode 100644 index d746bef..0000000 --- a/tests/test_pagination.py +++ /dev/null @@ -1,90 +0,0 @@ -"""Tests for inline pagination params (used in user + prometheus controllers).""" - -import pytest -import sys -import os - -sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) - -from fastapi import FastAPI, Depends, Query -from starlette.testclient import TestClient - - -@pytest.fixture -def app(): - application = FastAPI() - - @application.get("/items") - def list_items( - limit: int = Query(20, ge=1, le=100, description="Number of items per page"), - offset: int = Query(0, ge=0, description="Number of items to skip"), - ): - all_items = list(range(100)) - page = all_items[offset : offset + limit] - return { - "items": page, - "total": len(all_items), - "limit": limit, - "offset": offset, - } - - return application - - -@pytest.fixture -def client(app): - return TestClient(app) - - -class TestInlinePagination: - def test_defaults(self, client): - response = client.get("/items") - body = response.json() - assert response.status_code == 200 - assert body["limit"] == 20 - assert body["offset"] == 0 - assert len(body["items"]) == 20 - - def test_custom_limit(self, client): - response = client.get("/items?limit=5") - body = response.json() - assert body["limit"] == 5 - assert len(body["items"]) == 5 - - def test_custom_offset(self, client): - response = client.get("/items?offset=10") - body = response.json() - assert body["offset"] == 10 - assert len(body["items"]) == 20 - assert body["items"][0] == 10 - - def test_limit_and_offset(self, client): - response = client.get("/items?limit=10&offset=50") - body = response.json() - assert body["limit"] == 10 - assert body["offset"] == 50 - assert len(body["items"]) == 10 - assert body["items"][0] == 50 - - def test_limit_exceeds_max_rejected(self, client): - response = client.get("/items?limit=101") - assert response.status_code == 422 - - def test_limit_zero_rejected(self, client): - response = client.get("/items?limit=0") - assert response.status_code == 422 - - def test_negative_offset_rejected(self, client): - response = client.get("/items?offset=-1") - assert response.status_code == 422 - - def test_offset_beyond_total(self, client): - response = client.get("/items?offset=200") - body = response.json() - assert body["items"] == [] - - def test_limit_equals_max(self, client): - response = client.get("/items?limit=100") - body = response.json() - assert body["limit"] == 100 - assert len(body["items"]) == 100 diff --git a/tests/test_prometheus_agent_context.py b/tests/test_prometheus_agent_context.py index e05bc4e..ddc25b2 100644 --- a/tests/test_prometheus_agent_context.py +++ b/tests/test_prometheus_agent_context.py @@ -3,7 +3,7 @@ import json import pytest from datetime import datetime -from unittest.mock import patch, MagicMock +from unittest.mock import patch, MagicMock, AsyncMock from main.app.prometheus.agent import Prometheus, SYSTEM_PROMPT from main.models.prometheus import PrometheusSession @@ -123,3 +123,220 @@ def test_prompt_guides_save_when_and_types(self): assert "save_memory" in SYSTEM_PROMPT assert "preference" in SYSTEM_PROMPT assert "analysis" in SYSTEM_PROMPT + + +# ---- moved from test_prometheus_auth_coverage.py (TestPrometheusInit) ---- + + +# --------------------------------------------------------------------------- +# Prometheus (agent.py) — covers __init__, updateDates, sendMessage, streamMessage +# --------------------------------------------------------------------------- + + +class TestPrometheusInit: + """Cover __init__.""" + + @patch("main.app.prometheus.agent.Config") + @patch("main.app.prometheus.agent.genai") + @patch("main.app.prometheus.agent.client", None) + def test_init_creates_client(self, mock_genai, mock_config): + # _client is a lazy module-level singleton (created once per process); + # reset it so construction goes through the mocked genai.Client. + mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="test-key") + mock_config.DEBUG_MODE = True + + from main.app.prometheus.agent import Prometheus + + gen = Prometheus() + mock_genai.Client.assert_called_once_with(api_key="test-key") + + +# ---- moved from test_prometheus_auth_coverage.py (TestPrometheusSendMessage) ---- + + +class TestPrometheusSendMessage: + """Cover streamMessage in agent.py.""" + + @pytest.mark.anyio + @patch("main.app.prometheus.agent.PrometheusChatManager") + @patch("main.app.prometheus.agent.Config") + @patch("main.app.prometheus.agent.genai") + async def test_send_message_basic(self, mock_genai, mock_config, mock_chat): + mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="key") + mock_config.DEBUG_MODE = True + mock_config.STOCKS_API = {"HOST": "localhost", "PORT": 3200} + + mock_client = MagicMock() + mock_genai.Client = MagicMock(return_value=mock_client) + mock_chat.getHistory.return_value = [] + + async def fake_stream(*args, **kwargs): + yield {"type": "text", "text": "Hello from Gemini"} + + from main.app.prometheus.agent import Prometheus + + gen = Prometheus() + gen.streamMessage = fake_stream + + results = [] + async for event in gen.streamMessage( + query="Qual o P/L de PETR4?", sessionId="sess-1", db=MagicMock(), user={"userId": 1} + ): + results.append(event) + assert results[-1]["text"] == "Hello from Gemini" + + @pytest.mark.anyio + @patch("main.app.prometheus.agent.PrometheusChatManager") + @patch("main.app.prometheus.agent.Config") + @patch("main.app.prometheus.agent.genai") + async def test_send_message_saves_user_message_on_error(self, mock_genai, mock_config, mock_chat): + mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="key") + mock_config.DEBUG_MODE = True + mock_config.STOCKS_API = {"HOST": "localhost", "PORT": 3200} + + async def failing_stream(*args, **kwargs): + raise Exception("API error") + yield # make it async generator + + from main.app.prometheus.agent import Prometheus + + gen = Prometheus() + gen.streamMessage = failing_stream + + with pytest.raises(Exception): + async for _ in gen.streamMessage(query="test", sessionId="sess-2", db=MagicMock(), user={"userId": 1}): + pass + + @pytest.mark.anyio + @patch("main.app.prometheus.agent.PrometheusChatManager") + @patch("main.app.prometheus.agent.Config") + @patch("main.app.prometheus.agent.genai") + async def test_send_message_with_history(self, mock_genai, mock_config, mock_chat): + mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="key") + mock_config.DEBUG_MODE = True + mock_config.STOCKS_API = {"HOST": "localhost", "PORT": 3200} + + async def fake_stream(*args, **kwargs): + yield {"type": "text", "text": "Reply with history"} + + from main.app.prometheus.agent import Prometheus + + gen = Prometheus() + gen.streamMessage = fake_stream + + results = [] + async for event in gen.streamMessage(query="next", sessionId="sess-3", db=MagicMock(), user={"userId": 1}): + results.append(event) + assert results[-1]["text"] == "Reply with history" + + @pytest.mark.anyio + @patch("main.app.prometheus.agent.clientPool") + @patch("main.app.prometheus.agent.PrometheusChatManager") + @patch("main.app.prometheus.agent.Config") + @patch("main.app.prometheus.agent.genai") + async def test_stream_message_yields_text_chunks(self, mock_genai, mock_config, mock_chat, mock_pool_cls): + """streamMessage must yield dict chunks from async iterator.""" + mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="key") + mock_config.DEBUG_MODE = True + mock_config.STOCKS_API = {"HOST": "localhost", "PORT": 3200} + mock_chat.getHistory.return_value = [] + + mock_pool_cls.clients = {"stocks": MagicMock(), "searxng": MagicMock()} + mock_pool_cls.getClients = AsyncMock( + return_value=( + {"stocks": MagicMock(), "searxng": MagicMock()}, + [MagicMock(), MagicMock()], + ) + ) + + class FakeChunk: + def __init__(self, text=None, function_calls=None): + self.text = text + self.function_calls = function_calls + + chunks = [FakeChunk(text="Hello "), FakeChunk(text="world")] + + async def fake_aiter(): + for c in chunks: + yield c + + mock_chat_session = AsyncMock() + mock_chat_session.send_message_stream = AsyncMock(return_value=fake_aiter()) + + from main.app.prometheus.agent import Prometheus + + gen = Prometheus() + gen.makeChat = MagicMock(return_value=mock_chat_session) + + results = [] + async for event in gen.streamMessage(query="hi", sessionId="s1", db=MagicMock()): + results.append(event) + + assert len(results) == 2 + assert results[0] == {"type": "text", "text": "Hello "} + assert results[1] == {"type": "text", "text": "world"} + + @pytest.mark.anyio + @patch("main.app.prometheus.agent.clientPool") + @patch("main.app.prometheus.agent.PrometheusChatManager") + @patch("main.app.prometheus.agent.Config") + @patch("main.app.prometheus.agent.genai") + async def test_stream_message_handles_function_calls(self, mock_genai, mock_config, mock_chat, mock_pool_cls): + """streamMessage must handle function_calls as a list (not dict).""" + mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="key") + mock_config.DEBUG_MODE = True + mock_config.STOCKS_API = {"HOST": "localhost", "PORT": 3200} + mock_chat.getHistory.return_value = [] + + mock_pool_cls.clients = {"stocks": MagicMock(), "searxng": MagicMock()} + mock_pool_cls.getClients = AsyncMock( + return_value=( + {"stocks": MagicMock(), "searxng": MagicMock()}, + [MagicMock(), MagicMock()], + ) + ) + + class FakeChunk: + def __init__(self, text=None, function_calls=None): + self.text = text + self.function_calls = function_calls + + class FakeFunctionCall: + name = "search" + args = {"query": "test"} + + call_count = 0 + + async def fake_aiter_first(): + yield FakeChunk(function_calls=[FakeFunctionCall()]) + + async def fake_aiter_second(): + yield FakeChunk(text="Result: found it") + + mock_chat_session = AsyncMock() + + async def fake_stream(msg, config=None): + nonlocal call_count + call_count += 1 + if call_count == 1: + return fake_aiter_first() + return fake_aiter_second() + + mock_chat_session.send_message_stream = AsyncMock(side_effect=fake_stream) + + from main.app.prometheus.agent import Prometheus + + gen = Prometheus() + gen.makeChat = MagicMock(return_value=mock_chat_session) + + results = [] + async for event in gen.streamMessage(query="search test", sessionId="s2", db=MagicMock()): + results.append(event) + + assert any(e.get("text") == "Result: found it" for e in results) + assert call_count == 2 + + +# --------------------------------------------------------------------------- +# PrometheusChatManager (chat.py) +# --------------------------------------------------------------------------- diff --git a/tests/test_prometheus_auth_coverage.py b/tests/test_prometheus_auth_coverage.py deleted file mode 100644 index e893579..0000000 --- a/tests/test_prometheus_auth_coverage.py +++ /dev/null @@ -1,884 +0,0 @@ -""" -Tests to increase coverage for: - - main/app/prometheus/generation.py - - main/app/prometheus/chat.py - - main/app/authentication/authentication.py - - main/app/authentication/session.py - - main/app/authentication/sso.py -""" - -import pytest -import sys -import os -import json -from unittest.mock import patch, MagicMock, AsyncMock -from datetime import datetime, timedelta -from zoneinfo import ZoneInfo - -sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) - - -# --------------------------------------------------------------------------- -# Prometheus (agent.py) — covers __init__, updateDates, sendMessage, streamMessage -# --------------------------------------------------------------------------- - - -class TestPrometheusInit: - """Cover __init__.""" - - @patch("main.app.prometheus.agent.Config") - @patch("main.app.prometheus.agent.genai") - @patch("main.app.prometheus.agent.client", None) - def test_init_creates_client(self, mock_genai, mock_config): - # _client is a lazy module-level singleton (created once per process); - # reset it so construction goes through the mocked genai.Client. - mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="test-key") - mock_config.DEBUG_MODE = True - - from main.app.prometheus.agent import Prometheus - - gen = Prometheus() - mock_genai.Client.assert_called_once_with(api_key="test-key") - - -class TestPrometheusSendMessage: - """Cover streamMessage in agent.py.""" - - @pytest.mark.anyio - @patch("main.app.prometheus.agent.PrometheusChatManager") - @patch("main.app.prometheus.agent.Config") - @patch("main.app.prometheus.agent.genai") - async def test_send_message_basic(self, mock_genai, mock_config, mock_chat): - mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="key") - mock_config.DEBUG_MODE = True - mock_config.STOCKS_API = {"HOST": "localhost", "PORT": 3200} - - mock_client = MagicMock() - mock_genai.Client = MagicMock(return_value=mock_client) - mock_chat.getHistory.return_value = [] - - async def fake_stream(*args, **kwargs): - yield {"type": "text", "text": "Hello from Gemini"} - - from main.app.prometheus.agent import Prometheus - - gen = Prometheus() - gen.streamMessage = fake_stream - - results = [] - async for event in gen.streamMessage( - query="Qual o P/L de PETR4?", sessionId="sess-1", db=MagicMock(), user={"userId": 1} - ): - results.append(event) - assert results[-1]["text"] == "Hello from Gemini" - - @pytest.mark.anyio - @patch("main.app.prometheus.agent.PrometheusChatManager") - @patch("main.app.prometheus.agent.Config") - @patch("main.app.prometheus.agent.genai") - async def test_send_message_saves_user_message_on_error(self, mock_genai, mock_config, mock_chat): - mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="key") - mock_config.DEBUG_MODE = True - mock_config.STOCKS_API = {"HOST": "localhost", "PORT": 3200} - - async def failing_stream(*args, **kwargs): - raise Exception("API error") - yield # make it async generator - - from main.app.prometheus.agent import Prometheus - - gen = Prometheus() - gen.streamMessage = failing_stream - - with pytest.raises(Exception): - async for _ in gen.streamMessage(query="test", sessionId="sess-2", db=MagicMock(), user={"userId": 1}): - pass - - @pytest.mark.anyio - @patch("main.app.prometheus.agent.PrometheusChatManager") - @patch("main.app.prometheus.agent.Config") - @patch("main.app.prometheus.agent.genai") - async def test_send_message_with_history(self, mock_genai, mock_config, mock_chat): - mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="key") - mock_config.DEBUG_MODE = True - mock_config.STOCKS_API = {"HOST": "localhost", "PORT": 3200} - - async def fake_stream(*args, **kwargs): - yield {"type": "text", "text": "Reply with history"} - - from main.app.prometheus.agent import Prometheus - - gen = Prometheus() - gen.streamMessage = fake_stream - - results = [] - async for event in gen.streamMessage(query="next", sessionId="sess-3", db=MagicMock(), user={"userId": 1}): - results.append(event) - assert results[-1]["text"] == "Reply with history" - - @pytest.mark.anyio - @patch("main.app.prometheus.agent.clientPool") - @patch("main.app.prometheus.agent.PrometheusChatManager") - @patch("main.app.prometheus.agent.Config") - @patch("main.app.prometheus.agent.genai") - async def test_stream_message_yields_text_chunks(self, mock_genai, mock_config, mock_chat, mock_pool_cls): - """streamMessage must yield dict chunks from async iterator.""" - mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="key") - mock_config.DEBUG_MODE = True - mock_config.STOCKS_API = {"HOST": "localhost", "PORT": 3200} - mock_chat.getHistory.return_value = [] - - mock_pool_cls.clients = {"stocks": MagicMock(), "searxng": MagicMock()} - mock_pool_cls.getClients = AsyncMock( - return_value=( - {"stocks": MagicMock(), "searxng": MagicMock()}, - [MagicMock(), MagicMock()], - ) - ) - - class FakeChunk: - def __init__(self, text=None, function_calls=None): - self.text = text - self.function_calls = function_calls - - chunks = [FakeChunk(text="Hello "), FakeChunk(text="world")] - - async def fake_aiter(): - for c in chunks: - yield c - - mock_chat_session = AsyncMock() - mock_chat_session.send_message_stream = AsyncMock(return_value=fake_aiter()) - - from main.app.prometheus.agent import Prometheus - - gen = Prometheus() - gen.makeChat = MagicMock(return_value=mock_chat_session) - - results = [] - async for event in gen.streamMessage(query="hi", sessionId="s1", db=MagicMock()): - results.append(event) - - assert len(results) == 2 - assert results[0] == {"type": "text", "text": "Hello "} - assert results[1] == {"type": "text", "text": "world"} - - @pytest.mark.anyio - @patch("main.app.prometheus.agent.clientPool") - @patch("main.app.prometheus.agent.PrometheusChatManager") - @patch("main.app.prometheus.agent.Config") - @patch("main.app.prometheus.agent.genai") - async def test_stream_message_handles_function_calls(self, mock_genai, mock_config, mock_chat, mock_pool_cls): - """streamMessage must handle function_calls as a list (not dict).""" - mock_config.PROMETHEUS = MagicMock(GEMINI_API_KEY="key") - mock_config.DEBUG_MODE = True - mock_config.STOCKS_API = {"HOST": "localhost", "PORT": 3200} - mock_chat.getHistory.return_value = [] - - mock_pool_cls.clients = {"stocks": MagicMock(), "searxng": MagicMock()} - mock_pool_cls.getClients = AsyncMock( - return_value=( - {"stocks": MagicMock(), "searxng": MagicMock()}, - [MagicMock(), MagicMock()], - ) - ) - - class FakeChunk: - def __init__(self, text=None, function_calls=None): - self.text = text - self.function_calls = function_calls - - class FakeFunctionCall: - name = "search" - args = {"query": "test"} - - call_count = 0 - - async def fake_aiter_first(): - yield FakeChunk(function_calls=[FakeFunctionCall()]) - - async def fake_aiter_second(): - yield FakeChunk(text="Result: found it") - - mock_chat_session = AsyncMock() - - async def fake_stream(msg, config=None): - nonlocal call_count - call_count += 1 - if call_count == 1: - return fake_aiter_first() - return fake_aiter_second() - - mock_chat_session.send_message_stream = AsyncMock(side_effect=fake_stream) - - from main.app.prometheus.agent import Prometheus - - gen = Prometheus() - gen.makeChat = MagicMock(return_value=mock_chat_session) - - results = [] - async for event in gen.streamMessage(query="search test", sessionId="s2", db=MagicMock()): - results.append(event) - - assert any(e.get("text") == "Result: found it" for e in results) - assert call_count == 2 - - -# --------------------------------------------------------------------------- -# PrometheusChatManager (chat.py) -# --------------------------------------------------------------------------- - - -class TestPrometheusChatManager: - """Cover all methods in chat.py (lines 11-120).""" - - def test_init(self): - from main.app.prometheus.chat import PrometheusChatManager - - mgr = PrometheusChatManager() - assert mgr is not None - - def test_get_user_sessions(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - - mock_session1 = MagicMock() - mock_session1.sessionId = "s1" - mock_session1.title = "Title 1" - mock_session1.lastActivity = datetime(2026, 3, 23, 12, 0, 0) - - mock_session2 = MagicMock() - mock_session2.sessionId = "s2" - mock_session2.title = "Title 2" - mock_session2.lastActivity = None - - mock_db.query.return_value.filter.return_value.order_by.return_value.all.return_value = [ - mock_session1, - mock_session2, - ] - - result = PrometheusChatManager.getUserSessions(mock_db, userId=1) - assert len(result) == 2 - assert result[0]["sessionId"] == "s1" - assert result[0]["lastActivity"] == "2026-03-23T12:00:00" - assert result[1]["lastActivity"] is None - - def test_create_session(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - - result = PrometheusChatManager.createSession(mock_db, userId=1, title="Test") - assert isinstance(result, str) - assert len(result) > 0 - mock_db.add.assert_called_once() - mock_db.commit.assert_called_once() - - def test_update_session_title_found(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = mock_session - - result = PrometheusChatManager.updateSessionTitle(mock_db, "sess-123", "New Title") - assert result is True - assert mock_session.title == "New Title" - mock_db.commit.assert_called_once() - - def test_update_session_title_not_found(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = None - - result = PrometheusChatManager.updateSessionTitle(mock_db, "nonexistent", "Title") - assert result is False - - def test_save_message_found(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_session.history = [] - mock_db.query.return_value.filter.return_value.first.return_value = mock_session - - PrometheusChatManager.appendHistory( - mock_db, "sess-123", {"role": "user", "content": "Hello", "metadata": {"key": "val"}} - ) - - assert len(mock_session.history) == 1 - assert mock_session.history[0]["role"] == "user" - assert mock_session.history[0]["content"] == "Hello" - assert mock_session.history[0]["metadata"] == {"key": "val"} - mock_db.commit.assert_called_once() - - def test_save_message_history_none(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_session.history = None - mock_db.query.return_value.filter.return_value.first.return_value = mock_session - - PrometheusChatManager.appendHistory(mock_db, "sess-123", {"role": "assistant", "content": "Reply"}) - - assert mock_session.history == [ - { - "role": "assistant", - "content": "Reply", - "timestamp": mock_session.history[0]["timestamp"], - } - ] - - def test_save_message_not_found(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = None - - # Should not raise - PrometheusChatManager.appendHistory(mock_db, "nonexistent", {"role": "user", "content": "Hello"}) - - def test_get_history_with_messages(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_session.history = [ - {"role": "user", "content": "Hello", "timestamp": "2026-03-23T12:00:00"}, - {"role": "assistant", "content": "Hi there", "timestamp": "2026-03-23T12:01:00"}, - ] - mock_db.query.return_value.filter.return_value.first.return_value = mock_session - - result = PrometheusChatManager.getHistory(mock_db, "sess-123") - assert len(result) == 2 - assert result[0]["role"] == "user" - assert result[0]["parts"][0]["text"] == "Hello" - assert result[1]["role"] == "model" - - def test_get_history_empty(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = None - - result = PrometheusChatManager.getHistory(mock_db, "nonexistent") - assert result == [] - - def test_get_history_no_history(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_session.history = None - mock_db.query.return_value.filter.return_value.first.return_value = mock_session - - result = PrometheusChatManager.getHistory(mock_db, "sess-123") - assert result == [] - - def test_get_history_with_limit(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_session.history = [{"role": "user", "content": f"msg{i}"} for i in range(30)] - mock_db.query.return_value.filter.return_value.first.return_value = mock_session - - result = PrometheusChatManager.getHistory(mock_db, "sess-123", limit=5) - assert len(result) == 5 - - def test_delete_session_found(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = mock_session - - result = PrometheusChatManager.deleteSession(mock_db, "sess-123", userId=1) - assert result is True - mock_db.delete.assert_called_once_with(mock_session) - mock_db.commit.assert_called_once() - - def test_delete_session_not_found(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = None - - result = PrometheusChatManager.deleteSession(mock_db, "nonexistent", userId=1) - assert result is False - - def test_verify_session_ownership_true(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = "sess-123" - - result = PrometheusChatManager.verifySessionOwnership(mock_db, "sess-123", userId=1) - assert result is True - - def test_verify_session_ownership_false(self): - from main.app.prometheus.chat import PrometheusChatManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = None - - result = PrometheusChatManager.verifySessionOwnership(mock_db, "nonexistent", userId=1) - assert result is False - - -# --------------------------------------------------------------------------- -# AuthenticationManager (authentication.py) -# --------------------------------------------------------------------------- - - -class TestAuthenticationManager: - """Cover all methods in authentication.py (lines 13-75).""" - - @patch("main.app.authentication.authentication.hashPassword") - def test_create_user_account_success(self, mock_hash): - from main.app.authentication.authentication import AuthenticationManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = None - mock_hash.return_value = "hashed_pw" - - result = AuthenticationManager.createUserAccount(mock_db, "newuser", "new@example.com", password="pass123") - assert result is True - mock_db.add.assert_called_once() - mock_db.commit.assert_called_once() - - def test_create_user_account_no_password_no_google(self): - from main.app.authentication.authentication import AuthenticationManager - from fastapi import HTTPException - - mock_db = MagicMock() - - with pytest.raises(HTTPException) as exc_info: - AuthenticationManager.createUserAccount(mock_db, "user", "e@e.com") - assert exc_info.value.status_code == 400 - assert "password" in exc_info.value.detail.lower() - - def test_create_user_account_username_taken(self): - from main.app.authentication.authentication import AuthenticationManager - from fastapi import HTTPException - - mock_db = MagicMock() - existing = MagicMock() - existing.username = "taken" - mock_db.query.return_value.filter.return_value.first.return_value = existing - - with pytest.raises(HTTPException) as exc_info: - AuthenticationManager.createUserAccount(mock_db, "taken", "e@e.com", password="pass") - assert exc_info.value.status_code == 400 - assert "Username already taken" in exc_info.value.detail - - def test_create_user_account_email_taken(self): - from main.app.authentication.authentication import AuthenticationManager - from fastapi import HTTPException - - mock_db = MagicMock() - existing = MagicMock() - existing.username = "other" - mock_db.query.return_value.filter.return_value.first.return_value = existing - - with pytest.raises(HTTPException) as exc_info: - AuthenticationManager.createUserAccount(mock_db, "newuser", "taken@example.com", password="pass") - assert exc_info.value.status_code == 400 - assert "Email already registered" in exc_info.value.detail - - @patch("main.app.authentication.authentication.hashPassword") - def test_create_user_account_db_exception(self, mock_hash): - from main.app.authentication.authentication import AuthenticationManager - from fastapi import HTTPException - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = None - mock_db.commit.side_effect = Exception("DB error") - mock_hash.return_value = "hashed" - - with pytest.raises(HTTPException) as exc_info: - AuthenticationManager.createUserAccount(mock_db, "user", "e@e.com", password="pass") - assert exc_info.value.status_code == 500 - mock_db.rollback.assert_called() - - def test_create_user_account_with_google_id(self): - from main.app.authentication.authentication import AuthenticationManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = None - - result = AuthenticationManager.createUserAccount(mock_db, "googleuser", "g@g.com", googleId="google-123") - assert result is True - - def test_authenticate_google_user_found(self): - from main.app.authentication.authentication import AuthenticationManager - - mock_db = MagicMock() - mock_user = MagicMock() - mock_user.userId = 1 - mock_user.username = "testuser" - mock_user.getRolesList.return_value = ["USER"] - mock_db.query.return_value.filter.return_value.first.return_value = mock_user - - result = AuthenticationManager.authenticateGoogleUser(mock_db, "google-123") - assert result is not None - assert result["userId"] == 1 - assert result["username"] == "testuser" - - def test_authenticate_google_user_not_found(self): - from main.app.authentication.authentication import AuthenticationManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = None - - result = AuthenticationManager.authenticateGoogleUser(mock_db, "nonexistent") - assert result is None - - def test_authenticate_google_user_exception(self): - from main.app.authentication.authentication import AuthenticationManager - - mock_db = MagicMock() - mock_db.query.side_effect = Exception("DB error") - - result = AuthenticationManager.authenticateGoogleUser(mock_db, "google-123") - assert result is None - - @patch("main.app.authentication.authentication.verifyPassword") - def test_authenticate_user_success(self, mock_verify): - from main.app.authentication.authentication import AuthenticationManager - - mock_db = MagicMock() - mock_user = MagicMock() - mock_user.userId = 1 - mock_user.username = "testuser" - mock_user.passwordHash = "hashed" - mock_user.getRolesList.return_value = ["USER"] - mock_db.query.return_value.filter.return_value.first.return_value = mock_user - mock_verify.return_value = True - - result = AuthenticationManager.authenticateUser(mock_db, "testuser", "pass123") - assert result is not None - assert result["userId"] == 1 - - @patch("main.app.authentication.authentication.verifyPassword") - def test_authenticate_user_wrong_password(self, mock_verify): - from main.app.authentication.authentication import AuthenticationManager - - mock_db = MagicMock() - mock_user = MagicMock() - mock_user.passwordHash = "hashed" - mock_db.query.return_value.filter.return_value.first.return_value = mock_user - mock_verify.return_value = False - - result = AuthenticationManager.authenticateUser(mock_db, "testuser", "wrong") - assert result is None - - def test_authenticate_user_not_found(self): - from main.app.authentication.authentication import AuthenticationManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = None - - result = AuthenticationManager.authenticateUser(mock_db, "nobody", "pass") - assert result is None - - def test_authenticate_user_no_password_hash(self): - from main.app.authentication.authentication import AuthenticationManager - - mock_db = MagicMock() - mock_user = MagicMock() - mock_user.passwordHash = None - mock_db.query.return_value.filter.return_value.first.return_value = mock_user - - result = AuthenticationManager.authenticateUser(mock_db, "testuser", "pass") - assert result is None - - def test_authenticate_user_exception(self): - from main.app.authentication.authentication import AuthenticationManager - - mock_db = MagicMock() - mock_db.query.side_effect = Exception("DB error") - - result = AuthenticationManager.authenticateUser(mock_db, "testuser", "pass") - assert result is None - - -# --------------------------------------------------------------------------- -# SessionManager (session.py) -# --------------------------------------------------------------------------- - - -class TestSessionManager: - """Cover all methods in session.py (lines 14-154).""" - - @patch("main.app.authentication.session.datetime") - @patch("main.app.authentication.session.secrets") - def test_create_session(self, mock_secrets, mock_datetime): - from main.app.authentication.session import SessionManager - - mock_secrets.token_urlsafe.return_value = "session-id-123" - mock_secrets.token_hex.return_value = "a" * 64 - - mock_now = datetime(2026, 3, 23, 12, 0, 0, tzinfo=ZoneInfo("America/Sao_Paulo")) - mock_datetime.now.return_value = mock_now - - mock_db = MagicMock() - - result = SessionManager.createSession(mock_db, userId=1, userAgent="Mozilla/5.0") - - mock_db.add.assert_called_once() - mock_db.commit.assert_called_once() - assert result.sessionId == "session-id-123" - - @patch("main.app.authentication.session.datetime") - @patch("main.app.authentication.session.secrets") - def test_create_session_custom_expiry(self, mock_secrets, mock_datetime): - from main.app.authentication.session import SessionManager - - mock_secrets.token_urlsafe.return_value = "session-id-456" - mock_secrets.token_hex.return_value = "b" * 64 - - mock_now = datetime(2026, 3, 23, 12, 0, 0, tzinfo=ZoneInfo("America/Sao_Paulo")) - mock_datetime.now.return_value = mock_now - - custom_expiry = mock_now + timedelta(days=7) - mock_db = MagicMock() - - result = SessionManager.createSession(mock_db, userId=2, userAgent="Safari", expiresAt=custom_expiry) - assert result.expiresAt == custom_expiry - - def test_get_user_sessions_active_only(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - - SessionManager.getUserSessions(mock_db, userId=1) - - query = mock_db.query.return_value.filter.return_value - # Should have .filter().filter().order_by().limit().all() - query.filter.return_value.order_by.return_value.limit.return_value.all.assert_called_once() - - def test_get_user_sessions_active_only(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - - SessionManager.getUserSessions(mock_db, userId=1) - - # Active-only filter is always applied in a single filter call - mock_db.query.return_value.filter.return_value.order_by.return_value.limit.return_value.all.assert_called_once() - - def test_get_session_by_id(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - - SessionManager.getSessionById(mock_db, "sess-123", userId=1) - - query_filter = mock_db.query.return_value.filter.return_value - query_filter.filter.return_value.first.assert_called_once() - - def test_get_session_by_id_no_user_id(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - - SessionManager.getSessionById(mock_db, "sess-123") - - # With no userId, only one filter is applied - mock_db.query.return_value.filter.return_value.first.assert_called_once() - - def test_get_current_session(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - - result = SessionManager.getCurrentSession(mock_db, userId=1) - - mock_db.query.return_value.filter.return_value.order_by.return_value.first.assert_called_once() - - def test_revoke_session_found(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session - - result = SessionManager.revokeSession(mock_db, "sess-123", userId=1) - assert result is True - assert mock_session.isActive is False - mock_db.commit.assert_called_once() - - def test_revoke_session_not_found(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = None - - result = SessionManager.revokeSession(mock_db, "nonexistent", userId=1) - assert result is False - - def test_revoke_all_sessions(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - # revokeAllSessions: db.query(...).filter(userId, isActive).update(...) - mock_db.query.return_value.filter.return_value.update.return_value = 5 - - count = SessionManager.revokeAllSessions(mock_db, userId=1) - assert count == 5 - mock_db.commit.assert_called_once() - - def test_revoke_all_sessions_revokes_everything(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - # revokeAllSessions: db.query(...).filter(userId, isActive).update(...) - mock_db.query.return_value.filter.return_value.update.return_value = 3 - - count = SessionManager.revokeAllSessions(mock_db, userId=1) - assert count == 3 - - def test_update_last_active_found(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = mock_session - - result = SessionManager.updateLastActive(mock_db, "sess-123") - assert result is True - mock_db.commit.assert_called_once() - - def test_update_last_active_not_found(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.first.return_value = None - - result = SessionManager.updateLastActive(mock_db, "nonexistent") - assert result is False - - def test_validate_session_active(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_session.isActive = True - mock_session.expiresAt = datetime(2026, 12, 31, tzinfo=ZoneInfo("America/Sao_Paulo")) - mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session - - result = SessionManager.validateSession(mock_db, "sess-123", userId=1) - assert result is True - - def test_validate_session_not_found(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = None - - result = SessionManager.validateSession(mock_db, "nonexistent", userId=1) - assert result is False - - def test_validate_session_inactive(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_session.isActive = False - mock_session.expiresAt = datetime(2026, 12, 31, tzinfo=ZoneInfo("America/Sao_Paulo")) - mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session - - result = SessionManager.validateSession(mock_db, "sess-123", userId=1) - assert result is False - - def test_validate_session_expired(self): - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_session.isActive = True - mock_session.expiresAt = datetime(2020, 1, 1, tzinfo=ZoneInfo("America/Sao_Paulo")) - mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session - - result = SessionManager.validateSession(mock_db, "sess-123", userId=1) - assert result is False - assert mock_session.isActive is False - mock_db.commit.assert_called_once() - - def test_validate_session_expired_naive_tz(self): - """Exercises the tzinfo-is-None branch (line 144-148).""" - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_session.isActive = True - # Naive datetime (no timezone) - mock_session.expiresAt = datetime(2020, 1, 1) - mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session - - result = SessionManager.validateSession(mock_db, "sess-123", userId=1) - assert result is False - - def test_validate_session_no_expiry(self): - """Exercises the expiresAt-is-None branch (line 143).""" - from main.app.authentication.session import SessionManager - - mock_db = MagicMock() - mock_session = MagicMock() - mock_session.isActive = True - mock_session.expiresAt = None - mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_session - - result = SessionManager.validateSession(mock_db, "sess-123", userId=1) - assert result is True - - -# --------------------------------------------------------------------------- -# SSO (sso.py) -# --------------------------------------------------------------------------- - - -class TestSSO: - """Cover getGoogleSSO (lines 6-14).""" - - @patch("main.app.authentication.sso.Config") - @patch("main.app.authentication.sso.GoogleSSO") - def test_get_google_sso_with_redirect(self, mock_google_sso, mock_config): - from main.app.authentication.sso import getGoogleSSO - - mock_config.USER = MagicMock( - GOOGLE_CLIENT_ID="cid", - GOOGLE_CLIENT_SECRET="csecret", - GOOGLE_REDIRECT_URI="http://callback", - ) - - result = getGoogleSSO(redirectUri="http://custom-callback") - - mock_google_sso.assert_called_once_with( - client_id="cid", - client_secret="csecret", - redirect_uri="http://custom-callback", - ) - - @patch("main.app.authentication.sso.Config") - @patch("main.app.authentication.sso.GoogleSSO") - def test_get_google_sso_default_redirect(self, mock_google_sso, mock_config): - from main.app.authentication.sso import getGoogleSSO - - mock_config.USER = MagicMock( - GOOGLE_CLIENT_ID="cid", - GOOGLE_CLIENT_SECRET="csecret", - GOOGLE_REDIRECT_URI="http://default-callback", - ) - - result = getGoogleSSO() - - mock_google_sso.assert_called_once_with( - client_id="cid", - client_secret="csecret", - redirect_uri="http://default-callback", - ) diff --git a/tests/test_prometheus_resume.py b/tests/test_prometheus_resume.py index 1fe7713..08779e9 100644 --- a/tests/test_prometheus_resume.py +++ b/tests/test_prometheus_resume.py @@ -3,6 +3,8 @@ import main.controller.prometheus_controller as controller_mod import pytest +from datetime import datetime +from unittest.mock import MagicMock from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.pool import StaticPool @@ -147,3 +149,211 @@ async def runner(): done_events = [json.loads(ln[6:].strip()) for ln in data if ln[6:].strip() != "[DONE]"] assert {"type": "done"} in done_events assert "data: [DONE]\n\n" in data + + +# ---- moved from test_prometheus_auth_coverage.py (TestPrometheusChatManager) ---- + + +class TestPrometheusChatManager: + """Cover all methods in chat.py (lines 11-120).""" + + def test_init(self): + from main.app.prometheus.chat import PrometheusChatManager + + mgr = PrometheusChatManager() + assert mgr is not None + + def test_get_user_sessions(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + + mock_session1 = MagicMock() + mock_session1.sessionId = "s1" + mock_session1.title = "Title 1" + mock_session1.lastActivity = datetime(2026, 3, 23, 12, 0, 0) + + mock_session2 = MagicMock() + mock_session2.sessionId = "s2" + mock_session2.title = "Title 2" + mock_session2.lastActivity = None + + mock_db.query.return_value.filter.return_value.order_by.return_value.all.return_value = [ + mock_session1, + mock_session2, + ] + + result = PrometheusChatManager.getUserSessions(mock_db, userId=1) + assert len(result) == 2 + assert result[0]["sessionId"] == "s1" + assert result[0]["lastActivity"] == "2026-03-23T12:00:00" + assert result[1]["lastActivity"] is None + + def test_create_session(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + + result = PrometheusChatManager.createSession(mock_db, userId=1, title="Test") + assert isinstance(result, str) + assert len(result) > 0 + mock_db.add.assert_called_once() + mock_db.commit.assert_called_once() + + def test_update_session_title_found(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = mock_session + + result = PrometheusChatManager.updateSessionTitle(mock_db, "sess-123", "New Title") + assert result is True + assert mock_session.title == "New Title" + mock_db.commit.assert_called_once() + + def test_update_session_title_not_found(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = None + + result = PrometheusChatManager.updateSessionTitle(mock_db, "nonexistent", "Title") + assert result is False + + def test_save_message_found(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_session.history = [] + mock_db.query.return_value.filter.return_value.first.return_value = mock_session + + PrometheusChatManager.appendHistory( + mock_db, "sess-123", {"role": "user", "content": "Hello", "metadata": {"key": "val"}} + ) + + assert len(mock_session.history) == 1 + assert mock_session.history[0]["role"] == "user" + assert mock_session.history[0]["content"] == "Hello" + assert mock_session.history[0]["metadata"] == {"key": "val"} + mock_db.commit.assert_called_once() + + def test_save_message_history_none(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_session.history = None + mock_db.query.return_value.filter.return_value.first.return_value = mock_session + + PrometheusChatManager.appendHistory(mock_db, "sess-123", {"role": "assistant", "content": "Reply"}) + + assert mock_session.history == [ + { + "role": "assistant", + "content": "Reply", + "timestamp": mock_session.history[0]["timestamp"], + } + ] + + def test_save_message_not_found(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = None + + # Should not raise + PrometheusChatManager.appendHistory(mock_db, "nonexistent", {"role": "user", "content": "Hello"}) + + def test_get_history_with_messages(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_session.history = [ + {"role": "user", "content": "Hello", "timestamp": "2026-03-23T12:00:00"}, + {"role": "assistant", "content": "Hi there", "timestamp": "2026-03-23T12:01:00"}, + ] + mock_db.query.return_value.filter.return_value.first.return_value = mock_session + + result = PrometheusChatManager.getHistory(mock_db, "sess-123") + assert len(result) == 2 + assert result[0]["role"] == "user" + assert result[0]["parts"][0]["text"] == "Hello" + assert result[1]["role"] == "model" + + def test_get_history_empty(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = None + + result = PrometheusChatManager.getHistory(mock_db, "nonexistent") + assert result == [] + + def test_get_history_no_history(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_session.history = None + mock_db.query.return_value.filter.return_value.first.return_value = mock_session + + result = PrometheusChatManager.getHistory(mock_db, "sess-123") + assert result == [] + + def test_get_history_with_limit(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_session.history = [{"role": "user", "content": f"msg{i}"} for i in range(30)] + mock_db.query.return_value.filter.return_value.first.return_value = mock_session + + result = PrometheusChatManager.getHistory(mock_db, "sess-123", limit=5) + assert len(result) == 5 + + def test_delete_session_found(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_session = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = mock_session + + result = PrometheusChatManager.deleteSession(mock_db, "sess-123", userId=1) + assert result is True + mock_db.delete.assert_called_once_with(mock_session) + mock_db.commit.assert_called_once() + + def test_delete_session_not_found(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = None + + result = PrometheusChatManager.deleteSession(mock_db, "nonexistent", userId=1) + assert result is False + + def test_verify_session_ownership_true(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = "sess-123" + + result = PrometheusChatManager.verifySessionOwnership(mock_db, "sess-123", userId=1) + assert result is True + + def test_verify_session_ownership_false(self): + from main.app.prometheus.chat import PrometheusChatManager + + mock_db = MagicMock() + mock_db.query.return_value.filter.return_value.first.return_value = None + + result = PrometheusChatManager.verifySessionOwnership(mock_db, "nonexistent", userId=1) + assert result is False + + +# --------------------------------------------------------------------------- +# AuthenticationManager (authentication.py) +# --------------------------------------------------------------------------- diff --git a/tests/test_relevance_score.py b/tests/test_relevance_score.py index dde006f..c0f8856 100644 --- a/tests/test_relevance_score.py +++ b/tests/test_relevance_score.py @@ -16,39 +16,25 @@ def __init__(self, score=7.0, lastAccessedAt=None): class TestTimeDecay: - def test_just_accessed_has_full_score(self): - mem = FakeMemory(score=7.0, lastAccessedAt=NOW) - score = getRelevanceScore(mem, NOW) - assert score == pytest.approx(1.0, abs=0.01) - - def test_one_day_old(self): - mem = FakeMemory(score=7.0, lastAccessedAt=NOW - timedelta(days=1)) - score = getRelevanceScore(mem, NOW) - # R = e^(-1/7) ≈ 0.867 - assert score == pytest.approx(0.867, abs=0.05) - - def test_seven_days_old(self): - mem = FakeMemory(score=7.0, lastAccessedAt=NOW - timedelta(days=7)) - score = getRelevanceScore(mem, NOW) - # R = e^(-7/7) = e^(-1) ≈ 0.368 - assert score == pytest.approx(0.368, abs=0.05) - - def test_thirty_days_old(self): - mem = FakeMemory(score=7.0, lastAccessedAt=NOW - timedelta(days=30)) - score = getRelevanceScore(mem, NOW) - # R = e^(-30/7) ≈ 0.013 - assert score == pytest.approx(0.013, abs=0.01) - - def test_ninety_days_old(self): - mem = FakeMemory(score=7.0, lastAccessedAt=NOW - timedelta(days=90)) - score = getRelevanceScore(mem, NOW) + @pytest.mark.parametrize( + "days,expected,tol", + [ + (0, 1.0, 0.01), + (1, 0.867, 0.05), + (7, 0.368, 0.05), + (30, 0.013, 0.01), + ], + ) + def test_decay_matches_formula(self, days, expected, tol): + # R = e^(-t/S) with S=7.0 + mem = FakeMemory(score=7.0, lastAccessedAt=NOW - timedelta(days=days)) + assert getRelevanceScore(mem, NOW) == pytest.approx(expected, abs=tol) + + @pytest.mark.parametrize("days,ceiling", [(90, 0.01), (365, 0.001)]) + def test_old_memories_near_zero(self, days, ceiling): # R = e^(-90/7) ≈ 3.3e-6, essentially 0 - assert score < 0.01 - - def test_one_year_old(self): - mem = FakeMemory(score=7.0, lastAccessedAt=NOW - timedelta(days=365)) - score = getRelevanceScore(mem, NOW) - assert score < 0.001 + mem = FakeMemory(score=7.0, lastAccessedAt=NOW - timedelta(days=days)) + assert getRelevanceScore(mem, NOW) < ceiling def test_score_always_positive(self): for days in [0, 1, 7, 30, 90, 365, 730]: @@ -78,14 +64,6 @@ def test_ephemeral_old_loses_to_sticky_new(self): sticky_new = FakeMemory(score=14.0, lastAccessedAt=NOW) assert getRelevanceScore(sticky_new, NOW) > getRelevanceScore(ephemeral_old, NOW) - def test_higher_stability_always_wins_at_same_age(self): - """With same access time, higher stability always produces higher retention.""" - t = NOW - timedelta(days=14) - a = FakeMemory(score=3.0, lastAccessedAt=t) - b = FakeMemory(score=14.0, lastAccessedAt=t) - assert getRelevanceScore(b, NOW) > getRelevanceScore(a, NOW) - - class TestDecayMonotonicity: def test_older_always_lower_score(self): scores = [] diff --git a/tests/test_sandbox.py b/tests/test_sandbox.py index 65427c0..5f93645 100644 --- a/tests/test_sandbox.py +++ b/tests/test_sandbox.py @@ -1,26 +1,10 @@ import pytest from pathlib import Path from unittest.mock import AsyncMock, MagicMock, patch +from tests.conftest import mock_forgevm from main.app.prometheus.sandbox import SandboxManager -def mock_forgevm(mock_cls): - """Wire up mock forgevm AsyncClient that returns sandbox with all methods.""" - mock_client = AsyncMock() - mock_sandbox = AsyncMock() - mock_sandbox.id = "sb-mock-123" - mock_sandbox.exec = AsyncMock(return_value=MagicMock(stdout="Hello\n", stderr="")) - mock_sandbox.read_file = AsyncMock(return_value="file contents") - mock_sandbox.write_file = AsyncMock() - mock_sandbox.list_files = AsyncMock(return_value=[{"path": "/workspace/data.csv", "size": 100, "is_dir": False}]) - mock_sandbox.destroy = AsyncMock() - mock_client.spawn = AsyncMock(return_value=mock_sandbox) - mock_client.get = AsyncMock(return_value=mock_sandbox) - mock_client.close = AsyncMock() - mock_cls.return_value = mock_client - return mock_client, mock_sandbox - - class TestSandboxManager: @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") diff --git a/tests/test_sandbox_persistence.py b/tests/test_sandbox_persistence.py index 165bf95..eefa228 100644 --- a/tests/test_sandbox_persistence.py +++ b/tests/test_sandbox_persistence.py @@ -1,30 +1,12 @@ import pytest from pathlib import Path from unittest.mock import AsyncMock, MagicMock, patch +from tests.conftest import mock_forgevm from forgevm.exceptions import SandboxNotFound from main.models.sandbox import PrometheusSandbox from main.app.prometheus.sandbox import SandboxManager -def mock_forgevm(mock_cls): - """Wire up mock forgevm AsyncClient that returns sandbox with all methods.""" - mock_client = AsyncMock() - mock_sandbox = AsyncMock() - mock_sandbox.id = "sb-mock-123" - mock_sandbox.exec = AsyncMock(return_value=MagicMock(stdout="Hello\n", stderr="")) - mock_sandbox.read_file = AsyncMock(return_value="file contents") - mock_sandbox.write_file = AsyncMock() - mock_sandbox.list_files = AsyncMock(return_value=[{"path": "/workspace/data.csv", "size": 100, "is_dir": False}]) - mock_sandbox.destroy = AsyncMock() - mock_sandbox.extend_ttl = AsyncMock() - mock_sandbox.glob_files = AsyncMock(return_value=[]) - mock_client.spawn = AsyncMock(return_value=mock_sandbox) - mock_client.get = AsyncMock(return_value=mock_sandbox) - mock_client.close = AsyncMock() - mock_cls.return_value = mock_client - return mock_client, mock_sandbox - - class TestPrometheusSandboxModel: def test_create_sandbox_mapping(self, dbSession): sandbox = PrometheusSandbox( diff --git a/tests/test_stocks_api_coverage.py b/tests/test_stocks_api_coverage.py index 6df33d9..b4e570c 100644 --- a/tests/test_stocks_api_coverage.py +++ b/tests/test_stocks_api_coverage.py @@ -75,10 +75,7 @@ def make_manager(self): # --- cacheScheduler (shared scheduler, P5) ------------------------------- @patch("main.app.stocks_api.cache.registerJob") def test_cache_scheduler_registers_shared_job(self, mock_register): - from main.app.stocks_api.cache import StocksCacheManager - - mock_engine = MagicMock() - mgr = StocksCacheManager(mock_engine, threading.Lock()) + mgr = self.make_manager() # spawned init thread must never run against the real feather/subprocess path with patch("main.app.stocks_api.cache.threading.Thread"): diff --git a/tests/test_stocks_cache_zstd.py b/tests/test_stocks_cache_zstd.py index b689a58..e02954c 100644 --- a/tests/test_stocks_cache_zstd.py +++ b/tests/test_stocks_cache_zstd.py @@ -6,7 +6,7 @@ import main.app.stocks_api.cache as cache_mod from main.app.stocks_api.cache import StocksCacheManager -from main.app.stocks_api.query import StocksQueryManager, filterCotationColumn +from main.app.stocks_api.query import deserializeJsonColumns, filterCotationColumn class FakeResult: @@ -274,8 +274,7 @@ def test_deserialize_jsoncolumns_decompresses_bytes(): "COTACAO 10Y PADRAO": [zstd.ZstdCompressor(level=3).compress(b'[{"DATA": "01-01-2024", "PRECO": 10.0}]')], } ) - manager = StocksQueryManager(type("Fake", (), {"STOCKS_CACHE": None, "tickerIndex": {}, "nestedSample": None})()) - out = manager.deserializeJsonColumns(df) + out = deserializeJsonColumns(df) assert out["COTACAO 10Y PADRAO"].iloc[0] == [{"DATA": "01-01-2024", "PRECO": 10.0}] diff --git a/tests/test_stocks_compress.py b/tests/test_stocks_compress.py index 1a83df1..07f631c 100644 --- a/tests/test_stocks_compress.py +++ b/tests/test_stocks_compress.py @@ -60,153 +60,136 @@ def reset_abbrev_globals(): class TestCompactValue: """compactValue: float rounding, int suffixes, date compaction, passthroughs.""" - def test_float_rounds_to_10_significant_digits(self): - assert compactValue(3.14159265358979) == 3.141592654 - - def test_int_trillion_suffix(self): - assert compactValue(1_234_567_890_123) == "1.2T" - - def test_int_billion_suffix(self): - assert compactValue(1_234_567_890) == "1.2B" - - def test_int_million_suffix_exact(self): - assert compactValue(1_000_000) == "1M" - - def test_int_thousand_suffix(self): - assert compactValue(2_500) == "2.5K" - - def test_int_below_thousand_unchanged(self): - assert compactValue(999) == 999 - - def test_negative_int_suffix(self): - assert compactValue(-1_000_000) == "-1M" + @pytest.mark.parametrize( + "value,expected", + [ + (3.14159265358979, 3.141592654), + (1_234_567_890_123, "1.2T"), + (1_234_567_890, "1.2B"), + (1_000_000, "1M"), + (2_500, "2.5K"), + (999, 999), + (-1_000_000, "-1M"), + ("15-06-2026", "06-15"), + ("2026-06-15", "06-15"), + ("hello", "hello"), + ("15-06-202", "15-06-202"), + ], + ) + def test_value_cases(self, value, expected): + assert compactValue(value) == expected def test_bool_untouched(self): assert compactValue(True) is True assert compactValue(False) is False - def test_df_date_compacts_to_mm_yy(self): - assert compactValue("15-06-2026") == "06-15" - - def test_di_date_compacts_to_mm_dd(self): - assert compactValue("2026-06-15") == "06-15" - - def test_non_matching_string_unchanged(self): - assert compactValue("hello") == "hello" - assert compactValue("15-06-202") == "15-06-202" - class TestCompactRow: """compactRow: meta/historical/fundamental abbreviation + nested handling.""" - def test_meta_keys_abbreviated(self): - row = {"TICKER": "PETR4", "NOME": "PETROBRAS PN", "TIME": "2026-06-15"} - assert compactRow(row, "get_fundamental", ABBR_STUB, {}) == { - "TK": "PETR4", - "NM": "PETROBRAS PN", - "TI": "2026-06-15", - } - - def test_historical_year_col(self): - row = {"TICKER": "PETR4", "LUCRO LIQUIDO 2024": 50000} - assert compactRow(row, "get_historical", ABBR_STUB, {}) == {"TK": "PETR4", "LL.24": 50000} - - def test_historical_fallback_first_letters(self): - row = {"RECEITA LIQUIDA 2023": 100000} - assert compactRow(row, "get_historical", ABBR_STUB, {}) == {"RL.23": 100000} - - def test_historical_space_key_without_year_passthrough(self): - row = {"LUCRO LIQUIDO": 1} - assert compactRow(row, "get_historical", ABBR_STUB, {}) == {"LUCRO LIQUIDO": 1} - - def test_fundamental_keys_abbreviated(self): - row = {"P/L": 5.2} - assert compactRow(row, "get_fundamental", ABBR_STUB, {}) == {"PL": 5.2} - - def test_unknown_key_passthrough(self): - row = {"FOO": 1, "P/L": 2} - assert compactRow(row, "get_fundamental", ABBR_STUB, {}) == {"FOO": 1, "PL": 2} - - def test_nested_rename_drop_cap(self): - row = { - "NOTICIAS": [ - {"TITULO": "a", "LINK": "http://x", "EXTRA": "e"}, - {"TITULO": "b", "LINK": "http://y"}, - {"TITULO": "c", "LINK": "http://z"}, - ] - } - assert compactRow(row, "get_fundamental", ABBR_STUB, NEST_STUB) == { - "NOTICIAS": [{"T": "a", "EXTRA": "e"}, {"T": "b"}] - } - - def test_nested_defaults_when_spec_omits_options(self): - nests = {"NOTICIAS": {"subfields": {"TITULO": "T"}}} - row = {"NOTICIAS": [{"TITULO": "a", "LINK": "x"}]} - assert compactRow(row, "get_fundamental", ABBR_STUB, nests) == {"NOTICIAS": [{"T": "a", "LINK": "x"}]} - - def test_nested_field_not_list_untouched(self): - row = {"NOTICIAS": "x"} - assert compactRow(row, "get_fundamental", ABBR_STUB, NEST_STUB) == {"NOTICIAS": "x"} - - def test_nested_non_dict_items_kept(self): - row = {"NOTICIAS": [1, 2]} - assert compactRow(row, "get_fundamental", ABBR_STUB, NEST_STUB) == {"NOTICIAS": [1, 2]} + @pytest.mark.parametrize( + "row,tool,nests,expected", + [ + ( + {"TICKER": "PETR4", "NOME": "PETROBRAS PN", "TIME": "2026-06-15"}, + "get_fundamental", + {}, + {"TK": "PETR4", "NM": "PETROBRAS PN", "TI": "2026-06-15"}, + ), + ( + {"TICKER": "PETR4", "LUCRO LIQUIDO 2024": 50000}, + "get_historical", + {}, + {"TK": "PETR4", "LL.24": 50000}, + ), + ( + {"RECEITA LIQUIDA 2023": 100000}, + "get_historical", + {}, + {"RL.23": 100000}, + ), + ( + {"LUCRO LIQUIDO": 1}, + "get_historical", + {}, + {"LUCRO LIQUIDO": 1}, + ), + ({"P/L": 5.2}, "get_fundamental", {}, {"PL": 5.2}), + ({"FOO": 1, "P/L": 2}, "get_fundamental", {}, {"FOO": 1, "PL": 2}), + ( + { + "NOTICIAS": [ + {"TITULO": "a", "LINK": "http://x", "EXTRA": "e"}, + {"TITULO": "b", "LINK": "http://y"}, + {"TITULO": "c", "LINK": "http://z"}, + ] + }, + "get_fundamental", + NEST_STUB, + {"NOTICIAS": [{"T": "a", "EXTRA": "e"}, {"T": "b"}]}, + ), + ( + {"NOTICIAS": [{"TITULO": "a", "LINK": "x"}]}, + "get_fundamental", + {"NOTICIAS": {"subfields": {"TITULO": "T"}}}, + {"NOTICIAS": [{"T": "a", "LINK": "x"}]}, + ), + ({"NOTICIAS": "x"}, "get_fundamental", NEST_STUB, {"NOTICIAS": "x"}), + ({"NOTICIAS": [1, 2]}, "get_fundamental", NEST_STUB, {"NOTICIAS": [1, 2]}), + ], + ) + def test_row_cases(self, row, tool, nests, expected): + assert compactRow(row, tool, ABBR_STUB, nests) == expected class TestCompactCotations: """compactCotations: single/multi entry compaction + passthroughs.""" - def test_non_list_data_unchanged(self): - result = {"data": "x", "count": 1} - assert compactCotations(result) == {"data": "x", "count": 1} - - def test_missing_data_unchanged(self): - result = {"count": 1} - assert compactCotations(result) == {"count": 1} + @pytest.mark.parametrize( + "result", + [ + {"data": "x", "count": 1}, + {"count": 1}, + {"data": [{"TICKER": "PETR4"}]}, + {"data": [{"TICKER": "PETR4", "COTACAO 10Y PADRAO": []}]}, + {"data": [1, 2]}, + ], + ) + def test_passthrough_unchanged(self, result): + assert compactCotations(result) == result - def test_single_entry(self): - result = { - "data": [ + @pytest.mark.parametrize( + "entry,expected", + [ + ( { "TICKER": "PETR4", "NOME": "PETROBRAS PN", "TIME": "2026-06-15", "COTACAO 10Y PADRAO": [{"DATA": "15-06-2026", "PRECO": 28.5}], - } - ] - } - out = compactCotations(result) - assert out == { - "TK": "PETR4", - "NM": "PETROBRAS PN", - "TI": "06-15", - "C10": {"h": "D,P", "d": ["06-15|28.5"]}, - } + }, + { + "TK": "PETR4", + "NM": "PETROBRAS PN", + "TI": "06-15", + "C10": {"h": "D,P", "d": ["06-15|28.5"]}, + }, + ), + ( + {"TICKER": "PETR4", "COTACAO PADRAO": [{"DATA": "15-06-2026", "PRECO": 1.0}]}, + {"TK": "PETR4", "NM": "", "TI": "", "COTA": {"h": "D,P", "d": ["06-15|1.0"]}}, + ), + ( + {"TICKER": "PETR4", "COTACAO 10Y PADRAO": [{"DATA": "15-06-2026", "PRECO": 1.0}]}, + {"TK": "PETR4", "NM": "", "TI": "", "C10": {"h": "D,P", "d": ["06-15|1.0"]}}, + ), + ], + ) + def test_single_entry_compaction(self, entry, expected): + out = compactCotations({"data": [entry]}) + assert out == expected assert "data" not in out - def test_single_entry_non_10y_key_name(self): - result = {"data": [{"TICKER": "PETR4", "COTACAO PADRAO": [{"DATA": "15-06-2026", "PRECO": 1.0}]}]} - out = compactCotations(result) - assert out == { - "TK": "PETR4", - "NM": "", - "TI": "", - "COTA": {"h": "D,P", "d": ["06-15|1.0"]}, - } - - def test_single_entry_missing_nome_time_default_empty(self): - result = {"data": [{"TICKER": "PETR4", "COTACAO 10Y PADRAO": [{"DATA": "15-06-2026", "PRECO": 1.0}]}]} - out = compactCotations(result) - assert out == {"TK": "PETR4", "NM": "", "TI": "", "C10": {"h": "D,P", "d": ["06-15|1.0"]}} - - def test_single_entry_no_cotation_key_unchanged(self): - result = {"data": [{"TICKER": "PETR4"}]} - assert compactCotations(result) == result - - def test_single_entry_empty_cotation_list_unchanged(self): - result = {"data": [{"TICKER": "PETR4", "COTACAO 10Y PADRAO": []}]} - assert compactCotations(result) == result - def test_multi_entry(self): result = { "data": [ @@ -304,33 +287,56 @@ def test_rebuild_abbrevs_resets_globals(self): class TestCompressResponse: """compressResponse: pipeline orchestration across tools.""" - def test_pops_metadata_present_in_args(self): - raw = { - "count": 2, - "search": "PETR4", - "fields": ["P/L"], - "dates": "2024", - "type": "get_fundamental", - "data": [], - } - out = compressResponse(raw, "get_fundamental", {"search": "PETR4", "fields": ["P/L"], "dates": "2024"}) - assert out == {"data": []} - - def test_keeps_metadata_not_in_args(self): - raw = {"count": 1, "search": "PETR4", "type": "get_fundamental", "data": []} - assert compressResponse(raw, "get_fundamental", {}) == {"search": "PETR4", "data": []} - - def test_empty_data_list_passthrough(self): - raw = {"count": 0, "type": "get_fundamental", "data": []} - assert compressResponse(raw, "get_fundamental", {}) == {"data": []} - - def test_data_not_list_passthrough(self): - raw = {"type": "get_fundamental", "data": {"foo": 1}} - assert compressResponse(raw, "get_fundamental", {}) == {"data": {"foo": 1}} - - def test_data_non_dict_entries_passthrough(self): - raw = {"data": [1, 2]} - assert compressResponse(raw, "get_fundamental", {}) == {"data": [1, 2]} + @pytest.mark.parametrize( + "raw,tool,args,expected", + [ + ( + {"count": 2, "search": "PETR4", "fields": ["P/L"], "dates": "2024", + "type": "get_fundamental", "data": []}, + "get_fundamental", + {"search": "PETR4", "fields": ["P/L"], "dates": "2024"}, + {"data": []}, + ), + ( + {"count": 1, "search": "PETR4", "type": "get_fundamental", "data": []}, + "get_fundamental", + {}, + {"search": "PETR4", "data": []}, + ), + ( + {"count": 0, "type": "get_fundamental", "data": []}, + "get_fundamental", + {}, + {"data": []}, + ), + ( + {"type": "get_fundamental", "data": {"foo": 1}}, + "get_fundamental", + {}, + {"data": {"foo": 1}}, + ), + ( + {"data": [1, 2]}, + "get_fundamental", + {}, + {"data": [1, 2]}, + ), + ( + {"type": "get_cotations", "data": "x"}, + "get_cotations", + {}, + {"data": "x"}, + ), + ( + {"type": "get_live_price", "data": {"TICKER": "PETR4"}}, + "get_live_price", + {}, + {"data": {"TICKER": "PETR4"}}, + ), + ], + ) + def test_passthrough_cases(self, raw, tool, args, expected): + assert compressResponse(raw, tool, args) == expected def test_get_cotations_branch(self): raw = { @@ -354,10 +360,6 @@ def test_get_cotations_branch(self): "C10": {"h": "D,P", "d": ["06-15|28.5"]}, } - def test_get_cotations_data_not_list(self): - raw = {"type": "get_cotations", "data": "x"} - assert compressResponse(raw, "get_cotations", {}) == {"data": "x"} - def test_get_live_price_remaps_price_keys(self): raw = { "count": 1, @@ -387,10 +389,6 @@ def test_get_live_price_remaps_price_keys(self): } } - def test_get_live_price_data_not_list(self): - raw = {"type": "get_live_price", "data": {"TICKER": "PETR4"}} - assert compressResponse(raw, "get_live_price", {}) == {"data": {"TICKER": "PETR4"}} - def test_multi_row_list_of_dicts_with_fallback_abbrs(self): # cache absent: fallback abbrs have empty historical/fundamental, # so "P/L" passes through unabbreviated. Multi-row results stay diff --git a/tests/test_stocks_util.py b/tests/test_stocks_util.py deleted file mode 100644 index 6035d60..0000000 --- a/tests/test_stocks_util.py +++ /dev/null @@ -1,99 +0,0 @@ -import pytest -import sys -import os - -sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) - -from main.app.stocks_api.util import categorizeColumns, parseDateRange -import pandas as pd -from fastapi import HTTPException - - -class TestCategorizeColumns: - def test_categorize_columns_historical_only(self): - columns = ["TICKER", "NOME", "LUCRO LIQUIDO 2020", "LUCRO LIQUIDO 2021", "RECEITA 2020", "RECEITA 2021"] - historical, fundamental = categorizeColumns(columns) - - assert "LUCRO LIQUIDO" in historical - assert 2020 in historical["LUCRO LIQUIDO"] - assert 2021 in historical["LUCRO LIQUIDO"] - assert "RECEITA" in historical - - def test_categorize_columns_fundamental_only(self): - columns = ["TICKER", "NOME", "PRECO", "P/L", "ROE", "DY"] - historical, fundamental = categorizeColumns(columns) - - assert len(historical) == 0 - assert "PRECO" in fundamental - assert "P/L" in fundamental - assert "ROE" in fundamental - - def test_categorize_columns_mixed(self): - columns = ["TICKER", "NOME", "TIME", "PRECO", "P/L", "LUCRO LIQUIDO 2020", "LUCRO LIQUIDO 2021"] - historical, fundamental = categorizeColumns(columns) - - assert "LUCRO LIQUIDO" in historical - assert "PRECO" in fundamental - assert "P/L" in fundamental - - def test_categorize_columns_excludes_special(self): - columns = ["TICKER", "NOME", "TIME", "PRECO"] - historical, fundamental = categorizeColumns(columns) - - assert "TICKER" not in fundamental - assert "NOME" not in fundamental - assert "TIME" not in fundamental - - def test_categorize_columns_empty(self): - historical, fundamental = categorizeColumns([]) - assert len(historical) == 0 - assert len(fundamental) == 0 - - -class TestParseDateRange: - def test_parse_year_single(self): - start, end = parseDateRange("2020") - assert start.year == 2020 - assert start.month == 1 - assert start.day == 1 - assert end.year == 2020 - assert end.month == 12 - assert end.day == 31 - - def test_parse_year_range(self): - start, end = parseDateRange("2020,2023") - assert start.year == 2020 - assert end.year == 2023 - - def test_parse_year_none(self): - start, end = parseDateRange(None) - assert start is None - assert end is None - - def test_parse_year_empty_string(self): - start, end = parseDateRange("") - assert start is None - assert end is None - - def test_parse_month(self): - start, end = parseDateRange("2026-06") - assert start.month == 6 - assert start.day == 1 - assert end.month == 6 - assert end.day == 30 - - def test_parse_full_date(self): - start, end = parseDateRange("2026-06-15") - assert start == end - - def test_parse_two_values(self): - start, end = parseDateRange("2020-03,2023-09") - assert start.year == 2020 - assert start.month == 3 - assert end.year == 2023 - assert end.month == 9 - - def test_parse_three_values_raises(self): - with pytest.raises(HTTPException) as exc: - parseDateRange("2020,2021,2022") - assert exc.value.status_code == 400 diff --git a/tests/test_thread_safety.py b/tests/test_thread_safety.py index a90258a..72fa4fc 100644 --- a/tests/test_thread_safety.py +++ b/tests/test_thread_safety.py @@ -79,6 +79,46 @@ def test_session_is_requests_session(self): session = getSession() assert isinstance(session, requests.Session) + def test_concurrent_sessions_are_thread_local(self): + """getSession() must give each thread its own Session (merged from TestConcurrentGetSession).""" + from main.utils.http_session import getSession + import requests + + results: dict[str, bool] = {} + + def check(name: str): + s = getSession() + results[name] = isinstance(s, requests.Session) + + t1 = threading.Thread(target=check, args=("t1",)) + t2 = threading.Thread(target=check, args=("t2",)) + t1.start() + t2.start() + t1.join() + t2.join() + + assert results.get("t1") is True + assert results.get("t2") is True + + def test_connectivity_uses_getSession(self): + """connectivity.checkServiceConnection must call getSession(), not use a global Session.""" + from main.utils import connectivity + + with patch.object(connectivity, "getSession") as mock_get: + mock_session = MagicMock() + mock_resp = MagicMock() + mock_resp.status_code = 200 + mock_session.get.return_value = mock_resp + mock_get.return_value = mock_session + + with patch.object(connectivity, "Config") as mock_cfg: + mock_cfg.STOCKS_API = {"HOST": "localhost", "PORT": 3200} + result = connectivity.checkServiceConnection("STOCKS_API") + + mock_get.assert_called_once() + mock_session.get.assert_called_once() + assert result is True + # --------------------------------------------------------------------------- # Issue 5 – DiscordHandler bounded thread pool @@ -86,27 +126,33 @@ def test_session_is_requests_session(self): class TestDiscordHandlerThreadPool: - """Verify that DiscordHandler submits to a bounded executor, not raw threads.""" + """Verify DiscordHandler posts via the shared discordQueue, thread-safely.""" - def test_queue_and_lock_exist(self): - """The module-level queue, lock, and event must exist.""" - from main.utils.logging_config import queue, lock, event + def test_queue_and_handler_exist(self): + """The module-level discordQueue and DiscordHandler must exist.""" + from queue import Queue - assert queue is not None - assert lock is not None - assert event is not None + from main.utils.logging_config import DiscordHandler, discordQueue - def test_emit_adds_to_queue(self): - """DiscordHandler.emit() must add messages to the module queue.""" - from main.utils.logging_config import DiscordHandler, queue, lock + assert isinstance(discordQueue, Queue) + handler = DiscordHandler() + assert hasattr(handler, "acquire") and hasattr(handler, "release") - with patch("main.utils.logging_config.Config") as mock_cfg: + def test_emit_posts_to_webhook(self): + """DiscordHandler.emit() must POST the formatted message to the webhook.""" + from unittest.mock import patch + + from main.utils.logging_config import DiscordHandler + + with ( + patch("main.utils.logging_config.Config") as mock_cfg, + patch("main.utils.logging_config.requests.post") as mock_post, + patch("main.utils.logging_config.time.sleep"), + ): mock_cfg.DISCORD.ENABLED = True mock_cfg.DISCORD.WEBHOOK_URL = "https://discord.example.com/hook" handler = DiscordHandler() - with lock: - queue.clear() record = logging.LogRecord( name="test.module", level=logging.ERROR, @@ -118,91 +164,42 @@ def test_emit_adds_to_queue(self): ) handler.emit(record) - with lock: - assert len(queue) == 1 + mock_post.assert_called_once() + assert mock_post.call_args.kwargs["json"]["content"].startswith("[ERROR] [module]") def test_concurrent_emits_are_thread_safe(self): - """Many concurrent emit() calls must not corrupt the queue.""" - from main.utils.logging_config import DiscordHandler, queue, lock + """Many concurrent emit() calls must not corrupt handler state.""" + from unittest.mock import patch + + from main.utils.logging_config import DiscordHandler - with patch("main.utils.logging_config.Config") as mock_cfg: + with ( + patch("main.utils.logging_config.Config") as mock_cfg, + patch("main.utils.logging_config.requests.post") as mock_post, + patch("main.utils.logging_config.time.sleep"), + ): mock_cfg.DISCORD.ENABLED = True mock_cfg.DISCORD.WEBHOOK_URL = "https://discord.example.com/hook" handler = DiscordHandler() - with lock: - queue.clear() - - def emit(): + def emit(i): record = logging.LogRecord( name="test", level=logging.ERROR, pathname="test.py", lineno=1, - msg="concurrent test", + msg=f"concurrent test {i}", args=(), exc_info=None, ) handler.emit(record) - # Fire 20 concurrent emits - workers = [threading.Thread(target=emit) for _ in range(20)] + # Fire 20 concurrent emits with distinct messages (no dedup) + workers = [threading.Thread(target=emit, args=(i,)) for i in range(20)] for w in workers: w.start() for w in workers: w.join(timeout=5) - with lock: - # Queue may deduplicate identical messages, but no corruption - assert len(queue) >= 1 - assert all(isinstance(msg, str) for msg in queue) - - -# --------------------------------------------------------------------------- -# Integration: concurrent HTTP via getSession -# --------------------------------------------------------------------------- - - -class TestConcurrentGetSession: - """Verify getSession returns thread-local sessions under concurrency.""" - - def test_getSession_returns_thread_local_sessions(self): - """getSession() must give each thread its own Session.""" - from main.utils.http_session import getSession - import requests - - results: dict[str, bool] = {} - - def check(name: str): - s = getSession() - results[name] = isinstance(s, requests.Session) - - t1 = threading.Thread(target=check, args=("t1",)) - t2 = threading.Thread(target=check, args=("t2",)) - t1.start() - t2.start() - t1.join() - t2.join() - - assert results.get("t1") is True - assert results.get("t2") is True - - def test_connectivity_uses_getSession(self): - """connectivity.checkServiceConnection must call getSession(), not use a global Session.""" - from main.utils import connectivity - - with patch.object(connectivity, "getSession") as mock_get: - mock_session = MagicMock() - mock_resp = MagicMock() - mock_resp.status_code = 200 - mock_session.get.return_value = mock_resp - mock_get.return_value = mock_session - - with patch.object(connectivity, "Config") as mock_cfg: - mock_cfg.STOCKS_API = {"HOST": "localhost", "PORT": 3200} - result = connectivity.checkServiceConnection("STOCKS_API") - - mock_get.assert_called_once() - mock_session.get.assert_called_once() - assert result is True + assert mock_post.call_count == 20 From da61e77c7b2c62f67dda30097d5a690229b81def Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 15:27:34 -0300 Subject: [PATCH 30/57] fix logging tests hanging on real listener thread and network post --- tests/test_logging_config_coverage.py | 93 ++++++++++++++++++--------- 1 file changed, 64 insertions(+), 29 deletions(-) diff --git a/tests/test_logging_config_coverage.py b/tests/test_logging_config_coverage.py index d70d7fd..1c6741f 100644 --- a/tests/test_logging_config_coverage.py +++ b/tests/test_logging_config_coverage.py @@ -6,6 +6,30 @@ class TestDiscordHandlerEmit: + @pytest.fixture(autouse=True) + def _isolate_root_handlers(self): + # Import-time setupDiscordHandler() installs a real QueueHandler on + # the root logger + a live QueueListener thread. While Config is + # mocked, any ERROR log anywhere would ride that path into the + # globally-mocked requests.post and inflate call_count (2 == 1 + # flakes). Detach root handlers + drain the queue per test. + import queue + + import main.utils.logging_config as lc + + root = logging.getLogger() + saved = list(root.handlers) + root.handlers.clear() + try: + while True: + lc.discordQueue.get_nowait() + except queue.Empty: + pass + try: + yield + finally: + root.handlers[:] = saved + def make_handler(self): from main.utils.logging_config import DiscordHandler @@ -47,38 +71,32 @@ def test_level_below_error(self, mockConfig): record = self.make_record(level=logging.WARNING) handler.emit(record) + @patch("main.utils.logging_config.requests.post") @patch("main.utils.logging_config.Config") - def test_message_queued_on_error(self, mockConfig): + def test_message_queued_on_error(self, mockConfig, mockPost): mockConfig.DISCORD.ENABLED = True mockConfig.DISCORD.WEBHOOK_URL = "https://hook.test/123" - from main.utils.logging_config import queue, lock - handler = self.make_handler() - with lock: - queue.clear() record = self.make_record(level=logging.ERROR, msg="something broke") handler.emit(record) - with lock: - assert len(queue) == 1 + assert mockPost.call_count == 1 + @patch("main.utils.logging_config.requests.post") @patch("main.utils.logging_config.Config") - def test_message_truncation(self, mockConfig): + def test_message_truncation(self, mockConfig, mockPost): mockConfig.DISCORD.ENABLED = True mockConfig.DISCORD.WEBHOOK_URL = "https://hook.test/123" - from main.utils.logging_config import queue, lock - handler = self.make_handler() - with lock: - queue.clear() long_msg = "x" * 3000 record = self.make_record(level=logging.ERROR, msg=long_msg) handler.emit(record) - with lock: - assert len(queue) == 1 - assert len(queue[0]) <= 2000 + assert mockPost.call_count == 1 + content = mockPost.call_args.kwargs["json"]["content"] + assert len(content) <= 2000 + @patch("main.utils.logging_config.requests.post") @patch("main.utils.logging_config.Config") - def test_emit_does_not_raise(self, mockConfig): + def test_emit_does_not_raise(self, mockConfig, mockPost): mockConfig.DISCORD.ENABLED = True mockConfig.DISCORD.WEBHOOK_URL = "https://hook.test/123" handler = self.make_handler() @@ -86,15 +104,12 @@ def test_emit_does_not_raise(self, mockConfig): # Should not raise handler.emit(record) + @patch("main.utils.logging_config.requests.post") @patch("main.utils.logging_config.Config") - def test_with_exception_info(self, mockConfig): + def test_with_exception_info(self, mockConfig, mockPost): mockConfig.DISCORD.ENABLED = True mockConfig.DISCORD.WEBHOOK_URL = "https://hook.test/123" - from main.utils.logging_config import queue, lock - handler = self.make_handler() - with lock: - queue.clear() try: raise ValueError("test error") except ValueError: @@ -103,24 +118,44 @@ def test_with_exception_info(self, mockConfig): exc_info = sys.exc_info() record = self.make_record(level=logging.ERROR, msg="failed", exc_info=exc_info) handler.emit(record) - with lock: - assert len(queue) == 1 - assert "ValueError" in queue[0] + assert mockPost.call_count == 1 + content = mockPost.call_args.kwargs["json"]["content"] + assert "ValueError" in content class TestSetupLogging: + @patch("main.utils.logging_config.QueueListener") @patch("main.utils.logging_config.Config") - def test_setup_discord_handler_enabled(self, mockConfig): + def test_setup_discord_handler_enabled(self, mockConfig, mockListenerCls): mockConfig.DISCORD.ENABLED = True mockConfig.DISCORD.WEBHOOK_URL = "https://hook.test/123" from main.utils.logging_config import setupDiscordHandler - # Should add handler - setupDiscordHandler() - + root = logging.getLogger() + before = list(root.handlers) + try: + # Should add handler (listener mocked: no real thread starts) + setupDiscordHandler() + mockListenerCls.assert_called_once() + mockListenerCls.return_value.start.assert_called_once() + finally: + for h in list(root.handlers): + if h not in before: + root.removeHandler(h) + try: + h.close() + except Exception: + pass + try: + mockListenerCls.return_value.stop() + except Exception: + pass + + @patch("main.utils.logging_config.QueueListener") @patch("main.utils.logging_config.Config") - def test_setup_discord_handler_disabled(self, mockConfig): + def test_setup_discord_handler_disabled(self, mockConfig, mockListenerCls): mockConfig.DISCORD.ENABLED = False from main.utils.logging_config import setupDiscordHandler setupDiscordHandler() + mockListenerCls.assert_not_called() From d6bd668efa7bb9bd73db98c63ade5b3e04fbb072 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 15:40:15 -0300 Subject: [PATCH 31/57] restore pagination boundary tests against real endpoint --- tests/test_pagination.py | 113 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 tests/test_pagination.py diff --git a/tests/test_pagination.py b/tests/test_pagination.py new file mode 100644 index 0000000..252a201 --- /dev/null +++ b/tests/test_pagination.py @@ -0,0 +1,113 @@ +"""Pagination boundary tests against the real GET /prometheus/sessions endpoint. + +Replaces the deleted synthetic `/items` app tests with equivalent assertions +against the real Query(ge/le) guards in main/controller/prometheus_controller.py: +`limit: int = Query(20, ge=1, le=100)`, `offset: int = Query(0, ge=0)`. +""" + +import sys +import os +from unittest.mock import patch + +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) + +from tests.conftest import make_prometheus_client + + +def makeSessions(count: int) -> list[dict]: + return [{"sessionId": f"s{i}", "title": f"Chat {i}"} for i in range(count)] + + +class TestPrometheusSessionsPagination: + def test_defaults(self): + with patch("main.controller.prometheus_controller.PrometheusChatManager") as mockPcm: + mockPcm.getUserSessions.return_value = makeSessions(50) + client, _, _ = make_prometheus_client() + resp = client.get("/prometheus/sessions") + assert resp.status_code == 200 + body = resp.json() + assert body["limit"] == 20 + assert body["offset"] == 0 + assert body["total"] == 50 + assert len(body["sessions"]) == 20 + + def test_customLimit(self): + with patch("main.controller.prometheus_controller.PrometheusChatManager") as mockPcm: + mockPcm.getUserSessions.return_value = makeSessions(50) + client, _, _ = make_prometheus_client() + resp = client.get("/prometheus/sessions?limit=5") + body = resp.json() + assert resp.status_code == 200 + assert body["limit"] == 5 + assert len(body["sessions"]) == 5 + + def test_customOffset(self): + with patch("main.controller.prometheus_controller.PrometheusChatManager") as mockPcm: + mockPcm.getUserSessions.return_value = makeSessions(50) + client, _, _ = make_prometheus_client() + resp = client.get("/prometheus/sessions?offset=10") + body = resp.json() + assert resp.status_code == 200 + assert body["offset"] == 10 + assert len(body["sessions"]) == 20 + assert body["sessions"][0]["sessionId"] == "s10" + + def test_limitAndOffset(self): + with patch("main.controller.prometheus_controller.PrometheusChatManager") as mockPcm: + mockPcm.getUserSessions.return_value = makeSessions(100) + client, _, _ = make_prometheus_client() + resp = client.get("/prometheus/sessions?limit=10&offset=50") + body = resp.json() + assert resp.status_code == 200 + assert body["limit"] == 10 + assert body["offset"] == 50 + assert len(body["sessions"]) == 10 + assert body["sessions"][0]["sessionId"] == "s50" + + def test_limitExceedsMaxRejected(self): + with patch("main.controller.prometheus_controller.PrometheusChatManager") as mockPcm: + mockPcm.getUserSessions.return_value = makeSessions(150) + client, _, _ = make_prometheus_client() + resp = client.get("/prometheus/sessions?limit=101") + assert resp.status_code == 422 + + def test_limitZeroRejected(self): + with patch("main.controller.prometheus_controller.PrometheusChatManager") as mockPcm: + mockPcm.getUserSessions.return_value = makeSessions(50) + client, _, _ = make_prometheus_client() + resp = client.get("/prometheus/sessions?limit=0") + assert resp.status_code == 422 + + def test_limitNegativeRejected(self): + with patch("main.controller.prometheus_controller.PrometheusChatManager") as mockPcm: + mockPcm.getUserSessions.return_value = makeSessions(50) + client, _, _ = make_prometheus_client() + resp = client.get("/prometheus/sessions?limit=-1") + assert resp.status_code == 422 + + def test_negativeOffsetRejected(self): + with patch("main.controller.prometheus_controller.PrometheusChatManager") as mockPcm: + mockPcm.getUserSessions.return_value = makeSessions(50) + client, _, _ = make_prometheus_client() + resp = client.get("/prometheus/sessions?offset=-1") + assert resp.status_code == 422 + + def test_offsetBeyondTotal(self): + with patch("main.controller.prometheus_controller.PrometheusChatManager") as mockPcm: + mockPcm.getUserSessions.return_value = makeSessions(50) + client, _, _ = make_prometheus_client() + resp = client.get("/prometheus/sessions?offset=200") + body = resp.json() + assert resp.status_code == 200 + assert body["sessions"] == [] + assert body["total"] == 50 + + def test_limitEqualsMax(self): + with patch("main.controller.prometheus_controller.PrometheusChatManager") as mockPcm: + mockPcm.getUserSessions.return_value = makeSessions(150) + client, _, _ = make_prometheus_client() + resp = client.get("/prometheus/sessions?limit=100") + body = resp.json() + assert resp.status_code == 200 + assert body["limit"] == 100 + assert len(body["sessions"]) == 100 From c70c13418661d63720e47519841e95aaabdff09f Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 19:45:42 -0300 Subject: [PATCH 32/57] remove unused stocksapi quota settings fields --- config.py | 2 -- tests/test_config.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/config.py b/config.py index a7f20d4..bf30a45 100644 --- a/config.py +++ b/config.py @@ -53,8 +53,6 @@ class StocksApiSettings(BaseSettings): PORT: int = Field(default=3200, validation_alias=AliasChoices("STOCKSAPI_PORT")) KEY_SYSTEM: bool = Field(default=False, validation_alias=AliasChoices("STOCKSAPI_KEY.SYSTEM")) KEY: str = Field(default="", validation_alias=AliasChoices("STOCKSAPI_PRIVATE.KEY")) - DEFAULT_QUOTA: int = Field(default=100, validation_alias=AliasChoices("STOCKSAPI_DEFAULT.QUOTA")) - QUOTA_RESETDAYS: int = Field(default=30, validation_alias=AliasChoices("STOCKSAPI_QUOTA.RESETDAYS")) model_config = SettingsConfigDict(env_file=".env", extra="ignore") diff --git a/tests/test_config.py b/tests/test_config.py index b0849c5..6b3b03c 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -6,7 +6,7 @@ class TestConfig: def test_stocks_api_attributes(self): settings = StocksApiSettings() assert settings.KEY_SYSTEM is not None - assert settings.DEFAULT_QUOTA is not None + assert settings.KEY is not None def test_prometheus_attributes(self): settings = PrometheusSettings() From 121e2c7d81ca7a1ceff532a8d388b5b40dc16132 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 19:45:50 -0300 Subject: [PATCH 33/57] restore ci docker compose file per refused ruling --- .github/workflows/ci.yml | 57 +++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05962e3..ad05334 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -112,23 +112,38 @@ jobs: - name: Build Docker image run: docker build -t mansa-server:test . - - name: Export CI database credentials + - name: Create docker-compose.ci.yml for testing run: | - echo "MYSQL_ROOT_PASSWORD=${{ secrets.USER_MYSQL_PASSWORD }}" >> $GITHUB_ENV - echo "MYSQL_DATABASE=${{ secrets.USER_MYSQL_DATABASE }}" >> $GITHUB_ENV - echo "MYSQL_USER=${{ secrets.USER_MYSQL_USER }}" >> $GITHUB_ENV - echo "MYSQL_PASSWORD=${{ secrets.USER_MYSQL_PASSWORD }}" >> $GITHUB_ENV - echo "USER_MYSQL_HOST=db" >> $GITHUB_ENV - echo "USER_MYSQL_USER=${{ secrets.USER_MYSQL_USER }}" >> $GITHUB_ENV - echo "USER_MYSQL_PASSWORD=${{ secrets.USER_MYSQL_PASSWORD }}" >> $GITHUB_ENV - echo "USER_MYSQL_DATABASE=${{ secrets.USER_MYSQL_DATABASE }}" >> $GITHUB_ENV - echo "STOCKS_MYSQL_HOST=db" >> $GITHUB_ENV - echo "STOCKS_MYSQL_USER=${{ secrets.STOCKS_MYSQL_USER }}" >> $GITHUB_ENV - echo "STOCKS_MYSQL_PASSWORD=${{ secrets.STOCKS_MYSQL_PASSWORD }}" >> $GITHUB_ENV - echo "STOCKS_MYSQL_DATABASE=${{ secrets.STOCKS_MYSQL_DATABASE }}" >> $GITHUB_ENV - echo "USER_PORT=3200" >> $GITHUB_ENV - echo "STOCKSAPI_PORT=3201" >> $GITHUB_ENV - echo "PROMETHEUS_PORT=3202" >> $GITHUB_ENV + cat > docker-compose.ci.yml << 'EOF' + services: + db: + image: mysql:8.0 + environment: + MYSQL_ROOT_PASSWORD: ${{ secrets.USER_MYSQL_PASSWORD }} + MYSQL_DATABASE: ${{ secrets.USER_MYSQL_DATABASE }} + MYSQL_USER: ${{ secrets.USER_MYSQL_USER }} + MYSQL_PASSWORD: ${{ secrets.USER_MYSQL_PASSWORD }} + ports: + - "3306:3306" + + api: + image: mansa-server:test + ports: + - "8000:8000" + - "3200:3200" + environment: + USER_MYSQL_HOST: ${{ secrets.USER_MYSQL_HOST }} + USER_MYSQL_USER: ${{ secrets.USER_MYSQL_USER }} + USER_MYSQL_PASSWORD: ${{ secrets.USER_MYSQL_PASSWORD }} + USER_MYSQL_DATABASE: ${{ secrets.USER_MYSQL_DATABASE }} + STOCKS_MYSQL_HOST: ${{ secrets.STOCKS_MYSQL_HOST }} + STOCKS_MYSQL_USER: ${{ secrets.STOCKS_MYSQL_USER }} + STOCKS_MYSQL_PASSWORD: ${{ secrets.STOCKS_MYSQL_PASSWORD }} + STOCKS_MYSQL_DATABASE: ${{ secrets.STOCKS_MYSQL_DATABASE }} + DEBUG_MODE: "TRUE" + depends_on: + - db + EOF - name: Install Docker Compose run: | @@ -137,13 +152,13 @@ jobs: chmod +x ~/.docker/cli-plugins/docker-compose - name: Start services - run: docker compose up -d db api + run: docker compose -f docker-compose.ci.yml up -d - name: Wait for MySQL to be ready run: sleep 15 - name: Show container logs - run: docker compose logs + run: docker compose -f docker-compose.ci.yml logs - name: Check health endpoints run: | @@ -152,12 +167,12 @@ jobs: curl -f http://localhost:3200/user/health || echo "User health not available" - name: Show API logs (verify migrations ran) - run: docker compose logs api + run: docker compose -f docker-compose.ci.yml logs api - name: Show final container status if: always() - run: docker compose ps + run: docker compose -f docker-compose.ci.yml ps - name: Stop and remove containers if: always() - run: docker compose down -v \ No newline at end of file + run: docker compose -f docker-compose.ci.yml down -v \ No newline at end of file From 7b6fb349d27d8cec014ef7c3dc35b175317a050c Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 19:48:09 -0300 Subject: [PATCH 34/57] todo --- TODO.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/TODO.md b/TODO.md index c9b9c72..ca5a828 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,9 @@ - [ ] Implement an user management system so the user can customize its name, change password, profile picture and settings - [ ] Make an Password Recovery system and 2FA using the Email Protocol +- [ ] the scraper rentability should be calculated based on the COTACOA 10Y AJUSTADA instead of the tradingview endpoint +- [ ] add MACD, RSI and other metrics + - [ ] Use the ForgeVM architecture to expose MetaTrader5 terminals - [ ] Abacate Pay From 78084c0d76c87622625b9986338e6ffe40c7a28c Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 20:18:46 -0300 Subject: [PATCH 35/57] ci --- graphify-out/.graphify_labels.json | 6 +- graphify-out/GRAPH_REPORT.md | 388 ++- graphify-out/graph.json | 5021 +++++++++++++++++----------- graphify-out/manifest.json | 103 +- main/app/prometheus/sandbox.py | 4 +- tests/test_api_key_quota_atomic.py | 7 +- tests/test_relevance_score.py | 1 + tests/test_roles.py | 1 + tests/test_sandbox_auth_gating.py | 21 +- tests/test_stocks_compress.py | 10 +- 10 files changed, 3431 insertions(+), 2131 deletions(-) diff --git a/graphify-out/.graphify_labels.json b/graphify-out/.graphify_labels.json index 2912274..6eae3fa 100644 --- a/graphify-out/.graphify_labels.json +++ b/graphify-out/.graphify_labels.json @@ -567,6 +567,8 @@ "565": "Community 565", "566": "Community 566", "567": "Community 567", + "568": "Community 568", + "569": "Community 569", "570": "Community 570", "571": "Community 571", "572": "Community 572", @@ -574,7 +576,5 @@ "574": "Community 574", "575": "Community 575", "576": "Community 576", - "577": "Community 577", - "578": "Community 578", - "579": "Community 579" + "577": "Community 577" } diff --git a/graphify-out/GRAPH_REPORT.md b/graphify-out/GRAPH_REPORT.md index d862c70..d6b3ac9 100644 --- a/graphify-out/GRAPH_REPORT.md +++ b/graphify-out/GRAPH_REPORT.md @@ -1,16 +1,16 @@ -# Graph Report - server (2026-09-13) +# Graph Report - server (2026-09-14) ## Corpus Check -- 121 files · ~71,444 words +- 124 files · ~73,749 words - Verdict: corpus is large enough that graph structure adds value. ## Summary -- 5977 nodes · 8029 edges · 578 communities (337 shown, 241 thin omitted) -- Extraction: 84% EXTRACTED · 16% INFERRED · 0% AMBIGUOUS · INFERRED: 1258 edges (avg confidence: 0.69) +- 6024 nodes · 8107 edges · 578 communities (344 shown, 234 thin omitted) +- Extraction: 84% EXTRACTED · 16% INFERRED · 0% AMBIGUOUS · INFERRED: 1267 edges (avg confidence: 0.69) - Token cost: 0 input · 0 output ## Graph Freshness -- Built from commit: `8e244c48` +- Built from commit: `c70c1341` - Run `git rev-parse HEAD` and compare to check if the graph is stale. - Run `graphify update .` after code changes (no API cost). @@ -568,6 +568,8 @@ - [[_COMMUNITY_Community 565|Community 565]] - [[_COMMUNITY_Community 566|Community 566]] - [[_COMMUNITY_Community 567|Community 567]] +- [[_COMMUNITY_Community 568|Community 568]] +- [[_COMMUNITY_Community 569|Community 569]] - [[_COMMUNITY_Community 570|Community 570]] - [[_COMMUNITY_Community 571|Community 571]] - [[_COMMUNITY_Community 572|Community 572]] @@ -576,16 +578,14 @@ - [[_COMMUNITY_Community 575|Community 575]] - [[_COMMUNITY_Community 576|Community 576]] - [[_COMMUNITY_Community 577|Community 577]] -- [[_COMMUNITY_Community 578|Community 578]] -- [[_COMMUNITY_Community 579|Community 579]] ## God Nodes (most connected - your core abstractions) 1. `vocab` - 456 edges 2. `StocksCacheManager` - 80 edges 3. `HarnessState` - 68 edges 4. `UserManager` - 56 edges -5. `StocksQueryManager` - 50 edges -6. `Permission` - 50 edges +5. `Permission` - 50 edges +6. `StocksQueryManager` - 50 edges 7. `Pytest Testing` - 50 edges 8. `Roles` - 45 edges 9. `cn()` - 43 edges @@ -598,10 +598,10 @@ main/app/stocks_api/cache.py → tests/test_stocks_api_coverage.py - `StocksCacheManager` --calls--> `test_cache_scheduler_starts_daemon_thread()` [INFERRED] main/app/stocks_api/cache.py → tests/test_stocks_api_coverage.py +- `DiscordHandler` --uses--> `TestSetupLogging` [INFERRED] + main/utils/logging_config.py → tests/test_logging_config_coverage.py - `createKey()` --calls--> `test_create_key_new_user()` [INFERRED] main/app/stocks_api/key.py → tests/test_stocks_api_coverage.py -- `createKey()` --calls--> `test_create_key_exception_rollback()` [INFERRED] - main/app/stocks_api/key.py → tests/test_stocks_api_coverage.py ## Hyperedges (group relationships) - **Authentication Module** — AuthenticationManager, SessionManager, auth_util, auth_constants, getGoogleSSO [INFERRED] @@ -611,7 +611,7 @@ - **Configuration & Database Infrastructure** — config_Config, config_engine, config_stocksEngine [INFERRED] - **User Authentication & Authorization** — user_service, authentication, user_roles, permission_system [INFERRED] -## Communities (578 total, 241 thin omitted) +## Communities (578 total, 234 thin omitted) ### Community 0 - "Stocks API Endpoints" Cohesion: 0.0 @@ -626,8 +626,8 @@ Cohesion: 0.13 Nodes (21): Thin async wrapper around the CubeSandbox/E2B HTTP API. All methods are sta, SandboxManager, _mock_forgevm(), Unit tests for SandboxManager — HTTP calls mocked via a fake client class., Wire up mock forgevm AsyncClient that returns sandbox with all methods., Wire up mock forgevm AsyncClient that returns sandbox with all methods., test_create_sandbox(), test_destroy_sandbox() (+13 more) ### Community 3 - "Prometheus Agent" -Cohesion: 0.06 -Nodes (28): Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., replaceNan handles direct float NaN values (line 34)., Tests covering cache.py lines 28-76., Tests covering cache.py lines 28-76. (+20 more) +Cohesion: 0.11 +Nodes (12): _make_stocks_df(), Return a small DataFrame with the columns the query module expects., Return a small DataFrame with the columns the query module expects., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48. (+4 more) ### Community 4 - "Data Models & Types" Cohesion: 0.11 @@ -646,15 +646,15 @@ Cohesion: 0.07 Nodes (29): Algorithmic Compression (`compact.py`) Implementation Plan, code:python (# main/app/prometheus/compact.py), code:python (# Before:), code:python (# Before:), code:python (# Before:), code:bash (pytest tests/ -k "prometheus" -v), code:bash (git add main/app/prometheus/agent.py), code:bash (git mv main/app/prometheus/summarizer.py main/app/prometheus) (+21 more) ### Community 8 - "Device Detection" -Cohesion: 0.05 -Nodes (16): HarnessState, Retrieve a value from state. Returns default if key not found., Return a copy of the current state., Format state as a string for injection into the LLM context., Check if state changed since last reset., Reset the changed flag. Returns the previous state., Clear all state data., In-memory state dict that persists across loop iterations within a single reques (+8 more) +Cohesion: 0.08 +Nodes (9): HarnessState, Retrieve a value from state. Returns default if key not found., Return a copy of the current state., Format state as a string for injection into the LLM context., Check if state changed since last reset., Reset the changed flag. Returns the previous state., Clear all state data., In-memory state dict that persists across loop iterations within a single reques (+1 more) ### Community 9 - "Server Configuration" Cohesion: 0.11 Nodes (17): code:python (def filterCotationColumn(series: pd.Series, startDate, endDa), code:bash (git add -A), code:bash (git add main/app/stocks_api/query.py), code:python (def buildCotationDateIndex(df: pd.DataFrame, col: str = "COT), code:python (def filterCotationColumn(series: pd.Series, startDate, endDa), code:bash (git add main/app/stocks_api/cache.py main/app/stocks_api/que), code:python (PARQUET_PATH = Path(__file__).parent / "stocks_cache.parquet), code:bash (git add main/app/stocks_api/cache.py) (+9 more) ### Community 10 - "Prometheus Memory" -Cohesion: 0.06 +Cohesion: 0.05 Nodes (35): Tests for queryCotations and /stocks/cotations., 2 tickers x 2 rows. Rows 0,2 are 2024-01-15; rows 1,3 are 2024-06-15. M, Tests for queryCotations and /stocks/cotations., 4 rows for 2 tickers -> 2 results, one per ticker, both with latest TIME., 4 rows for 2 tickers -> 2 results, one per ticker, both with latest TIME., 2 tickers x 2 rows. Rows 0,2 are 2024-01-15; rows 1,3 are 2024-06-15. M, dates="2016-12-02" should keep only the 02-12-2016 entry in each JSON list., dates="2016-12-02" should keep only the 02-12-2016 entry in each JSON list. (+27 more) ### Community 11 - "Auth Utilities & SSO" @@ -666,24 +666,24 @@ Cohesion: 0.08 Nodes (13): LoopEvent, LoopEvent model for observable agent loops., LoopLogger, LoopLogger — batched event logging for observable agent loops., Queue events during a loop, flush to DB at end., Log a generic event with optional metadata., Log a tool invocation., Log end of a turn with timing. (+5 more) ### Community 13 - "Prometheus Tools" -Cohesion: 0.13 -Nodes (21): benchOnce(), main(), _fulltext_search(), fullTextSearch(), minMax(), scoreCandidates(), scoreRecency(), search() (+13 more) +Cohesion: 0.15 +Nodes (13): benchOnce(), main(), batchCosineSimilarity(), decodeEmbeddings(), normalizeRows(), Empty matrix → empty array., Single row matches cosine_similarity., Multiple rows ranked correctly. (+5 more) ### Community 14 - "User Roles & Permissions" Cohesion: 0.06 -Nodes (30): _make_stocksapi_client(), Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont, Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont, Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont (+22 more) +Nodes (30): _make_stocksapi_client(), Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont, Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont, Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont (+22 more) ### Community 15 - "Community 15" Cohesion: 0.05 Nodes (38): code:block1 (User 123: "Analyze PETR4 vs VALE3 correlation"), code:python (from main.app.prometheus.sandbox import SandboxManager), code:python (TOOL_REGISTRY: dict[str, Any] = {), code:bash (git add main/app/prometheus/tools.py tests/test_sandbox_tool), code:python (import pytest), code:python (from main.app.prometheus.sandbox import SandboxManager), code:python (async def streamMessage(self, query=None, sessionId=None, db), code:python (## Code Sandbox (On-Demand)) (+30 more) ### Community 16 - "Community 16" -Cohesion: 0.09 -Nodes (20): Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 109-136: POST /prometheus/chat/stream (SSE)., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 120-121: existing session with verified ownership., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat. (+12 more) +Cohesion: 0.06 +Nodes (31): _make_prometheus_client(), Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 111-112: sessionId is None, new session created., Covers lines 111-112: sessionId is None, new session created., Covers lines 109-136: POST /prometheus/chat/stream (SSE)., Covers lines 118-119: sessionId is None, new session created., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat. (+23 more) ### Community 17 - "Community 17" -Cohesion: 0.08 -Nodes (23): search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., DataFrame without TIME column., Invalid date -> inner 400 caught by outer except -> 500., DataFrame without TIME column., DataFrame without TIME column., search.strip() == '' should still dedup (line 181). (+15 more) +Cohesion: 0.07 +Nodes (26): Two dates in the range, both valid., Two dates in the range, both valid., Two dates in the range, both valid., Two dates in the range, both valid., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., search.strip() == '' should still dedup (line 181)., Search with no index match falls back to string startswith. (+18 more) ### Community 18 - "Community 18" Cohesion: 0.07 @@ -698,12 +698,12 @@ Cohesion: 0.06 Nodes (35): 1. Memory System (B+), 2. Summarizer/Episodes (B), 3. Loop Events (A-), 4. Core Architecture (B+), 5. Security (B+), 6. Performance (B), 7. Code Quality (B), After (B+) (+27 more) ### Community 21 - "Community 21" -Cohesion: 0.06 -Nodes (24): Store a value in state. Marks state as changed for context injection., _make_stocks_df(), Return a small DataFrame with the columns the query module expects., Return a small DataFrame with the columns the query module expects., Tests covering query.py lines 77-132., Tests covering query.py lines 77-132., Tests covering query.py lines 77-132., Tests covering query.py lines 77-132. (+16 more) +Cohesion: 0.11 +Nodes (16): Calling with all None returns 400., Tests covering query.py lines 142-202., Tests covering query.py lines 142-202., Tests covering query.py lines 142-202., Tests covering query.py lines 142-202., Tests covering query.py lines 142-202., Tests covering query.py lines 142-202., Calling with all None returns 400. (+8 more) ### Community 22 - "Community 22" -Cohesion: 0.14 -Nodes (7): filterCotationColumn(), Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., TestQueryLiveCotation +Cohesion: 0.1 +Nodes (13): filterCotationColumn(), Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422. (+5 more) ### Community 23 - "Community 23" Cohesion: 0.06 @@ -714,20 +714,20 @@ Cohesion: 0.09 Nodes (5): Tests for agent <-> persistent sandbox integration (Task 3)., Verify the agent uses getOrCreate + syncToSandbox/syncFromSandbox., Test the premium gating logic used in streamMessage., TestPersistentSandboxLifecycle, TestPremiumCheck ### Community 25 - "Community 25" -Cohesion: 0.09 -Nodes (9): Tests for input validation via HTTP endpoints. Validation is now inline via Bod, PUT /prometheus/sessions/{sessionId} — validates title via Body(...), POST /auth/register — validates username, email, password via Body(...), Test that endpoints reject requests with missing required fields., POST /auth/login — validates username, password via Body(...), TestLoginValidation, TestMissingBody, TestRegisterValidation (+1 more) +Cohesion: 0.06 +Nodes (13): Tests for input validation via HTTP endpoints. Validation is now inline via Bod, PUT /prometheus/sessions/{sessionId} — validates title via Body(...), POST /prometheus/chat/stream — validates query via Body(...), POST /auth/register — validates username, email, password via Body(...), Test that endpoints reject requests with missing required fields., POST /auth/login — validates username, password via Body(...), POST /prometheus/sessions — validates title via Body(...), TestChatValidation (+5 more) ### Community 26 - "Community 26" Cohesion: 0.11 Nodes (20): createKey(), _hash_key(), hashKey(), Return SHA-256 hex digest of the given key., Test that concurrent requests are properly serialized at DB level. Th, Test edge case: request exactly at quota limit., Test edge case: request exactly at quota limit., Test that invalid API key returns zero rows affected. (+12 more) ### Community 27 - "Community 27" -Cohesion: 0.16 -Nodes (14): getRelevanceScore(), _FakeMemory, A memory with no lastAccessedAt should use baseScore as-is., Scores are deterministic — no cron mutation needed., Same memory at different points in time yields different scores., A memory accessed 10x (baseScore 1.0) should still outrank a memory acce, A rarely-used old memory should lose to a popular fresh one., With same access time, higher baseScore always wins. (+6 more) +Cohesion: 0.15 +Nodes (15): getUserMemories(), getRelevanceScore(), _FakeMemory, A memory with no lastAccessedAt should use baseScore as-is., Scores are deterministic — no cron mutation needed., Same memory at different points in time yields different scores., A memory accessed 10x (baseScore 1.0) should still outrank a memory acce, A rarely-used old memory should lose to a popular fresh one. (+7 more) ### Community 28 - "Community 28" -Cohesion: 0.07 -Nodes (27): Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., If an unexpected exception occurs in queryHistorical., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them). (+19 more) +Cohesion: 0.05 +Nodes (42): Tests covering query.py lines 77-132., Tests covering query.py lines 77-132., Tests covering query.py lines 77-132., Tests covering query.py lines 77-132., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., No historical data columns -> inner 400 caught by outer except -> 500., Pass field name WITHOUT year (how categorizeColumns returns them). (+34 more) ### Community 29 - "Community 29" Cohesion: 0.09 @@ -770,8 +770,8 @@ Cohesion: 0.07 Nodes (27): code:json ([), code:javascript (const loadHistory = async (sid) => {), code:jsx (export default function MessageList({ messages, toolEvents, ), code:javascript (const loadHistory = async (sid) => {), code:jsx (export default function AgentLoop({ toolEvents, turnMetrics ), code:bash (git add frontend/src/App.jsx frontend/src/components/Message), code:bash (docker-compose up -d --build), code:sql (SELECT COUNT(*) FROM prometheus WHERE JSON_CONTAINS_PATH(his) (+19 more) ### Community 39 - "Community 39" -Cohesion: 0.07 -Nodes (26): Two dates in the range, both valid., Two dates in the range, both valid., Two dates in the range, both valid., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., search.strip() == '' should still dedup (line 181)., Search with no index match falls back to string startswith., Two dates in the range, both valid. (+18 more) +Cohesion: 0.06 +Nodes (31): Invalid date -> inner 400 passes through (not wrapped as 500)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500. (+23 more) ### Community 40 - "Community 40" Cohesion: 0.12 @@ -799,7 +799,7 @@ Nodes (5): Tests for main/utils/roles.py — covers requirePermission and edge c ### Community 46 - "Community 46" Cohesion: 0.09 -Nodes (20): Regression: queryFundamental must not mutate the shared cache TIME column., Regression: queryFundamental must not mutate the shared cache TIME column., Regression: queryFundamental must not mutate the shared cache TIME column., Single invalid date -> inner 400 passes through., Single invalid date -> inner 400 caught by outer except -> 500., Single invalid date -> inner 400 caught by outer except -> 500., Single invalid date -> inner 400 caught by outer except -> 500., Invalid fields now raise 400 with actionable error message. (+12 more) +Nodes (21): Regression: queryFundamental must not mutate the shared cache TIME column., Regression: queryFundamental must not mutate the shared cache TIME column., Regression: queryFundamental must not mutate the shared cache TIME column., Single invalid date -> inner 400 passes through., Single invalid date -> inner 400 caught by outer except -> 500., Single invalid date -> inner 400 caught by outer except -> 500., Single invalid date -> inner 400 caught by outer except -> 500., Invalid fields now raise 400 with actionable error message. (+13 more) ### Community 47 - "Community 47" Cohesion: 0.1 @@ -810,8 +810,8 @@ Cohesion: 0.06 Nodes (34): Backend (COMMIT), code:bash (cd frontend && pnpm add @openuidev/react-lang), code:bash (rm frontend/src/components/MdocMessage.jsx), code:python ("""OpenUI Lang system prompt section for Prometheus agent.), code:block12, code:block13, code:block14, code:block15 (+26 more) ### Community 49 - "Community 49" -Cohesion: 0.07 -Nodes (21): dispatchToolCall(), TDD tests: verify memory tools are wired into the Prometheus agent. RED: Thes, TOOL_REGISTRY pattern must work correctly., test_memory_tool_skipped_without_user(), test_non_memory_tool_not_routed_to_executeMemoryTool(), test_non_registry_tool_not_routed(), test_save_memory_routed_to_executeMemoryTool(), test_save_memory_routed_via_registry() (+13 more) +Cohesion: 0.13 +Nodes (18): dispatchToolCall(), TDD tests: verify memory tools are wired into the Prometheus agent. RED: Thes, test_memory_tool_skipped_without_user(), test_non_memory_tool_not_routed_to_executeMemoryTool(), test_non_registry_tool_not_routed(), test_save_memory_routed_to_executeMemoryTool(), test_save_memory_routed_via_registry(), test_search_memory_routed_to_executeMemoryTool() (+10 more) ### Community 50 - "Community 50" Cohesion: 0.07 @@ -826,12 +826,12 @@ Cohesion: 0.08 Nodes (7): Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., TestPrometheusChatManager ### Community 53 - "Community 53" -Cohesion: 0.11 -Nodes (30): applyUpdate(), archiveDead(), clearAll(), clearAllAsync(), count_memories(), countMemories(), countTokensCached(), decayScores() (+22 more) +Cohesion: 0.1 +Nodes (39): applyUpdate(), archiveDead(), clearAll(), clearAllAsync(), count_memories(), countMemories(), countTokensCached(), decayScores() (+31 more) ### Community 54 - "Community 54" -Cohesion: 0.06 -Nodes (26): create_memories(), Zero access but score still above threshold → not archived., Even with low score, if accessed → not archived., Even with low score, if accessed → not archived., Already archived memories are skipped., Already archived memories are skipped., Decay happens first, then archive check with new scores., Decay happens first, then archive check with new scores. (+18 more) +Cohesion: 0.11 +Nodes (14): generateKey(), JSONBytesResponse, listFields(), Sends pre-serialized JSON bytes without re-encoding (cache-friendly)., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental. (+6 more) ### Community 55 - "Community 55" Cohesion: 0.11 @@ -862,8 +862,8 @@ Cohesion: 0.1 Nodes (20): architectures, attention_probs_dropout_prob, gradient_checkpointing, hidden_act, hidden_dropout_prob, hidden_size, initializer_range, intermediate_size (+12 more) ### Community 63 - "Community 63" -Cohesion: 0.19 -Nodes (9): _filterCotationByDate(), filterCotationData(), _parseCotationDate(), Shared query pipeline for historical and fundamental endpoints., Fetch live prices for B3 tickers via yfinance. B3 tickers must match, Parse DD-MM-YYYY from COTACAO 10Y JSON DATA field. ponytail: stdlib datetime onl, Filter COTACAO 10Y JSON entries by their inner DATA field (DD-MM-YYYY)., sanitizeNanValues() (+1 more) +Cohesion: 0.26 +Nodes (4): Shared query pipeline for historical and fundamental endpoints., Fetch live prices for B3 tickers via yfinance. B3 tickers must match, sanitizeNanValues(), StocksQueryManager ### Community 64 - "Community 64" Cohesion: 0.06 @@ -877,6 +877,10 @@ Nodes (19): API Endpoints, API Key Verification, Brazilian Stocks Market API, co Cohesion: 0.1 Nodes (19): 1. Explore Agent — Prometheus Architecture, 2. MySQL Vector Storage (Researcher), 3. Memory Patterns (Researcher), A. Vector Embedding Integration, B. Pandas-First Vector Cache, C. Search Upgrade, code:python (class MemoryCache:), code:python (def searchMemories(cls, db, userId, query, embedding=None, l) (+11 more) +### Community 67 - "Community 67" +Cohesion: 0.21 +Nodes (7): ResultCache — SHA256-keyed file-based cache for computed results., File-based cache keyed by SHA256 of code. Stores results as JSON under:, Return cached result dict or None if miss., Store result with timestamp., Delete all cached results for a session., Check if a result exists for the given code., ResultCache + ### Community 68 - "Community 68" Cohesion: 0.13 Nodes (18): SessionManager, PrometheusChatManager, Cover getGoogleSSO (lines 6-14)., Cover getGoogleSSO (lines 6-14)., Cover __init__ and updateDates., Cover __init__ and updateDates (lines 22-37)., Cover streamMessage in agent.py., Cover sendMessage and streamMessage in agent.py. (+10 more) @@ -894,8 +898,8 @@ Cohesion: 0.11 Nodes (19): API Key System, B3 Scraper, Fundamental Data, Gemini Model, Historical Data, Ma'at Stock Algorithm, Mansa Server, MySQL Database (+11 more) ### Community 72 - "Community 72" -Cohesion: 0.14 -Nodes (3): getCurrentSelic(), getInitialData(), calculateInvestingScore() +Cohesion: 0.1 +Nodes (9): B3Scraper, getCurrentSelic(), getInitialData(), calculateInvestingScore(), initialize(), P5: register the scraper cron jobs on the shared scheduler. Kept in this, registerScraperJobs(), runScraper() (+1 more) ### Community 73 - "Community 73" Cohesion: 0.16 @@ -926,15 +930,15 @@ Cohesion: 0.05 Nodes (44): cn(), AlertDialogAction(), AlertDialogCancel(), AlertDialogContent(), AlertDialogDescription(), AlertDialogFooter(), AlertDialogHeader(), AlertDialogMedia() (+36 more) ### Community 80 - "Community 80" -Cohesion: 0.15 +Cohesion: 0.16 Nodes (18): buildSummary(), charCount(), countTokens(), dedup(), extractDecisions(), extractMetrics(), extractSnapshots(), extractTickers() (+10 more) ### Community 81 - "Community 81" -Cohesion: 0.17 -Nodes (12): getLiveCotation(), Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th (+4 more) +Cohesion: 0.15 +Nodes (13): getLiveCotation(), Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th (+5 more) ### Community 82 - "Community 82" -Cohesion: 0.16 +Cohesion: 0.15 Nodes (14): arrowTypeFor(), buildCotationDateIndex(), buildFeatherCache(), buildTickerIndex(), optimizeDtypes(), P1: establish the sorted-cache invariant once at load/refresh. Sorts by (, P1: first-occurrence index over a sortCacheFrame-sorted frame. The cache, Get cached stocks data with optional column filtering. (+6 more) ### Community 83 - "Community 83" @@ -950,8 +954,8 @@ Cohesion: 0.21 Nodes (16): AddDividendDialog(), fmtBRL(), AddLotDialog(), HoldingSearchBox(), matchHoldings(), assertDividendTotal(), assertNotFuture(), assertTicker() (+8 more) ### Community 86 - "Community 86" -Cohesion: 0.17 -Nodes (4): POST /memories rejects missing key., POST /memories rejects missing value., Full integration tests using mocked MemoryManager., TestMemoryEndpointsIntegration +Cohesion: 0.08 +Nodes (11): Verify memory endpoints exist and are wired correctly., GET /prometheus/memories exists., POST /memories rejects missing key., POST /memories rejects missing value., POST /prometheus/memories exists., DELETE /prometheus/memories/{id} exists., GET /memories requires authentication., GET /memories requires USE_PROMETHEUS (basic USER role denied). (+3 more) ### Community 87 - "Community 87" Cohesion: 0.1 @@ -966,8 +970,8 @@ Cohesion: 0.08 Nodes (23): code:python (import asyncio), code:jsx (import { describe, it, expect, vi, beforeEach } from 'vitest), code:javascript (const RESUME_KEY = 'mansa_resume';), code:javascript (let accumulated = '';), code:javascript (const maybeResume = useCallback(async () => {), code:javascript (useEffect(() => {), code:bash (git add frontend/src/App.jsx frontend/src/App.resume.test.js), code:bash (git add TODO.md) (+15 more) ### Community 90 - "Community 90" -Cohesion: 0.14 -Nodes (11): Integration tests for the verifyAPIKey function., Test successful API key verification., Integration tests for the verifyAPIKey function., Test API key verification when quota is exceeded., Test API key verification with invalid key., Test API key verification with missing key., Test API key verification with invalid key., Test that API key system can be disabled. (+3 more) +Cohesion: 0.18 +Nodes (11): Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback. (+3 more) ### Community 91 - "Community 91" Cohesion: 0.12 @@ -1002,28 +1006,28 @@ Cohesion: 0.28 Nodes (6): extractTokenPayload(), Tests for extractTokenPayload — the standalone token extraction dependency., Create a mock Starlette Request with given headers., Authorization: Bearer (empty) — no token after Bearer., Authorization: Basic xxx — not Bearer, so no token found., TestExtractTokenPayload ### Community 99 - "Community 99" -Cohesion: 0.05 -Nodes (33): _make_prometheus_client(), Covers lines 111-112: sessionId is None, new session created., Covers lines 111-112: sessionId is None, new session created., Covers lines 118-119: sessionId is None, new session created., Covers lines 111-112: sessionId is None, new session created., Return (client, app) with prometheus router and mocked deps., Covers lines 33-36: GET /prometheus/sessions., Covers lines 33-36: GET /prometheus/sessions. (+25 more) +Cohesion: 0.1 +Nodes (17): Covers lines 62-63, 65-68: PUT /prometheus/sessions/{sessionId}., Covers lines 62-63, 65-68: PUT /prometheus/sessions/{sessionId}., Covers lines 65-68: title updated successfully., Covers lines 65-68: title updated successfully., Covers lines 62-63, 65-68: PUT /prometheus/sessions/{sessionId}., Covers lines 65-68: title updated successfully., Covers lines 62-63: not the session owner., Covers lines 62-63: not the session owner. (+9 more) ### Community 100 - "Community 100" -Cohesion: 0.09 -Nodes (12): _assert_gemini_safe(), Every function in TOOL_REGISTRY must have Gemini-safe signatures. Custom cl, Every function in TOOL_REGISTRY must have Gemini-safe signatures. Custom cl, Regression: HarnessState must never leak into tool signatures., Regression: HarnessState must never leak into tool signatures., Assert a tool function has only Gemini-compatible parameter types., Assert a tool function has only Gemini-compatible parameter types., test_get_state_no_state_returns_error() (+4 more) +Cohesion: 0.12 +Nodes (8): _assert_gemini_safe(), Assert a tool function has only Gemini-compatible parameter types., Assert a tool function has only Gemini-compatible parameter types., test_get_state_no_state_returns_error(), test_set_state_no_state_returns_error(), test_tool_has_gemini_safe_signature(), TestStateToolFunctions, TestToolRegistry ### Community 101 - "Community 101" -Cohesion: 0.15 -Nodes (15): execute_code(), Store a value in the harness state for this session. Use this to save inter, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Read a file from the workspace. Args: path: Path to the file (e., Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis, (+7 more) +Cohesion: 0.2 +Nodes (12): execute_code(), Store a value in the harness state for this session. Use this to save inter, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Store a value in the harness state for this session. Use this to save inter (+4 more) ### Community 102 - "Community 102" -Cohesion: 0.14 -Nodes (8): BaseSettings, BaseMansaSettings, DiscordSettings, MysqlSettings, ScraperSettings, StocksApiSettings, UserSettings, TestConfig +Cohesion: 0.12 +Nodes (11): BaseSettings, BaseMansaSettings, Config, DiscordSettings, MysqlSettings, PrometheusSettings, ScraperSettings, StocksApiSettings (+3 more) ### Community 103 - "Community 103" Cohesion: 0.13 Nodes (14): 10. Performance, 11. Testing, 12. Risks, 13. Out of Scope (YAGNI), 14. Open Questions, 1. Executive Summary, 2. Context & Motivation, 5. Architecture Decision (+6 more) ### Community 104 - "Community 104" -Cohesion: 0.1 -Nodes (17): Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126, 131, 135-136., Covers lines 126, 131, 135-136., Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126, 131, 135-136., Covers lines 127-129: session not found., Covers lines 127-129: session not found. (+9 more) +Cohesion: 0.07 +Nodes (26): Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 120-121: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126, 131, 135-136. (+18 more) ### Community 106 - "Community 106" Cohesion: 0.22 @@ -1042,24 +1046,24 @@ Cohesion: 0.14 Nodes (13): cls_token, do_basic_tokenize, do_lower_case, mask_token, model_max_length, name_or_path, never_split, pad_token (+5 more) ### Community 110 - "Community 110" -Cohesion: 0.24 -Nodes (5): lifespan(), status(), checkDatabaseConnection(), checkSingleDb(), runMigrations() +Cohesion: 0.15 +Nodes (12): initialize(), P5: register memory maintenance on the shared scheduler. Kept in this ser, registerMemoryMaintenanceJob(), initialize(), P5: register the session-cleanup job on the shared scheduler. Kept in thi, registerSessionCleanupJobs(), UserService, getSharedScheduler() (+4 more) ### Community 111 - "Community 111" Cohesion: 0.14 Nodes (13): code:python (import pytest), code:python (import logging), code:bash (git add main/app/prometheus/state.py tests/test_harness_stat), File Map, Global Constraints, Phase 1: HarnessState (In-Memory Agent Scratchpad), Prometheus Harness — Master Implementation Plan (v2: CubeSandbox + On-Demand), Relationship to Existing Systems (+5 more) ### Community 112 - "Community 112" -Cohesion: 0.13 -Nodes (12): GET /stocks/realtime-cotation without search returns 422., GET /cotations without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422., GET /stocks/realtime-cotation without search returns 422. (+4 more) +Cohesion: 0.2 +Nodes (14): Store a value in state. Marks state as changed for context injection., compactCotations(), compactRow(), compactValue(), compressResponse(), fixHeaders(), getAbbr(), getNest() (+6 more) ### Community 113 - "Community 113" Cohesion: 0.15 Nodes (7): write_file returns False when host write fails (e.g. invalid path chars)., read_file reads from host filesystem., write_file writes to host filesystem., list_files lists host filesystem entries., list_files returns empty for missing directory., read_file raises FileNotFoundError for missing file., TestSandboxManager ### Community 114 - "Community 114" -Cohesion: 0.29 -Nodes (6): Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok, Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: HTTPException raised by verifyAccessToken is re-raised. +Cohesion: 0.17 +Nodes (12): Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok, Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok, Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok, Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok, Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: HTTPException raised by verifyAccessToken is re-raised., Covers line 67: extractTokenPayload re-raises HTTPException from verifyAccessTok (+4 more) ### Community 115 - "Community 115" Cohesion: 0.17 @@ -1067,7 +1071,7 @@ Nodes (11): dateOnly(), EditDividendDialog(), EditLotDialog(), fmtBRL(), fmtMone ### Community 116 - "Community 116" Cohesion: 0.14 -Nodes (15): _build_system_prompt(), buildSystemPrompt(), chatSession(), _execute_memory_tool(), executeMemoryTool(), _get_client(), _get_memory_tools(), getClient() (+7 more) +Nodes (16): _build_system_prompt(), buildSystemPrompt(), chatSession(), _execute_memory_tool(), executeMemoryTool(), _get_client(), _get_memory_tools(), getClient() (+8 more) ### Community 117 - "Community 117" Cohesion: 0.15 @@ -1083,7 +1087,7 @@ Nodes (26): code:python ("""Tests for SandboxManager file mutation helpers (dele ### Community 120 - "Community 120" Cohesion: 0.12 -Nodes (27): _make_auth_client(), Tests to cover uncovered lines across controllers, UserManager, and auth util., Return (client, app) with auth + user routers and mocked getSession., test_callback_existing_user(), test_callback_generic_exception(), test_callback_new_user(), test_callback_no_user_info(), test_callback_with_state_redirect() (+19 more) +Nodes (26): _make_auth_client(), Tests to cover uncovered lines across controllers, UserManager, and auth util., Return (client, app) with auth + user routers and mocked getSession., Covers lines 107, 109-130, 133: logout token extraction and revocation., Covers lines 111-113: token extracted from Authorization Bearer header., test_callback_existing_user(), test_callback_generic_exception(), test_callback_new_user() (+18 more) ### Community 121 - "Community 121" Cohesion: 0.21 @@ -1091,7 +1095,7 @@ Nodes (12): code:python (import inspect), code:python (from main.app.prometheus. ### Community 122 - "Community 122" Cohesion: 0.15 -Nodes (11): test_setup_discord_handler_disabled(), test_setup_discord_handler_enabled(), TestSetupLogging, Many concurrent emit() calls must not create more threads than max_workers., Verify that DiscordHandler submits to a bounded executor, not raw threads., The module-level discordExecutor must exist with max_workers <= 5., DiscordHandler.emit() must use discordExecutor.submit, not Thread.start., TestDiscordHandlerThreadPool (+3 more) +Nodes (10): test_setup_discord_handler_disabled(), test_setup_discord_handler_enabled(), Many concurrent emit() calls must not create more threads than max_workers., Verify that DiscordHandler submits to a bounded executor, not raw threads., The module-level discordExecutor must exist with max_workers <= 5., DiscordHandler.emit() must use discordExecutor.submit, not Thread.start., TestDiscordHandlerThreadPool, DiscordHandler (+2 more) ### Community 123 - "Community 123" Cohesion: 0.17 @@ -1106,8 +1110,8 @@ Cohesion: 0.13 Nodes (3): PrometheusSession, createSession(), TestPrometheusSessionModel ### Community 126 - "Community 126" -Cohesion: 0.15 -Nodes (11): _count_memories(), _create_memory(), _get_memory(), Keys with Jaccard > 0.8 should merge., Keys with Jaccard > 0.8 should merge., Keys with low similarity should not merge., Keys with low similarity should not merge., Keys with low similarity should not merge. (+3 more) +Cohesion: 0.33 +Nodes (5): Non-JSON-dict/list string is left as-is., Non-JSON-dict/list string is left as-is., Non-JSON-dict/list string is left as-is., Non-JSON-dict/list string is left as-is., Non-JSON-dict/list string is left as-is. ### Community 127 - "Community 127" Cohesion: 0.2 @@ -1122,11 +1126,11 @@ Cohesion: 0.2 Nodes (10): Tests for stocks API field validation — verifies the fields parameter accepts a, Integration: /stocks/fundamental must accept slash and dot fields., Minimal TestClient with just the stocks router for validation tests., GET /fundamental?fields=P/L must not return 422 (validation error)., GET /fundamental?fields=P/L must not return 422 (validation error)., Integration: /stocks/fundamental must accept slash and dot fields., GET /fundamental?fields=P/L must not return 422 (validation error)., GET /historical?fields=P/L must not return 422. (+2 more) ### Community 130 - "Community 130" -Cohesion: 0.17 -Nodes (7): Verify memory endpoints exist and are wired correctly., GET /prometheus/memories exists., POST /prometheus/memories exists., DELETE /prometheus/memories/{id} exists., GET /memories requires authentication., GET /memories requires USE_PROMETHEUS (basic USER role denied)., TestMemoryControllerRoutes +Cohesion: 0.33 +Nodes (5): Performance tests for query operations, Query should respond within 1 second, Performance tests for query operations, Query should respond within 1 second, TestQueryPerformance ### Community 131 - "Community 131" -Cohesion: 0.11 +Cohesion: 0.1 Nodes (17): Same input → same hash., Different inputs → different hashes., Returns 32-char hex string., pack → unpack preserves values., Empty list roundtrips., 384-dim vector packs to 1536 bytes., TestContentHash, TestPackUnpack (+9 more) ### Community 132 - "Community 132" @@ -1146,12 +1150,12 @@ Cohesion: 0.11 Nodes (4): cache(), Tests for ResultCache., TestColumnValidator, TestResultCache ### Community 136 - "Community 136" -Cohesion: 0.2 -Nodes (9): Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132). (+1 more) +Cohesion: 0.14 +Nodes (11): Integration tests for the verifyAPIKey function., Test successful API key verification., Integration tests for the verifyAPIKey function., Test API key verification when quota is exceeded., Test API key verification with invalid key., Test API key verification with missing key., Test API key verification with invalid key., Test that API key system can be disabled. (+3 more) ### Community 137 - "Community 137" -Cohesion: 0.2 -Nodes (9): Invalid date -> inner 400 passes through (not wrapped as 500)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Two dates in the range, both valid. (+1 more) +Cohesion: 0.14 +Nodes (14): _count_memories(), _create_memory(), _get_memory(), Keys with Jaccard > 0.8 should merge., Keys with Jaccard > 0.8 should merge., Keys with low similarity should not merge., Keys with low similarity should not merge., Keys with low similarity should not merge. (+6 more) ### Community 138 - "Community 138" Cohesion: 0.18 @@ -1162,8 +1166,8 @@ Cohesion: 0.24 Nodes (6): Dataset, produce_data(), Train script for a single file Need to set the TPU address first: export XRT_TP, A class that handles the reddit data files, A class that handles one dataset, RedditDataset ### Community 140 - "Community 140" -Cohesion: 0.11 -Nodes (28): Base, PrometheusMemory, PrometheusMemory, MemoryManager, PrometheusMemory, All memory operations. Stateless class methods., PrometheusService, TestDifferentKeysNoMerge (+20 more) +Cohesion: 0.08 +Nodes (32): Base, PrometheusMemory, PrometheusMemory, MemoryManager, PrometheusMemory, All memory operations. Stateless class methods., PrometheusService, TestDifferentKeysNoMerge (+24 more) ### Community 141 - "Community 141" Cohesion: 0.24 @@ -1202,8 +1206,8 @@ Cohesion: 0.2 Nodes (3): MEMORY_TOOLS must be defined as a Tool wrapping FunctionDeclarations., MEMORY_TOOLS must be a list of callables with proper signatures., TestMemoryToolsDefinition ### Community 152 - "Community 152" -Cohesion: 0.09 -Nodes (23): _getDb(), Search user's saved memories, preferences, and past analysis context. Use t, Search user's saved memories, preferences, and past analysis context. Use t, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use (+15 more) +Cohesion: 0.18 +Nodes (12): _getDb(), Search user's saved memories, preferences, and past analysis context. Use t, Search user's saved memories, preferences, and past analysis context. Use t, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use (+4 more) ### Community 153 - "Community 153" Cohesion: 0.12 @@ -1239,11 +1243,11 @@ Nodes (17): §2 Service/Business Separation — MVC 4/10 (Historical layering sc ### Community 161 - "Community 161" Cohesion: 0.11 -Nodes (18): Category 2: Async/Sync Inconsistencies (MEDIUM), Category 4: Caching & Memory (MEDIUM), Category 6: Configuration & Environment (LOW), Category 8: Testing Gaps (MEDIUM), Executive Summary, Full Code Review Report, Issue 2.1 — All route handlers are synchronous, Issue 2.2 — ServiceManager runs uvicorn in daemon threads (+10 more) +Nodes (18): Category 2: Async/Sync Inconsistencies (MEDIUM), Category 4: Caching & Memory (MEDIUM), Category 6: Configuration & Environment (LOW), Category 7: Code Quality (LOW), Executive Summary, Full Code Review Report, Issue 2.1 — All route handlers are synchronous, Issue 2.2 — ServiceManager runs uvicorn in daemon threads (+10 more) ### Community 162 - "Community 162" -Cohesion: 0.21 -Nodes (7): ResultCache — SHA256-keyed file-based cache for computed results., File-based cache keyed by SHA256 of code. Stores results as JSON under:, Return cached result dict or None if miss., Store result with timestamp., Delete all cached results for a session., Check if a result exists for the given code., ResultCache +Cohesion: 0.2 +Nodes (10): list_files(), List files in the workspace directory. Args: path: Directory pat, Read a file from the sandbox filesystem. Args: path: Absolute pa, List files in the workspace directory. Args: path: Directory pat, List files in the workspace directory. Args: path: Directory pat, List files in the workspace directory. Args: path: Directory pat, List files in the workspace directory. Args: path: Directory pat, List files in the workspace directory. Args: path: Directory pat (+2 more) ### Community 163 - "Community 163" Cohesion: 0.22 @@ -1270,8 +1274,8 @@ Cohesion: 0.4 Nodes (4): compilerOptions, baseUrl, paths, @/* ### Community 169 - "Community 169" -Cohesion: 0.1 -Nodes (15): generateKey(), getCotations(), JSONBytesResponse, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur (+7 more) +Cohesion: 0.18 +Nodes (11): getCotations(), Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur, Get 10-year daily price history (cotation) for Brazilian B3 stocks. Retur (+3 more) ### Community 170 - "Community 170" Cohesion: 0.25 @@ -1310,16 +1314,16 @@ Cohesion: 0.29 Nodes (7): Integration: /stocks/fundamental date filter should work per-ticker., Integration: /stocks/fundamental date filter should work per-ticker., When tickers have different date coverage, each should get its closest snapshot., When tickers have different date coverage, each should get its closest snapshot., Integration: /stocks/fundamental date filter should work per-ticker., When tickers have different date coverage, each should get its closest snapshot., TestFundamentalDateFiltering ### Community 181 - "Community 181" -Cohesion: 0.57 -Nodes (6): addRole(), addRoleToUser(), getCurrentUser(), getRolesList(), hasRole(), toDict() +Cohesion: 0.12 +Nodes (15): code:python ("""add embedding vector column."""), code:python ("""One-shot: embed rows with NULL embedding. Delete after ru), code:bash (git add migrations/versions/xxxx_add_embedding_vector.py), code:python (def searchpgvector(db: Session, userId: int, query: str, lim), code:bash (git add main/app/prometheus/memory.py main/app/prometheus/ve), code:python (def test_knn_result_shape(dbSession):), code:bash (git add tests/), code:bash (git rm scripts/backfill_embedding_vector.py) (+7 more) ### Community 182 - "Community 182" Cohesion: 0.25 Nodes (7): code:block1 (main/), Execution Handoff, Executive Summary: What Mem0 Does That We Don't, File Structure, Mem0 vs Prometheus Memory System — Comparison & Upgrade Plan, Self-Review Checklist, What We Already Do Well (Don't Replace) ### Community 183 - "Community 183" -Cohesion: 0.17 -Nodes (7): Different query parameters should not share cache, Cache should expire after TTL, Tests for query result caching, CacheManager should track cached queries, Query cache should have configurable TTL, getCachedStocks should support column filtering, TestQueryCaching +Cohesion: 0.07 +Nodes (17): Different query parameters should not share cache, Cache should expire after TTL, Tests for connection pool configuration, Stocks engine should have optimized pool settings, Tests for lazy JSON deserialization, Query manager should have deserialize method, Integration tests for all query optimizations, All optimizations should be implemented (+9 more) ### Community 184 - "Community 184" Cohesion: 0.11 @@ -1330,16 +1334,16 @@ Cohesion: 0.38 Nodes (7): code:python (import pytest), code:python (from __future__ import annotations), code:bash (git add main/app/prometheus/context.py tests/test_context.py), Phase 4: ToolContext (Bundled Dispatch Dependencies), Phase 4: ToolContext (Replace God Function), Task 5: ToolContext — Dataclass for Agent Use, Task 5: ToolContext — Single Dispatch Object ### Community 186 - "Community 186" -Cohesion: 0.22 -Nodes (7): Integration tests for all query optimizations, Integration tests for all query optimizations, All optimizations should be implemented, All optimizations should be implemented, Query filter should use ticker index, Query filter should use ticker index, TestQueryOptimization +Cohesion: 0.12 +Nodes (11): Thread-safe proxy that delegates to per-thread sessions., SessionProxy, Verify that getSession() returns per-thread Session instances., Calling getSession() twice in the same thread returns the same object., Two threads must NOT share a Session object., With 20 concurrent threads, every thread must get its own Session., The returned object must be a real requests.Session., TestGetSession (+3 more) ### Community 187 - "Community 187" Cohesion: 0.29 Nodes (6): DEVELOPER:, PREMIUM:, Prometheus, STOCKS_API, USER:, User structure defined by string roles: ### Community 188 - "Community 188" -Cohesion: 0.38 -Nodes (9): Tests for main/utils/logging_config.py — covers DiscordHandler branches., test_discord_disabled(), test_discord_no_webhook(), test_exception_in_submit(), test_level_below_error(), test_message_truncation(), test_submit_called_on_error(), test_with_exception_info() (+1 more) +Cohesion: 0.33 +Nodes (10): Tests for main/utils/logging_config.py — covers DiscordHandler branches., test_discord_disabled(), test_discord_no_webhook(), test_exception_in_submit(), test_level_below_error(), test_message_truncation(), test_submit_called_on_error(), test_with_exception_info() (+2 more) ### Community 189 - "Community 189" Cohesion: 0.36 @@ -1362,8 +1366,8 @@ Cohesion: 0.33 Nodes (6): normalizer, clean_text, handle_chinese_chars, lowercase, strip_accents, type ### Community 194 - "Community 194" -Cohesion: 0.26 -Nodes (5): buildClient(), ensureFastmcp(), MCPClientPool, _parseServers(), Config +Cohesion: 0.29 +Nodes (5): buildClient(), connect(), ensureFastmcp(), MCPClientPool, _parseServers() ### Community 195 - "Community 195" Cohesion: 0.33 @@ -1442,8 +1446,8 @@ Cohesion: 0.17 Nodes (11): code:python (def test_search_defersEmbeddingBlob(db):), code:python (from contextlib import contextmanager), code:python (from sqlalchemy.orm import defer), code:bash (git add main/app/prometheus/memory.py tests/test_memory_sear), code:python (def test_search_fusesFulltextOverVectorOnly(db):), code:python (def minMax(values: list[float]) -> list[float]:), code:bash (git add main/app/prometheus/memory.py tests/test_memory_sear), Global Constraints (+3 more) ### Community 215 - "Community 215" -Cohesion: 0.31 -Nodes (3): Pytest Testing, PrometheusSettings, TestSandboxConfig +Cohesion: 0.19 +Nodes (8): AuthenticationService, initialize(), initialize(), MCPDetectMiddleware, StocksAPIService, getApp(), runAll(), ServiceManager ### Community 216 - "Community 216" Cohesion: 0.29 @@ -1469,10 +1473,6 @@ Nodes (5): model, continuing_subword_prefix, max_input_chars_per_word, type, unk Cohesion: 0.2 Nodes (9): Covers lines 143, 145, 147-148: POST /user/sessions/revoke-all., Covers lines 143, 145, 147-148: POST /user/sessions/revoke-all., Covers lines 143, 145, 147-148., Covers lines 143, 145, 147-148., Covers lines 143, 145, 147-148: POST /user/sessions/revoke-all., Covers lines 143, 145, 147-148., Covers lines 143, 145, 147-148: POST /user/sessions/revoke-all., Covers lines 143, 145, 147-148. (+1 more) -### Community 222 - "Community 222" -Cohesion: 0.19 -Nodes (8): AuthenticationService, initialize(), initialize(), MCPDetectMiddleware, StocksAPIService, getApp(), runAll(), ServiceManager - ### Community 223 - "Community 223" Cohesion: 0.4 Nodes (5): code:python (from main.app.prometheus.tools import SANDBOX_TOOLS, SANDBOX), code:python (from main.app.prometheus.sandbox import SandboxManager), code:python (async def dispatchToolCall(functionCall, mcpClients, user=No), code:bash (git add main/app/prometheus/tools.py tests/test_sandbox.py), Task 5: Sandbox Tools — Gemini Function Declarations + Dispatch @@ -1505,6 +1505,10 @@ Nodes (5): code:python (import pytest), code:python (import hashlib), code:bash Cohesion: 0.18 Nodes (11): 2.2.1 Complexity hotspots table (H1–H17 condensed to P0/P1/P2), 2.2.2 Blob inventory (LOC table + SRP evidence), 2.2.3 Mass data loads, 2.2.4 Phased fix roadmap (P0/P1/P2), §2.2 CODE EFFICIENCY — O(n²), Complexity & Blob Anti-Patterns, code:block4 (scraper.py:44 671 LOC — mass loads: SELECT * fetchma), code:powershell (ruff check . && ruff format --check .), code:powershell (pytest tests/test_stocks_cache_concurrency.py -v # ThreadPo) (+3 more) +### Community 231 - "Community 231" +Cohesion: 0.13 +Nodes (13): Covers lines 95-98: session deleted., Covers lines 96-97: session not found., Covers lines 96-97: session not found., Covers lines 96-97: session not found., Covers lines 95-98: DELETE /prometheus/sessions/{sessionId}., Covers lines 95-98: session deleted., Covers lines 96-97: session not found., Covers lines 95-98: DELETE /prometheus/sessions/{sessionId}. (+5 more) + ### Community 232 - "Community 232" Cohesion: 0.4 Nodes (5): Bucket A: Security Fixes (quick wins, 30 min), Bucket B: DB Session Cleanup (medium, 1-2 hrs), Bucket C: Testing (medium, 2-3 hrs), Bucket D: Infrastructure (large, 4+ hrs), Recommended Delegation Buckets @@ -1514,8 +1518,8 @@ Cohesion: 0.4 Nodes (5): 8. Build Sequence (4 phases, each independently shippable), Phase 0 — Sandbox foundation (1-2 days, no user-facing change), Phase 1 — MCP exposure of STOCKS_API (1 day), Phase 2 — Refactor PROMETHEUS to agentic (3-5 days, the big one), Phase 3 — Hardening (1-2 days, can ship incrementally) ### Community 234 - "Community 234" -Cohesion: 0.32 -Nodes (4): memoryMaintenance(), _create(), After 10 cycles, preference (0.99^10) > context (0.90^10)., TestTypeAwareDecay +Cohesion: 0.14 +Nodes (11): memoryMaintenance(), Decay happens first, then archive check with new scores., Decay happens first, then archive check with new scores., Score that decays to >= threshold stays alive. 0.11 * 0.95 = 0.1045 >= 0.1., Score that decays to >= threshold stays alive. 0.12 * 0.90 = 0.108 >= 0.1., 89 days with low score → not archived (need > 90)., 89 days with low score → not archived (need > 90)., TestDecayAndArchiveTogether (+3 more) ### Community 236 - "Community 236" Cohesion: 0.5 @@ -1561,6 +1565,10 @@ Nodes (4): code:tsx (import React from "react";), code:tsx (import { SandboxArti Cohesion: 0.5 Nodes (4): Category 5: Error Handling Gaps (MEDIUM), Issue 5.1 — Generic exception handler swallows traceback in production, Issue 5.2 — DiscordHandler sends only message, not traceback, Issue 5.3 — `_build_error_response` ignores `status_code` parameter +### Community 251 - "Community 251" +Cohesion: 0.09 +Nodes (17): client(), pytest_configure(), TestClient with all routers mounted — no lifespan (no DB/service init). O, Set required env vars before test collection. config.py eagerly instantia, Reset slowapi in-memory rate limiter between every test., Set required env vars before test collection. config.py eagerly instantia, TestClient with all routers mounted — no lifespan (no DB/service init). O, TestClient with all routers mounted — no lifespan (no DB/service init). O (+9 more) + ### Community 252 - "Community 252" Cohesion: 0.5 Nodes (3): Comma-separated list containing slash fields must pass., Comma-separated list containing slash fields must pass., Comma-separated list containing slash fields must pass. @@ -1598,12 +1606,12 @@ Cohesion: 0.5 Nodes (4): code:python (def test_link_memory_to_entities(db_session, sample_user):), code:python (# Add to main/app/prometheus/memory.py), code:bash (git add main/app/prometheus/memory.py tests/test_memory_grap), Task 5: Graph Memory Operations ### Community 263 - "Community 263" -Cohesion: 0.25 -Nodes (7): No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., Multiple search terms, all found in tickerIndex. +Cohesion: 0.22 +Nodes (8): 1. Prime owns the goal, lanes own the work, 2. Dispatch: `delegate()`, one per lane, one turn, 3. Delegate toolsets vary — verify each lane, 4. Trust nothing — verify everything, 5. Windows PowerShell survival, 6. Finish per lane, not per swarm, 7. Standing bans (this repo), SWARMS.md — subagent swarm playbook (OpenCode / Hermes) ### Community 474 - "Community 474" -Cohesion: 0.13 -Nodes (13): Covers lines 95-98: session deleted., Covers lines 96-97: session not found., Covers lines 96-97: session not found., Covers lines 96-97: session not found., Covers lines 95-98: DELETE /prometheus/sessions/{sessionId}., Covers lines 95-98: session deleted., Covers lines 96-97: session not found., Covers lines 95-98: DELETE /prometheus/sessions/{sessionId}. (+5 more) +Cohesion: 0.22 +Nodes (4): authenticateUser(), createUserAccount(), FastAPI, PaginationParams ### Community 476 - "Community 476" Cohesion: 0.22 @@ -1645,25 +1653,21 @@ Nodes (4): Priority 1: Fix Critical Gaps, Priority 2: Improve Retrieval, Priorit Cohesion: 0.23 Nodes (6): CHART_COLORS, PortfolioBarsCard(), PortfolioPieCard(), tooltipStyle, groupHistoryByMonth(), monthKey() -### Community 487 - "Community 487" -Cohesion: 0.15 -Nodes (12): dispatchToolCall must route memory tool names via TOOL_REGISTRY., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., dispatchToolCall must route memory tool names to executeMemoryTool., makeChat must include MEMORY_TOOLS alongside MCP sessions., dispatchToolCall must route memory tool names to executeMemoryTool. (+4 more) - ### Community 488 - "Community 488" -Cohesion: 0.33 -Nodes (4): initialize(), P5: register the session-cleanup job on the shared scheduler. Kept in thi, registerSessionCleanupJobs(), UserService +Cohesion: 0.12 +Nodes (10): Regression: is_string_dtype fails when column has strings + None (pandas 2.x)., Tests covering query.py lines 50-67., Tests covering query.py lines 50-67., Regression: is_string_dtype fails when column has strings + None (pandas 2.x)., Regression: is_string_dtype fails when column has strings + None (pandas 2.x)., Regression: is_string_dtype fails when column has strings + None (pandas 2.x)., Tests covering query.py lines 50-67., Tests covering query.py lines 50-67. (+2 more) ### Community 489 - "Community 489" Cohesion: 0.6 Nodes (4): hammer_measured(), main(), Fire n requests with c concurrent workers, measuring ttfb + total per request., stats() ### Community 490 - "Community 490" -Cohesion: 0.1 -Nodes (13): Tests for connection pool configuration, Stocks engine should have optimized pool settings, Tests for lazy JSON deserialization, Query manager should have deserialize method, Tests for dynamic ticker index feature, Ticker index should be built when cache is loaded, Ticker index should contain all tickers from cache, Ticker index should be case-insensitive (+5 more) +Cohesion: 0.33 +Nodes (5): Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, TestFilterBySearchTerms ### Community 491 - "Community 491" -Cohesion: 0.47 -Nodes (3): TestCleanup, cleanup(), Close the main thread's session at interpreter shutdown. +Cohesion: 0.24 +Nodes (5): lifespan(), status(), checkDatabaseConnection(), checkSingleDb(), runMigrations() ### Community 492 - "Community 492" Cohesion: 0.33 @@ -1682,28 +1686,28 @@ Cohesion: 0.25 Nodes (7): code:python (from dataclasses import dataclass), code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py ), code:python (from datetime import date), File Structure, Global Constraints, Task 3: Pure derivation math, Wallet Management (Thoth/Iyagba) Implementation Plan ### Community 498 - "Community 498" -Cohesion: 0.05 -Nodes (52): AuthenticationManager, IntFlag, Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 28: GET /auth/health. (+44 more) +Cohesion: 0.06 +Nodes (36): AuthenticationManager, IntFlag, Covers line 28: GET /auth/health., Covers line 28: GET /auth/health., Covers line 13: UserManager.__init__., Covers line 13: UserManager.__init__., Covers line 13: UserManager.__init__., Covers line 13: UserManager.__init__. (+28 more) ### Community 499 - "Community 499" Cohesion: 0.2 Nodes (9): code:python (import numpy as np), code:python (def normalizeRows(matrix: np.ndarray) -> np.ndarray:), code:bash (git add main/app/prometheus/vector.py tests/test_vector_norm), code:python ("""One-shot: renormalize stored embeddings to unit norm. Usa), code:bash (git add scripts/backfill_normalize_embeddings.py), Global Constraints, Lane 1: Normalized Embeddings + Dot-Product Search Implementation Plan, Task 1: Normalize on encode + row-normalize helper (+1 more) ### Community 500 - "Community 500" -Cohesion: 0.24 -Nodes (8): initialize(), P5: register memory maintenance on the shared scheduler. Kept in this ser, registerMemoryMaintenanceJob(), getSharedScheduler(), P5: single shared BackgroundScheduler for all services. Replaces the 4 per-serv, Return the process-wide scheduler, starting it on first use., Register func on the shared scheduler (replaces any same-id job). trigger i, registerJob() +Cohesion: 0.25 +Nodes (8): Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Read a file from the sandbox filesystem. Args: path: Absolute pa, Read a file from the sandbox filesystem. Args: path: Absolute pa, Read a file from the workspace. Args: path: Path to the file (e., read_file() ### Community 501 - "Community 501" Cohesion: 0.22 Nodes (3): getCurrentSession(), getSessions(), sessionToDict() ### Community 502 - "Community 502" -Cohesion: 0.08 -Nodes (20): Tests for connection pool configuration, Tests for connection pool configuration, Stocks engine should have optimized pool settings, Stocks engine should have optimized pool settings, Tests for lazy JSON deserialization, Tests for lazy JSON deserialization, Query manager should have deserialize method, Query manager should have deserialize method (+12 more) +Cohesion: 0.11 +Nodes (15): Tests for connection pool configuration, Tests for connection pool configuration, Stocks engine should have optimized pool settings, Stocks engine should have optimized pool settings, Tests for lazy JSON deserialization, Tests for lazy JSON deserialization, Query manager should have deserialize method, Query manager should have deserialize method (+7 more) ### Community 503 - "Community 503" -Cohesion: 0.29 -Nodes (6): Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., TestStocksApiFundamental +Cohesion: 0.17 +Nodes (7): Tests for dynamic ticker index feature, Ticker index should be built when cache is loaded, Ticker index should contain all tickers from cache, Ticker index should be case-insensitive, Looking up ticker should return valid row index, Ticker index should be rebuilt when cache refreshes, TestTickerIndex ### Community 505 - "Community 505" Cohesion: 0.33 @@ -1719,43 +1723,47 @@ Nodes (9): Appendix F: CI Gate & Graphify Verification Details, code:ini (# setu ### Community 509 - "Community 509" Cohesion: 0.33 -Nodes (5): Non-JSON-dict/list string is left as-is., Non-JSON-dict/list string is left as-is., Non-JSON-dict/list string is left as-is., Non-JSON-dict/list string is left as-is., Non-JSON-dict/list string is left as-is. +Nodes (5): Disputed (already litigated — needs your ruling to proceed), Held out (your ignore rules — not proposed), PONYTAIL.md — proposed cuts, NOT applied. Approve before any edit., Proposed (awaiting approval), Refused ### Community 510 - "Community 510" Cohesion: 0.6 Nodes (3): bench(), main(), stats() ### Community 512 - "Community 512" -Cohesion: 0.2 -Nodes (10): listFields(), Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental. (+2 more) +Cohesion: 0.22 +Nodes (7): Integration tests for all query optimizations, Integration tests for all query optimizations, All optimizations should be implemented, All optimizations should be implemented, Query filter should use ticker index, Query filter should use ticker index, TestQueryOptimization + +### Community 517 - "Community 517" +Cohesion: 0.25 +Nodes (14): baseFrame(), deserializeJsonColumns(), envelope(), filterBySearchTerms(), _filterCotationByDate(), filterCotationData(), finalize(), _parseCotationDate() (+6 more) ### Community 518 - "Community 518" -Cohesion: 0.33 -Nodes (4): Integration tests for all query optimizations, All optimizations should be implemented, Query filter should use ticker index, TestQueryOptimization +Cohesion: 0.08 +Nodes (19): create_memories(), Zero access but score still above threshold → not archived., Even with low score, if accessed → not archived., Even with low score, if accessed → not archived., Already archived memories are skipped., Already archived memories are skipped., Helper to create memories with controlled baseScore, lastAccessedAt, accessCount, Helper to create memories with controlled baseScore, lastAccessedAt, accessCount (+11 more) ### Community 519 - "Community 519" -Cohesion: 0.22 -Nodes (7): verifyAccessToken(), Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError. +Cohesion: 0.57 +Nodes (6): addRole(), addRoleToUser(), getCurrentUser(), getRolesList(), hasRole(), toDict() ### Community 520 - "Community 520" -Cohesion: 0.33 -Nodes (5): pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged. +Cohesion: 0.16 +Nodes (9): pd.NA is not a string, so lambda returns it unchanged., All four SPECIAL_COLS should parse correctly when mixed with None., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., All four SPECIAL_COLS should parse correctly when mixed with None., All four SPECIAL_COLS should parse correctly when mixed with None. (+1 more) ### Community 521 - "Community 521" -Cohesion: 0.16 -Nodes (14): compactCotations(), compactRow(), compactValue(), compressResponse(), fixHeaders(), getAbbr(), getNest(), toColumnar() (+6 more) +Cohesion: 0.2 +Nodes (9): Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132). (+1 more) ### Community 522 - "Community 522" -Cohesion: 0.14 -Nodes (9): Verify that getSession() returns per-thread Session instances., Calling getSession() twice in the same thread returns the same object., Two threads must NOT share a Session object., With 20 concurrent threads, every thread must get its own Session., The returned object must be a real requests.Session., TestGetSession, get_session(), Return a requests.Session for the current thread. Sessions are created la (+1 more) +Cohesion: 0.32 +Nodes (3): TestCleanup, cleanup(), Close the main thread's session at interpreter shutdown. ### Community 523 - "Community 523" -Cohesion: 0.07 -Nodes (35): check_cache(), list_files(), Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri (+27 more) +Cohesion: 0.13 +Nodes (18): check_cache(), Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Read a file from the workspace. Args: path: Path to the file (e., List files in the workspace directory. Args: path: Directory pat (+10 more) ### Community 524 - "Community 524" -Cohesion: 0.33 -Nodes (5): Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, TestFilterBySearchTerms +Cohesion: 0.22 +Nodes (7): verifyAccessToken(), Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError. ### Community 525 - "Community 525" Cohesion: 0.12 @@ -1765,17 +1773,13 @@ Nodes (16): Covers line 16: empty password raises ValueError., Covers line 16: e Cohesion: 0.33 Nodes (7): buildKey(), clearAll(), getMatrix(), invalidateUser(), runAwait(), main(), One-shot: renormalize stored embeddings to unit norm. Usage: python scripts/back -### Community 527 - "Community 527" -Cohesion: 0.09 -Nodes (17): client(), pytest_configure(), TestClient with all routers mounted — no lifespan (no DB/service init). O, Set required env vars before test collection. config.py eagerly instantia, Reset slowapi in-memory rate limiter between every test., Set required env vars before test collection. config.py eagerly instantia, TestClient with all routers mounted — no lifespan (no DB/service init). O, TestClient with all routers mounted — no lifespan (no DB/service init). O (+9 more) - ### Community 528 - "Community 528" Cohesion: 0.07 Nodes (26): Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added. (+18 more) ### Community 529 - "Community 529" -Cohesion: 0.22 -Nodes (4): authenticateUser(), createUserAccount(), FastAPI, PaginationParams +Cohesion: 0.18 +Nodes (6): System prompt should include state context when provided., System prompt should not include state section when empty., State section should appear after memories section., All state entries should appear in the prompt., System prompt should work without state parameter., TestBuildSystemPromptState ### Community 530 - "Community 530" Cohesion: 0.39 @@ -1793,34 +1797,34 @@ Nodes (4): Appendix E: Shared-Kernel Deep Dive (should-be-kernel vs leak), E.1 S Cohesion: 0.5 Nodes (4): LATER (P2 — when touching these files), NOW (P0 — fix before next release), Priority Matrix, SOON (P1 — fix within 2 weeks) +### Community 535 - "Community 535" +Cohesion: 0.33 +Nodes (5): replaceNan handles direct float NaN values (line 34)., replaceNan handles direct float NaN values (line 34)., replaceNan handles direct float NaN values (line 34)., replaceNan handles direct float NaN values (line 34)., replaceNan handles direct float NaN values (line 34). + ### Community 536 - "Community 536" -Cohesion: 0.15 -Nodes (18): executeStateTool(), get_state(), Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, test_dispatch_get_state(), test_dispatch_set_state() (+10 more) +Cohesion: 0.14 +Nodes (19): executeStateTool(), get_state(), Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, test_dispatch_get_state() (+11 more) ### Community 538 - "Community 538" Cohesion: 0.4 -Nodes (4): COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament, COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament, COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament, COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament +Nodes (5): Category 8: Testing Gaps (MEDIUM), Issue 8.1 — No integration tests for full request lifecycle, Issue 8.2 — No tests for scraper, stocks query, or cache, Issue 8.3 — No tests for Google OAuth callback, Issue 8.4 — No tests for session cleanup ### Community 539 - "Community 539" -Cohesion: 0.33 -Nodes (5): Performance tests for query operations, Query should respond within 1 second, Performance tests for query operations, Query should respond within 1 second, TestQueryPerformance +Cohesion: 0.29 +Nodes (6): Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., TestStocksApiHealth ### Community 540 - "Community 540" Cohesion: 0.29 Nodes (6): code:python (import argparse), code:bash (git add bench/bench_memory_vector.py), Global Constraints, Lane 4: Before/After Bench Implementation Plan, Task 1: Bench script with synthetic scale sweep, Task 2: Record baseline and post-lane numbers ### Community 541 - "Community 541" -Cohesion: 0.38 -Nodes (6): create_memory(), createMemory(), _downloadModel(), embed(), getEmbeddingModel(), executeMemoryTool() +Cohesion: 0.2 +Nodes (3): Pytest Testing, Tests for main/utils/http_session.py — covers all branches., TestGetSession ### Community 542 - "Community 542" Cohesion: 0.5 Nodes (3): at, label, rows -### Community 543 - "Community 543" -Cohesion: 0.4 -Nodes (5): Category 7: Code Quality (LOW), Issue 7.1 — Unused imports, Issue 7.2 — Missing type hints, Issue 7.3 — `UserManager.__init__` does nothing, Issue 7.4 — Mixed async/sync in roles.py - ### Community 545 - "Community 545" Cohesion: 0.29 Nodes (7): code:python (def test_split_cliff_no_fake_loss_on_adjusted_series(monkeyp), code:python (def test_snapshot_includes_received_and_cash_gain(dbSession,), code:python (def test_history_merges_dividend_receipts(dbSession, sampleU), code:python (def test_ex_div_methodology_decides_received_stacking(dbSess), code:python (def ex_div_smoothing_verdict(padrao_before: float, padrao_af), code:bash (git add main/app/wallet/manager.py main/controller/wallet_co), Task 12: Split-cliff regression test + snapshot/history dividend extension + final gate @@ -1882,12 +1886,16 @@ Cohesion: 0.5 Nodes (4): code:python (import pytest), code:python (import logging), code:bash (git add main/app/wallet/prices.py tests/test_wallet_prices.p), Task 6: Price client — one batched STOCKS_API fetch per snapshot ### Community 562 - "Community 562" -Cohesion: 0.67 -Nodes (3): checkServiceConnection — success, not found, errors., checkServiceConnection — success, not found, errors., TestCheckServiceConnection +Cohesion: 0.38 +Nodes (6): create_memory(), createMemory(), _downloadModel(), embed(), getEmbeddingModel(), executeMemoryTool() + +### Community 563 - "Community 563" +Cohesion: 0.29 +Nodes (6): Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., TestStocksApiHistorical ### Community 564 - "Community 564" -Cohesion: 0.4 -Nodes (5): initialize(), P5: register the scraper cron jobs on the shared scheduler. Kept in this, registerScraperJobs(), runScraper(), ScraperService +Cohesion: 0.67 +Nodes (3): checkServiceConnection — success, not found, errors., checkServiceConnection — success, not found, errors., TestCheckServiceConnection ### Community 565 - "Community 565" Cohesion: 0.33 @@ -1901,25 +1909,45 @@ Nodes (3): checkMySqlConnection — success, errors, engine=None paths., checkMy Cohesion: 0.14 Nodes (18): verifyAPIKey(), Tests to increase coverage for query.py, key.py, and cache.py in stocks_api., Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, Tests covering key.py lines 15-40. Uses asyncio.run() since pytest-asyncio, test_cache_scheduler_starts_apscheduler(), test_cache_scheduler_starts_daemon_thread() (+10 more) +### Community 568 - "Community 568" +Cohesion: 0.29 +Nodes (6): GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422. + +### Community 570 - "Community 570" +Cohesion: 0.33 +Nodes (5): Tests for optimized search filtering, Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, Filter should use ticker index for O(1) lookup, TestFilterBySearchTerms + +### Community 571 - "Community 571" +Cohesion: 0.33 +Nodes (6): dispatchToolCall must route memory tool names via TOOL_REGISTRY., dispatchToolCall must route memory tool names to executeMemoryTool., dispatchToolCall must route memory tool names to executeMemoryTool., dispatchToolCall must route memory tool names to executeMemoryTool., dispatchToolCall must route memory tool names to executeMemoryTool., TestDispatchRoutesMemoryTools + +### Community 572 - "Community 572" +Cohesion: 0.33 +Nodes (5): Every function in TOOL_REGISTRY must have Gemini-safe signatures. Custom cl, Every function in TOOL_REGISTRY must have Gemini-safe signatures. Custom cl, Regression: HarnessState must never leak into tool signatures., Regression: HarnessState must never leak into tool signatures., TestGeminiCompatibility + +### Community 573 - "Community 573" +Cohesion: 0.33 +Nodes (6): makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., TestMakeChatIncludesMemoryTools + ## Knowledge Gaps -- **3024 isolated node(s):** `$schema`, `style`, `rsc`, `tsx`, `config` (+3019 more) +- **3044 isolated node(s):** `$schema`, `style`, `rsc`, `tsx`, `config` (+3039 more) These have ≤1 connection - possible missing edges or undocumented components. -- **241 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes. +- **234 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes. ## Suggested Questions _Questions this graph is uniquely positioned to answer:_ -- **Why does `Pytest Testing` connect `Community 215` to `Authentication Core`, `Frontend Components`, `Community 129`, `Data Models & Types`, `Community 131`, `Community 135`, `Community 138`, `Community 140`, `Community 527`, `Community 529`, `Community 18`, `Community 147`, `Community 24`, `Community 25`, `Community 536`, `Community 27`, `Community 29`, `Community 32`, `Community 33`, `Community 546`, `Community 40`, `Community 44`, `Community 45`, `Community 172`, `Community 49`, `Community 51`, `Community 54`, `Community 567`, `Community 184`, `Community 59`, `Community 188`, `Community 67`, `Community 86`, `Community 475`, `Community 120`, `Community 93`, `Community 477`, `Community 100`, `Community 234`, `Community 490`, `Community 495`, `Community 502`, `Community 504`, `Community 251`, `Community 125`?** - _High betweenness centrality (0.112) - this node is a cross-community bridge._ -- **Why does `FastAPI` connect `Community 529` to `Community 129`, `Community 519`, `Community 530`, `Community 18`, `Community 147`, `Community 26`, `Community 33`, `Community 546`, `Community 34`, `Community 40`, `Community 169`, `Community 45`, `Community 181`, `Community 567`, `Community 58`, `Community 63`, `Community 71`, `Community 73`, `Community 84`, `Community 475`, `Community 120`, `Community 477`, `Community 222`, `Community 110`, `Community 498`, `Community 501`, `Community 504`?** - _High betweenness centrality (0.050) - this node is a cross-community bridge._ -- **Why does `UserManager` connect `Community 498` to `Community 130`, `Prometheus Agent`, `Prometheus Memory`, `Community 525`, `User Roles & Permissions`, `Community 141`, `Community 16`, `Community 528`, `Community 21`, `Community 22`, `Community 37`, `Community 47`, `Community 178`, `Community 181`, `Community 565`, `Community 567`, `Community 58`, `Community 61`, `Community 68`, `Community 208`, `Community 86`, `Community 474`, `Community 221`, `Community 99`, `Community 104`, `Community 107`, `Community 493`, `Community 503`, `Community 125`?** - _High betweenness centrality (0.032) - this node is a cross-community bridge._ +- **Why does `Pytest Testing` connect `Community 541` to `Authentication Core`, `Frontend Components`, `Community 129`, `Data Models & Types`, `Community 131`, `Community 518`, `Community 135`, `Community 138`, `Community 140`, `Community 527`, `Community 18`, `Community 147`, `Community 24`, `Community 25`, `Community 536`, `Community 27`, `Community 29`, `Community 32`, `Community 33`, `Community 546`, `Community 40`, `Community 44`, `Community 45`, `Community 172`, `Community 49`, `Community 51`, `Community 567`, `Community 184`, `Community 183`, `Community 59`, `Community 188`, `Community 86`, `Community 474`, `Community 475`, `Community 120`, `Community 93`, `Community 477`, `Community 100`, `Community 234`, `Community 495`, `Community 502`, `Community 504`, `Community 251`, `Community 125`?** + _High betweenness centrality (0.102) - this node is a cross-community bridge._ +- **Why does `UserManager` connect `Community 498` to `Prometheus Agent`, `Community 519`, `Prometheus Memory`, `Community 140`, `Community 525`, `User Roles & Permissions`, `Community 141`, `Community 16`, `Community 528`, `Community 21`, `Community 22`, `Community 539`, `Community 28`, `Community 37`, `Community 47`, `Community 178`, `Community 563`, `Community 565`, `Community 567`, `Community 58`, `Community 61`, `Community 68`, `Community 208`, `Community 86`, `Community 221`, `Community 99`, `Community 231`, `Community 104`, `Community 488`, `Community 107`, `Community 493`, `Community 114`, `Community 120`, `Community 125`?** + _High betweenness centrality (0.042) - this node is a cross-community bridge._ +- **Why does `Prometheus` connect `Community 116` to `Frontend Components`, `Device Detection`, `Community 138`, `Community 140`, `Frontend App Shell`, `Community 529`, `Community 151`, `Community 24`, `Community 543`, `Community 544`, `Community 52`, `Community 569`, `Community 571`, `Community 60`, `Community 573`, `Community 194`, `Community 67`, `Community 68`, `Community 80`, `Community 87`, `Community 88`, `Community 93`, `Community 102`, `Community 105`, `Community 125`?** + _High betweenness centrality (0.037) - this node is a cross-community bridge._ - **Are the 72 inferred relationships involving `StocksCacheManager` (e.g. with `TestStocksCacheManager` and `TestVerifyAPIKey`) actually correct?** _`StocksCacheManager` has 72 INFERRED edges - model-reasoned connections that need verification._ - **Are the 52 inferred relationships involving `HarnessState` (e.g. with `Prometheus` and `.streamMessage()`) actually correct?** _`HarnessState` has 52 INFERRED edges - model-reasoned connections that need verification._ - **Are the 54 inferred relationships involving `UserManager` (e.g. with `AuthenticationManager` and `User`) actually correct?** _`UserManager` has 54 INFERRED edges - model-reasoned connections that need verification._ -- **Are the 38 inferred relationships involving `StocksQueryManager` (e.g. with `StocksCacheManager` and `TestStocksCacheManager`) actually correct?** - _`StocksQueryManager` has 38 INFERRED edges - model-reasoned connections that need verification._ \ No newline at end of file +- **Are the 48 inferred relationships involving `Permission` (e.g. with `PrometheusMemory` and `UserManager`) actually correct?** + _`Permission` has 48 INFERRED edges - model-reasoned connections that need verification._ \ No newline at end of file diff --git a/graphify-out/graph.json b/graphify-out/graph.json index 15a80cb..4c55292 100644 --- a/graphify-out/graph.json +++ b/graphify-out/graph.json @@ -208,16 +208,16 @@ "label": "PrometheusSettings", "file_type": "code", "source_file": "config.py", - "source_location": "L61", + "source_location": "L59", "id": "server_config_prometheussettings", - "community": 215, + "community": 102, "norm_label": "prometheussettings" }, { "label": "ScraperSettings", "file_type": "code", "source_file": "config.py", - "source_location": "L78", + "source_location": "L76", "id": "server_config_scrapersettings", "community": 102, "norm_label": "scrapersettings" @@ -226,7 +226,7 @@ "label": "DiscordSettings", "file_type": "code", "source_file": "config.py", - "source_location": "L87", + "source_location": "L85", "id": "server_config_discordsettings", "community": 102, "norm_label": "discordsettings" @@ -235,16 +235,16 @@ "label": "Config", "file_type": "code", "source_file": "config.py", - "source_location": "L93", + "source_location": "L91", "id": "server_config_config", - "community": 194, + "community": 102, "norm_label": "config" }, { "label": "getSession()", "file_type": "code", "source_file": "config.py", - "source_location": "L131", + "source_location": "L129", "id": "server_config_getsession", "community": 102, "norm_label": "getsession()" @@ -253,7 +253,7 @@ "label": "getStocksSession()", "file_type": "code", "source_file": "config.py", - "source_location": "L139", + "source_location": "L137", "id": "server_config_getstockssession", "community": 102, "norm_label": "getstockssession()" @@ -264,43 +264,43 @@ "source_file": "run.py", "source_location": "L1", "id": "run_py", - "community": 110, + "community": 491, "norm_label": "run.py" }, { "label": "lifespan()", "file_type": "code", "source_file": "run.py", - "source_location": "L28", + "source_location": "L27", "id": "server_run_lifespan", - "community": 110, + "community": 491, "norm_label": "lifespan()" }, { "label": "health()", "file_type": "code", "source_file": "run.py", - "source_location": "L73", + "source_location": "L72", "id": "server_run_health", - "community": 110, + "community": 491, "norm_label": "health()" }, { "label": "status()", "file_type": "code", "source_file": "run.py", - "source_location": "L78", + "source_location": "L77", "id": "server_run_status", - "community": 110, + "community": 491, "norm_label": "status()" }, { "label": "triggerScraper()", "file_type": "code", "source_file": "run.py", - "source_location": "L112", + "source_location": "L111", "id": "server_run_triggerscraper", - "community": 110, + "community": 491, "norm_label": "triggerscraper()" }, { @@ -2190,7 +2190,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L1", "id": "main_app_authentication_authentication_py", - "community": 529, + "community": 474, "norm_label": "authentication.py" }, { @@ -2208,7 +2208,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L16", "id": "authentication_authentication_createuseraccount", - "community": 529, + "community": 474, "norm_label": "createuseraccount()" }, { @@ -2217,7 +2217,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L51", "id": "authentication_authentication_authenticategoogleuser", - "community": 529, + "community": 474, "norm_label": "authenticategoogleuser()" }, { @@ -2226,7 +2226,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L65", "id": "authentication_authentication_authenticateuser", - "community": 529, + "community": 474, "norm_label": "authenticateuser()" }, { @@ -2256,20 +2256,11 @@ "community": 68, "norm_label": "sessionmanager" }, - { - "label": "getDeviceName()", - "file_type": "code", - "source_file": "main/app/authentication/session.py", - "source_location": "L14", - "id": "authentication_session_getdevicename", - "community": 149, - "norm_label": "getdevicename()" - }, { "label": "createSession()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L22", + "source_location": "L14", "id": "authentication_session_createsession", "community": 149, "norm_label": "createsession()" @@ -2278,7 +2269,7 @@ "label": "getUserSessions()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L53", + "source_location": "L45", "id": "authentication_session_getusersessions", "community": 149, "norm_label": "getusersessions()" @@ -2287,7 +2278,7 @@ "label": "getSessionById()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L60", + "source_location": "L50", "id": "authentication_session_getsessionbyid", "community": 149, "norm_label": "getsessionbyid()" @@ -2296,7 +2287,7 @@ "label": "getCurrentSession()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L67", + "source_location": "L57", "id": "authentication_session_getcurrentsession", "community": 149, "norm_label": "getcurrentsession()" @@ -2305,7 +2296,7 @@ "label": "revokeSession()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L79", + "source_location": "L69", "id": "authentication_session_revokesession", "community": 149, "norm_label": "revokesession()" @@ -2314,7 +2305,7 @@ "label": "revokeAllSessions()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L91", + "source_location": "L81", "id": "authentication_session_revokeallsessions", "community": 149, "norm_label": "revokeallsessions()" @@ -2323,7 +2314,7 @@ "label": "updateLastActive()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L107", + "source_location": "L94", "id": "authentication_session_updatelastactive", "community": 149, "norm_label": "updatelastactive()" @@ -2332,7 +2323,7 @@ "label": "validateSession()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L117", + "source_location": "L104", "id": "authentication_session_validatesession", "community": 149, "norm_label": "validatesession()" @@ -2361,7 +2352,7 @@ "source_file": "main/app/authentication/util.py", "source_location": "L1", "id": "main_app_authentication_util_py", - "community": 519, + "community": 524, "norm_label": "util.py" }, { @@ -2397,7 +2388,7 @@ "source_file": "main/app/authentication/util.py", "source_location": "L44", "id": "authentication_util_verifyaccesstoken", - "community": 519, + "community": 524, "norm_label": "verifyaccesstoken()" }, { @@ -2427,11 +2418,20 @@ "community": 116, "norm_label": "safefilter()" }, + { + "label": "persistEvent()", + "file_type": "code", + "source_file": "main/app/prometheus/agent.py", + "source_location": "L31", + "id": "prometheus_agent_persistevent", + "community": 116, + "norm_label": "persistevent()" + }, { "label": "getClient()", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L38", + "source_location": "L45", "id": "prometheus_agent_getclient", "community": 116, "norm_label": "getclient()" @@ -2440,7 +2440,7 @@ "label": "Prometheus", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L201", + "source_location": "L208", "id": "prometheus_agent_prometheus", "community": 116, "norm_label": "prometheus" @@ -2449,7 +2449,7 @@ "label": ".__init__()", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L202", + "source_location": "L209", "id": "prometheus_agent_prometheus_init", "community": 116, "norm_label": ".__init__()" @@ -2458,7 +2458,7 @@ "label": "buildSystemPrompt()", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L206", + "source_location": "L213", "id": "prometheus_agent_buildsystemprompt", "community": 116, "norm_label": "buildsystemprompt()" @@ -2467,7 +2467,7 @@ "label": ".makeChat()", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L235", + "source_location": "L242", "id": "prometheus_agent_prometheus_makechat", "community": 116, "norm_label": ".makechat()" @@ -2476,7 +2476,7 @@ "label": ".streamMessage()", "file_type": "code", "source_file": "main/app/prometheus/agent.py", - "source_location": "L246", + "source_location": "L253", "id": "prometheus_agent_prometheus_streammessage", "community": 116, "norm_label": ".streammessage()" @@ -2575,7 +2575,7 @@ "label": "getTokenizer()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L33", + "source_location": "L31", "id": "prometheus_compact_gettokenizer", "community": 80, "norm_label": "gettokenizer()" @@ -2584,7 +2584,7 @@ "label": "countTokens()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L45", + "source_location": "L43", "id": "prometheus_compact_counttokens", "community": 80, "norm_label": "counttokens()" @@ -2593,7 +2593,7 @@ "label": "getStocksFieldsUrl()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L62", + "source_location": "L60", "id": "prometheus_compact_getstocksfieldsurl", "community": 80, "norm_label": "getstocksfieldsurl()" @@ -2602,43 +2602,16 @@ "label": "loadFieldData()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L66", + "source_location": "L64", "id": "prometheus_compact_loadfielddata", "community": 80, "norm_label": "loadfielddata()" }, - { - "label": "getHistoricalFields()", - "file_type": "code", - "source_file": "main/app/prometheus/compact.py", - "source_location": "L89", - "id": "prometheus_compact_gethistoricalfields", - "community": 80, - "norm_label": "gethistoricalfields()" - }, - { - "label": "getFundamentalColumns()", - "file_type": "code", - "source_file": "main/app/prometheus/compact.py", - "source_location": "L93", - "id": "prometheus_compact_getfundamentalcolumns", - "community": 80, - "norm_label": "getfundamentalcolumns()" - }, - { - "label": "invalidateFieldData()", - "file_type": "code", - "source_file": "main/app/prometheus/compact.py", - "source_location": "L97", - "id": "prometheus_compact_invalidatefielddata", - "community": 80, - "norm_label": "invalidatefielddata()" - }, { "label": "getMetricRegex()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L103", + "source_location": "L82", "id": "prometheus_compact_getmetricregex", "community": 80, "norm_label": "getmetricregex()" @@ -2647,7 +2620,7 @@ "label": "dedup()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L117", + "source_location": "L96", "id": "prometheus_compact_dedup", "community": 80, "norm_label": "dedup()" @@ -2656,7 +2629,7 @@ "label": "extractTickers()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L121", + "source_location": "L100", "id": "prometheus_compact_extracttickers", "community": 80, "norm_label": "extracttickers()" @@ -2665,7 +2638,7 @@ "label": "extractMetrics()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L125", + "source_location": "L104", "id": "prometheus_compact_extractmetrics", "community": 80, "norm_label": "extractmetrics()" @@ -2674,7 +2647,7 @@ "label": "extractDecisions()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L131", + "source_location": "L108", "id": "prometheus_compact_extractdecisions", "community": 80, "norm_label": "extractdecisions()" @@ -2683,7 +2656,7 @@ "label": "extractSnapshots()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L145", + "source_location": "L122", "id": "prometheus_compact_extractsnapshots", "community": 80, "norm_label": "extractsnapshots()" @@ -2692,7 +2665,7 @@ "label": "extractToolCalls()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L158", + "source_location": "L135", "id": "prometheus_compact_extracttoolcalls", "community": 80, "norm_label": "extracttoolcalls()" @@ -2701,7 +2674,7 @@ "label": "buildSummary()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L174", + "source_location": "L151", "id": "prometheus_compact_buildsummary", "community": 80, "norm_label": "buildsummary()" @@ -2710,7 +2683,7 @@ "label": "PrometheusCompactor", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L195", + "source_location": "L172", "id": "prometheus_compact_prometheuscompactor", "community": 80, "norm_label": "prometheuscompactor" @@ -2719,7 +2692,7 @@ "label": ".shouldCompact()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L196", + "source_location": "L173", "id": "prometheus_compact_prometheuscompactor_shouldcompact", "community": 80, "norm_label": ".shouldcompact()" @@ -2728,7 +2701,7 @@ "label": ".getCompactableChunk()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L213", + "source_location": "L190", "id": "prometheus_compact_prometheuscompactor_getcompactablechunk", "community": 80, "norm_label": ".getcompactablechunk()" @@ -2737,7 +2710,7 @@ "label": ".extractEpisode()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L222", + "source_location": "L199", "id": "prometheus_compact_prometheuscompactor_extractepisode", "community": 80, "norm_label": ".extractepisode()" @@ -2746,7 +2719,7 @@ "label": ".consolidate()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L244", + "source_location": "L221", "id": "prometheus_compact_prometheuscompactor_consolidate", "community": 80, "norm_label": ".consolidate()" @@ -2755,7 +2728,7 @@ "label": ".compact()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L271", + "source_location": "L248", "id": "prometheus_compact_prometheuscompactor_compact", "community": 80, "norm_label": ".compact()" @@ -2764,7 +2737,7 @@ "label": ".getEpisodes()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L310", + "source_location": "L287", "id": "prometheus_compact_prometheuscompactor_getepisodes", "community": 80, "norm_label": ".getepisodes()" @@ -2788,10 +2761,19 @@ "norm_label": "buildclient()" }, { - "label": "MCPClientPool", + "label": "connect()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", "source_location": "L29", + "id": "prometheus_mcp_connect", + "community": 194, + "norm_label": "connect()" + }, + { + "label": "MCPClientPool", + "file_type": "code", + "source_file": "main/app/prometheus/mcp.py", + "source_location": "L36", "id": "prometheus_mcp_mcpclientpool", "community": 194, "norm_label": "mcpclientpool" @@ -2800,7 +2782,7 @@ "label": ".__init__()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L30", + "source_location": "L37", "id": "prometheus_mcp_mcpclientpool_init", "community": 194, "norm_label": ".__init__()" @@ -2809,7 +2791,7 @@ "label": ".initialize()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L35", + "source_location": "L42", "id": "prometheus_mcp_mcpclientpool_initialize", "community": 194, "norm_label": ".initialize()" @@ -2818,7 +2800,7 @@ "label": ".getClients()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L52", + "source_location": "L56", "id": "prometheus_mcp_mcpclientpool_getclients", "community": 194, "norm_label": ".getclients()" @@ -2827,7 +2809,7 @@ "label": ".healthCheck()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L59", + "source_location": "L63", "id": "prometheus_mcp_mcpclientpool_healthcheck", "community": 194, "norm_label": ".healthcheck()" @@ -2836,7 +2818,7 @@ "label": ".reconnect()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L71", + "source_location": "L75", "id": "prometheus_mcp_mcpclientpool_reconnect", "community": 194, "norm_label": ".reconnect()" @@ -2845,7 +2827,7 @@ "label": ".close()", "file_type": "code", "source_file": "main/app/prometheus/mcp.py", - "source_location": "L88", + "source_location": "L90", "id": "prometheus_mcp_mcpclientpool_close", "community": 194, "norm_label": ".close()" @@ -2859,29 +2841,11 @@ "community": 53, "norm_label": "memory.py" }, - { - "label": "matrixKey()", - "file_type": "code", - "source_file": "main/app/prometheus/memory.py", - "source_location": "L31", - "id": "prometheus_memory_matrixkey", - "community": 53, - "norm_label": "matrixkey()" - }, - { - "label": "matrixUserTag()", - "file_type": "code", - "source_file": "main/app/prometheus/memory.py", - "source_location": "L38", - "id": "prometheus_memory_matrixusertag", - "community": 53, - "norm_label": "matrixusertag()" - }, { "label": "getMatrix()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L43", + "source_location": "L31", "id": "prometheus_memory_getmatrix", "community": 53, "norm_label": "getmatrix()" @@ -2890,7 +2854,7 @@ "label": "invalidateUser()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L56", + "source_location": "L49", "id": "prometheus_memory_invalidateuser", "community": 53, "norm_label": "invalidateuser()" @@ -2899,7 +2863,7 @@ "label": "clearAll()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L60", + "source_location": "L53", "id": "prometheus_memory_clearall", "community": 53, "norm_label": "clearall()" @@ -2908,7 +2872,7 @@ "label": "getClient()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L84", + "source_location": "L77", "id": "prometheus_memory_getclient", "community": 53, "norm_label": "getclient()" @@ -2917,16 +2881,16 @@ "label": "minMax()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L91", + "source_location": "L84", "id": "prometheus_memory_minmax", - "community": 13, + "community": 53, "norm_label": "minmax()" }, { "label": "normalizeKey()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L100", + "source_location": "L93", "id": "prometheus_memory_normalizekey", "community": 53, "norm_label": "normalizekey()" @@ -2935,34 +2899,43 @@ "label": "findSimilarKey()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L107", + "source_location": "L100", "id": "prometheus_memory_findsimilarkey", "community": 53, "norm_label": "findsimilarkey()" }, + { + "label": "scoreRow()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L123", + "id": "prometheus_memory_scorerow", + "community": 53, + "norm_label": "scorerow()" + }, { "label": "scoreRecency()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L130", + "source_location": "L135", "id": "prometheus_memory_scorerecency", - "community": 13, + "community": 53, "norm_label": "scorerecency()" }, { "label": "scoreCandidates()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L148", + "source_location": "L145", "id": "prometheus_memory_scorecandidates", - "community": 13, + "community": 53, "norm_label": "scorecandidates()" }, { "label": "sumTokens()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L176", + "source_location": "L162", "id": "prometheus_memory_sumtokens", "community": 53, "norm_label": "sumtokens()" @@ -2971,7 +2944,7 @@ "label": "PrometheusMemory", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L191", + "source_location": "L177", "id": "prometheus_memory_prometheusmemory", "community": 140, "norm_label": "prometheusmemory" @@ -2980,7 +2953,7 @@ "label": "getMemoryLimit()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L193", + "source_location": "L179", "id": "prometheus_memory_getmemorylimit", "community": 53, "norm_label": "getmemorylimit()" @@ -2989,16 +2962,25 @@ "label": "countMemories()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L199", + "source_location": "L185", "id": "prometheus_memory_countmemories", "community": 53, "norm_label": "countmemories()" }, + { + "label": "touch()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L194", + "id": "prometheus_memory_touch", + "community": 53, + "norm_label": "touch()" + }, { "label": "upsertMemory()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L208", + "source_location": "L205", "id": "prometheus_memory_upsertmemory", "community": 53, "norm_label": "upsertmemory()" @@ -3007,52 +2989,43 @@ "label": "search()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L286", + "source_location": "L269", "id": "prometheus_memory_search", - "community": 13, + "community": 53, "norm_label": "search()" }, { "label": "fullTextSearch()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L349", + "source_location": "L332", "id": "prometheus_memory_fulltextsearch", - "community": 13, + "community": 53, "norm_label": "fulltextsearch()" }, { "label": "getUserMemories()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L407", + "source_location": "L390", "id": "prometheus_memory_getusermemories", - "community": 53, + "community": 27, "norm_label": "getusermemories()" }, { "label": "deleteMemory()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L432", + "source_location": "L415", "id": "prometheus_memory_deletememory", "community": 53, "norm_label": "deletememory()" }, - { - "label": "countTokensCached()", - "file_type": "code", - "source_file": "main/app/prometheus/memory.py", - "source_location": "L450", - "id": "prometheus_memory_counttokenscached", - "community": 53, - "norm_label": "counttokenscached()" - }, { "label": "extract()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L454", + "source_location": "L433", "id": "prometheus_memory_extract", "community": 53, "norm_label": "extract()" @@ -3169,25 +3142,16 @@ "label": "list_files()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L186", + "source_location": "L189", "id": "prometheus_sandbox_list_files", "community": 69, "norm_label": "list_files()" }, - { - "label": "write_bytes()", - "file_type": "code", - "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L194", - "id": "prometheus_sandbox_write_bytes", - "community": 69, - "norm_label": "write_bytes()" - }, { "label": "delete_file()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L205", + "source_location": "L197", "id": "prometheus_sandbox_delete_file", "community": 69, "norm_label": "delete_file()" @@ -3196,7 +3160,7 @@ "label": "syncToSandbox()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L222", + "source_location": "L214", "id": "prometheus_sandbox_synctosandbox", "community": 69, "norm_label": "synctosandbox()" @@ -3205,7 +3169,7 @@ "label": "syncFromSandbox()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L241", + "source_location": "L233", "id": "prometheus_sandbox_syncfromsandbox", "community": 69, "norm_label": "syncfromsandbox()" @@ -3342,7 +3306,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L51", "id": "prometheus_tools_save_memory", - "community": 152, + "community": 90, "norm_label": "save_memory()" }, { @@ -3360,7 +3324,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L114", "id": "prometheus_tools_read_file", - "community": 523, + "community": 500, "norm_label": "read_file()" }, { @@ -3378,7 +3342,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L144", "id": "prometheus_tools_list_files", - "community": 523, + "community": 162, "norm_label": "list_files()" }, { @@ -3414,7 +3378,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L52", "id": "prometheus_tools_rationale_52", - "community": 152, + "community": 90, "norm_label": "store a memory about the user's preferences, analysis results, or feedback." }, { @@ -3432,7 +3396,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L115", "id": "prometheus_tools_rationale_115", - "community": 523, + "community": 500, "norm_label": "read a file from the workspace. args: path: path to the file (e." }, { @@ -3486,7 +3450,7 @@ "source_file": "main/app/prometheus/vector.py", "source_location": "L15", "id": "prometheus_vector_embed", - "community": 13, + "community": 53, "norm_label": "embed()" }, { @@ -3567,7 +3531,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L42", "id": "scraper_b3_scraper_b3scraper", - "community": 535, + "community": 72, "norm_label": "b3scraper" }, { @@ -3639,7 +3603,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L228", "id": "scraper_b3_scraper_b3scraper_historicalcotationprofits_oceans14", - "community": 535, + "community": 72, "norm_label": ".historicalcotationprofits_oceans14()" }, { @@ -3675,7 +3639,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L296", "id": "scraper_b3_scraper_b3scraper_fundamentalindicators", - "community": 535, + "community": 72, "norm_label": ".fundamentalindicators()" }, { @@ -3684,7 +3648,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L419", "id": "scraper_b3_scraper_b3scraper_processticker", - "community": 535, + "community": 72, "norm_label": ".processticker()" }, { @@ -3693,7 +3657,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L450", "id": "scraper_b3_scraper_b3scraper_scrapestocks", - "community": 535, + "community": 72, "norm_label": ".scrapestocks()" }, { @@ -3702,7 +3666,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L497", "id": "scraper_b3_scraper_b3scraper_reordercolumns", - "community": 535, + "community": 72, "norm_label": ".reordercolumns()" }, { @@ -3711,7 +3675,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L506", "id": "scraper_b3_scraper_b3scraper_serializecomplextypes", - "community": 535, + "community": 72, "norm_label": ".serializecomplextypes()" }, { @@ -3720,7 +3684,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L525", "id": "scraper_b3_scraper_b3scraper_exportjson", - "community": 535, + "community": 72, "norm_label": ".exportjson()" }, { @@ -3729,7 +3693,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L533", "id": "scraper_b3_scraper_b3scraper_exportmysql", - "community": 535, + "community": 72, "norm_label": ".exportmysql()" }, { @@ -3763,7 +3727,7 @@ "label": "optimizeDtypes()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L38", + "source_location": "L39", "id": "stocks_api_cache_optimizedtypes", "community": 82, "norm_label": "optimizedtypes()" @@ -3772,7 +3736,7 @@ "label": "arrowTypeFor()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L58", + "source_location": "L59", "id": "stocks_api_cache_arrowtypefor", "community": 82, "norm_label": "arrowtypefor()" @@ -3781,7 +3745,7 @@ "label": "buildFeatherCache()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L69", + "source_location": "L70", "id": "stocks_api_cache_buildfeathercache", "community": 82, "norm_label": "buildfeathercache()" @@ -3790,7 +3754,7 @@ "label": "tryBuildLock()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L153", + "source_location": "L165", "id": "stocks_api_cache_trybuildlock", "community": 82, "norm_label": "trybuildlock()" @@ -3799,7 +3763,7 @@ "label": "sortCacheFrame()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L170", + "source_location": "L182", "id": "stocks_api_cache_sortcacheframe", "community": 82, "norm_label": "sortcacheframe()" @@ -3808,7 +3772,7 @@ "label": "buildTickerIndex()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L180", + "source_location": "L192", "id": "stocks_api_cache_buildtickerindex", "community": 82, "norm_label": "buildtickerindex()" @@ -3817,7 +3781,7 @@ "label": "StocksCacheManager", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L189", + "source_location": "L201", "id": "stocks_api_cache_stockscachemanager", "community": 42, "norm_label": "stockscachemanager" @@ -3826,7 +3790,7 @@ "label": ".__init__()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L190", + "source_location": "L202", "id": "stocks_api_cache_stockscachemanager_init", "community": 42, "norm_label": ".__init__()" @@ -3835,7 +3799,7 @@ "label": ".snapshot()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L198", + "source_location": "L210", "id": "stocks_api_cache_stockscachemanager_snapshot", "community": 42, "norm_label": ".snapshot()" @@ -3844,16 +3808,16 @@ "label": ".cacheScheduler()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L202", + "source_location": "L214", "id": "stocks_api_cache_stockscachemanager_cachescheduler", - "community": 500, + "community": 82, "norm_label": ".cachescheduler()" }, { "label": ".loadFromFeather()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L213", + "source_location": "L225", "id": "stocks_api_cache_stockscachemanager_loadfromfeather", "community": 82, "norm_label": ".loadfromfeather()" @@ -3862,7 +3826,7 @@ "label": ".getCachedStocks()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L232", + "source_location": "L244", "id": "stocks_api_cache_stockscachemanager_getcachedstocks", "community": 82, "norm_label": ".getcachedstocks()" @@ -3873,7 +3837,7 @@ "source_file": "main/app/stocks_api/compress.py", "source_location": "L1", "id": "main_app_stocks_api_compress_py", - "community": 521, + "community": 112, "norm_label": "compress.py" }, { @@ -3882,7 +3846,7 @@ "source_file": "main/app/stocks_api/compress.py", "source_location": "L23", "id": "stocks_api_compress_getabbr", - "community": 521, + "community": 112, "norm_label": "getabbr()" }, { @@ -3891,7 +3855,7 @@ "source_file": "main/app/stocks_api/compress.py", "source_location": "L31", "id": "stocks_api_compress_getnest", - "community": 521, + "community": 112, "norm_label": "getnest()" }, { @@ -3903,67 +3867,40 @@ "community": 82, "norm_label": "rebuildabbrevs()" }, - { - "label": "walk()", - "file_type": "code", - "source_file": "main/app/stocks_api/compress.py", - "source_location": "L46", - "id": "stocks_api_compress_walk", - "community": 521, - "norm_label": "walk()" - }, { "label": "compactValue()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L54", + "source_location": "L46", "id": "stocks_api_compress_compactvalue", - "community": 521, + "community": 112, "norm_label": "compactvalue()" }, - { - "label": "toColumnar()", - "file_type": "code", - "source_file": "main/app/stocks_api/compress.py", - "source_location": "L75", - "id": "stocks_api_compress_tocolumnar", - "community": 521, - "norm_label": "tocolumnar()" - }, - { - "label": "fixHeaders()", - "file_type": "code", - "source_file": "main/app/stocks_api/compress.py", - "source_location": "L84", - "id": "stocks_api_compress_fixheaders", - "community": 521, - "norm_label": "fixheaders()" - }, { "label": "compactRow()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L93", + "source_location": "L67", "id": "stocks_api_compress_compactrow", - "community": 521, + "community": 112, "norm_label": "compactrow()" }, { "label": "compactCotations()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L121", + "source_location": "L95", "id": "stocks_api_compress_compactcotations", - "community": 521, + "community": 112, "norm_label": "compactcotations()" }, { "label": "compressResponse()", "file_type": "code", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L155", + "source_location": "L130", "id": "stocks_api_compress_compressresponse", - "community": 521, + "community": 112, "norm_label": "compressresponse()" }, { @@ -3990,14 +3927,14 @@ "source_file": "main/app/stocks_api/query.py", "source_location": "L1", "id": "main_app_stocks_api_query_py", - "community": 63, + "community": 517, "norm_label": "query.py" }, { "label": "sanitizeNanValues()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L18", + "source_location": "L17", "id": "stocks_api_query_sanitizenanvalues", "community": 63, "norm_label": "sanitizenanvalues()" @@ -4006,100 +3943,100 @@ "label": "filterCotationColumn()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L34", + "source_location": "L33", "id": "stocks_api_query_filtercotationcolumn", "community": 22, "norm_label": "filtercotationcolumn()" }, { - "label": "StocksQueryManager", + "label": "baseFrame()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L54", - "id": "stocks_api_query_stocksquerymanager", - "community": 63, - "norm_label": "stocksquerymanager" + "source_location": "L53", + "id": "stocks_api_query_baseframe", + "community": 517, + "norm_label": "baseframe()" }, { - "label": ".__init__()", + "label": "validateFields()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L55", - "id": "stocks_api_query_stocksquerymanager_init", - "community": 63, - "norm_label": ".__init__()" + "source_location": "L66", + "id": "stocks_api_query_validatefields", + "community": 517, + "norm_label": "validatefields()" }, { - "label": ".baseFrame()", + "label": "envelope()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L58", - "id": "stocks_api_query_stocksquerymanager_baseframe", - "community": 63, - "norm_label": ".baseframe()" + "source_location": "L79", + "id": "stocks_api_query_envelope", + "community": 517, + "norm_label": "envelope()" }, { - "label": ".finalize()", + "label": "finalize()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L69", - "id": "stocks_api_query_stocksquerymanager_finalize", - "community": 63, - "norm_label": ".finalize()" + "source_location": "L90", + "id": "stocks_api_query_finalize", + "community": 517, + "norm_label": "finalize()" }, { - "label": ".deserializeJsonColumns()", + "label": "deserializeJsonColumns()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L109", - "id": "stocks_api_query_stocksquerymanager_deserializejsoncolumns", - "community": 63, - "norm_label": ".deserializejsoncolumns()" + "source_location": "L123", + "id": "stocks_api_query_deserializejsoncolumns", + "community": 517, + "norm_label": "deserializejsoncolumns()" }, { - "label": ".filterBySearchTerms()", + "label": "filterBySearchTerms()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L136", - "id": "stocks_api_query_stocksquerymanager_filterbysearchterms", - "community": 63, - "norm_label": ".filterbysearchterms()" + "source_location": "L151", + "id": "stocks_api_query_filterbysearchterms", + "community": 517, + "norm_label": "filterbysearchterms()" }, { - "label": ".queryHistorical()", + "label": "queryHistorical()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L153", - "id": "stocks_api_query_stocksquerymanager_queryhistorical", - "community": 63, - "norm_label": ".queryhistorical()" + "source_location": "L169", + "id": "stocks_api_query_queryhistorical", + "community": 517, + "norm_label": "queryhistorical()" }, { - "label": ".queryFundamental()", + "label": "queryFundamental()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L220", - "id": "stocks_api_query_stocksquerymanager_queryfundamental", - "community": 63, - "norm_label": ".queryfundamental()" + "source_location": "L226", + "id": "stocks_api_query_queryfundamental", + "community": 517, + "norm_label": "queryfundamental()" }, { - "label": ".queryCotations()", + "label": "queryCotations()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L284", - "id": "stocks_api_query_stocksquerymanager_querycotations", - "community": 63, - "norm_label": ".querycotations()" + "source_location": "L289", + "id": "stocks_api_query_querycotations", + "community": 517, + "norm_label": "querycotations()" }, { - "label": ".queryLiveCotation()", + "label": "queryLiveCotation()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L331", - "id": "stocks_api_query_stocksquerymanager_querylivecotation", - "community": 63, - "norm_label": ".querylivecotation()" + "source_location": "L330", + "id": "stocks_api_query_querylivecotation", + "community": 81, + "norm_label": "querylivecotation()" }, { "label": "sync_cache.py", @@ -4111,13 +4048,13 @@ "norm_label": "sync_cache.py" }, { - "label": "sync_cache()", + "label": "cache()", "file_type": "code", "source_file": "main/app/stocks_api/sync_cache.py", - "source_location": "L13", - "id": "stocks_api_sync_cache_sync_cache", + "source_location": "L14", + "id": "stocks_api_sync_cache_cache", "community": 511, - "norm_label": "sync_cache()" + "norm_label": "cache()" }, { "label": "util.py", @@ -4132,34 +4069,34 @@ "label": "dedupAbbrev()", "file_type": "code", "source_file": "main/app/stocks_api/util.py", - "source_location": "L20", + "source_location": "L17", "id": "stocks_api_util_dedupabbrev", - "community": 521, + "community": 112, "norm_label": "dedupabbrev()" }, { "label": "autoAbbreviate()", "file_type": "code", "source_file": "main/app/stocks_api/util.py", - "source_location": "L29", + "source_location": "L26", "id": "stocks_api_util_autoabbreviate", - "community": 521, + "community": 112, "norm_label": "autoabbreviate()" }, { "label": "generateAbbreviations()", "file_type": "code", "source_file": "main/app/stocks_api/util.py", - "source_location": "L50", + "source_location": "L47", "id": "stocks_api_util_generateabbreviations", - "community": 521, + "community": 112, "norm_label": "generateabbreviations()" }, { "label": "categorizeColumns()", "file_type": "code", "source_file": "main/app/stocks_api/util.py", - "source_location": "L59", + "source_location": "L56", "id": "stocks_api_util_categorizecolumns", "community": 147, "norm_label": "categorizecolumns()" @@ -4168,7 +4105,7 @@ "label": "parseDate()", "file_type": "code", "source_file": "main/app/stocks_api/util.py", - "source_location": "L76", + "source_location": "L73", "id": "stocks_api_util_parsedate", "community": 73, "norm_label": "parsedate()" @@ -4177,7 +4114,7 @@ "label": "parseDateRange()", "file_type": "code", "source_file": "main/app/stocks_api/util.py", - "source_location": "L88", + "source_location": "L85", "id": "stocks_api_util_parsedaterange", "community": 73, "norm_label": "parsedaterange()" @@ -4186,9 +4123,9 @@ "label": "detectNestedFields()", "file_type": "code", "source_file": "main/app/stocks_api/util.py", - "source_location": "L99", + "source_location": "L96", "id": "stocks_api_util_detectnestedfields", - "community": 521, + "community": 112, "norm_label": "detectnestedfields()" }, { @@ -4197,7 +4134,7 @@ "source_file": "main/app/user/user.py", "source_location": "L1", "id": "main_app_user_user_py", - "community": 181, + "community": 519, "norm_label": "user.py" }, { @@ -4215,7 +4152,7 @@ "source_file": "main/app/user/user.py", "source_location": "L16", "id": "user_user_getroleslist", - "community": 181, + "community": 519, "norm_label": "getroleslist()" }, { @@ -4224,7 +4161,7 @@ "source_file": "main/app/user/user.py", "source_location": "L22", "id": "user_user_getcurrentuser", - "community": 181, + "community": 519, "norm_label": "getcurrentuser()" }, { @@ -4431,7 +4368,7 @@ "source_file": "main/controller/stocksapi_controller.py", "source_location": "L1", "id": "main_controller_stocksapi_controller_py", - "community": 169, + "community": 54, "norm_label": "stocksapi_controller.py" }, { @@ -4440,7 +4377,7 @@ "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", "id": "controller_stocksapi_controller_health", - "community": 169, + "community": 54, "norm_label": "health()" }, { @@ -4449,7 +4386,7 @@ "source_file": "main/controller/stocksapi_controller.py", "source_location": "L38", "id": "controller_stocksapi_controller_listfields", - "community": 512, + "community": 54, "norm_label": "listfields()" }, { @@ -4494,7 +4431,7 @@ "source_file": "main/controller/stocksapi_controller.py", "source_location": "L39", "id": "controller_stocksapi_controller_rationale_39", - "community": 512, + "community": 54, "norm_label": "discover available field names before querying /historical or /fundamental." }, { @@ -4555,7 +4492,7 @@ "label": "health()", "file_type": "code", "source_file": "main/controller/user_controller.py", - "source_location": "L32", + "source_location": "L29", "id": "controller_user_controller_health", "community": 501, "norm_label": "health()" @@ -4564,7 +4501,7 @@ "label": "getMe()", "file_type": "code", "source_file": "main/controller/user_controller.py", - "source_location": "L37", + "source_location": "L34", "id": "controller_user_controller_getme", "community": 501, "norm_label": "getme()" @@ -4573,7 +4510,7 @@ "label": "testAdminAccess()", "file_type": "code", "source_file": "main/controller/user_controller.py", - "source_location": "L42", + "source_location": "L39", "id": "controller_user_controller_testadminaccess", "community": 501, "norm_label": "testadminaccess()" @@ -4582,7 +4519,7 @@ "label": "getSessions()", "file_type": "code", "source_file": "main/controller/user_controller.py", - "source_location": "L50", + "source_location": "L47", "id": "controller_user_controller_getsessions", "community": 501, "norm_label": "getsessions()" @@ -4591,7 +4528,7 @@ "label": "getCurrentSession()", "file_type": "code", "source_file": "main/controller/user_controller.py", - "source_location": "L76", + "source_location": "L73", "id": "controller_user_controller_getcurrentsession", "community": 501, "norm_label": "getcurrentsession()" @@ -4600,7 +4537,7 @@ "label": "revokeSession()", "file_type": "code", "source_file": "main/controller/user_controller.py", - "source_location": "L89", + "source_location": "L86", "id": "controller_user_controller_revokesession", "community": 501, "norm_label": "revokesession()" @@ -4609,7 +4546,7 @@ "label": "revokeAllSessions()", "file_type": "code", "source_file": "main/controller/user_controller.py", - "source_location": "L110", + "source_location": "L107", "id": "controller_user_controller_revokeallsessions", "community": 501, "norm_label": "revokeallsessions()" @@ -4800,7 +4737,7 @@ "source_file": "main/service/authentication_service.py", "source_location": "L1", "id": "main_service_authentication_service_py", - "community": 222, + "community": 215, "norm_label": "authentication_service.py" }, { @@ -4809,7 +4746,7 @@ "source_file": "main/service/authentication_service.py", "source_location": "L9", "id": "service_authentication_service_authenticationservice", - "community": 222, + "community": 215, "norm_label": "authenticationservice" }, { @@ -4818,7 +4755,7 @@ "source_file": "main/service/authentication_service.py", "source_location": "L11", "id": "service_authentication_service_initialize", - "community": 222, + "community": 215, "norm_label": "initialize()" }, { @@ -4827,7 +4764,7 @@ "source_file": "main/service/prometheus_service.py", "source_location": "L1", "id": "main_service_prometheus_service_py", - "community": 500, + "community": 110, "norm_label": "prometheus_service.py" }, { @@ -4854,7 +4791,7 @@ "source_file": "main/service/prometheus_service.py", "source_location": "L67", "id": "service_prometheus_service_initialize", - "community": 500, + "community": 110, "norm_label": "initialize()" }, { @@ -4863,7 +4800,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L1", "id": "main_service_scraper_service_py", - "community": 564, + "community": 72, "norm_label": "scraper_service.py" }, { @@ -4872,7 +4809,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L13", "id": "service_scraper_service_runscraper", - "community": 564, + "community": 72, "norm_label": "runscraper()" }, { @@ -4881,7 +4818,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L23", "id": "service_scraper_service_registerscraperjobs", - "community": 564, + "community": 72, "norm_label": "registerscraperjobs()" }, { @@ -4890,7 +4827,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L49", "id": "service_scraper_service_scraperservice", - "community": 564, + "community": 72, "norm_label": "scraperservice" }, { @@ -4899,7 +4836,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L51", "id": "service_scraper_service_initialize", - "community": 564, + "community": 72, "norm_label": "initialize()" }, { @@ -4908,7 +4845,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L1", "id": "main_service_stocksapi_service_py", - "community": 222, + "community": 215, "norm_label": "stocksapi_service.py" }, { @@ -4917,7 +4854,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L10", "id": "service_stocksapi_service_mcpdetectmiddleware", - "community": 222, + "community": 215, "norm_label": "mcpdetectmiddleware" }, { @@ -4926,7 +4863,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L11", "id": "service_stocksapi_service_mcpdetectmiddleware_init", - "community": 222, + "community": 215, "norm_label": ".__init__()" }, { @@ -4935,7 +4872,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L14", "id": "service_stocksapi_service_mcpdetectmiddleware_call", - "community": 222, + "community": 215, "norm_label": ".__call__()" }, { @@ -4944,7 +4881,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L25", "id": "service_stocksapi_service_stocksapiservice", - "community": 222, + "community": 215, "norm_label": "stocksapiservice" }, { @@ -4953,7 +4890,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L27", "id": "service_stocksapi_service_initialize", - "community": 222, + "community": 215, "norm_label": "initialize()" }, { @@ -4962,7 +4899,7 @@ "source_file": "main/service/user_service.py", "source_location": "L1", "id": "main_service_user_service_py", - "community": 488, + "community": 110, "norm_label": "user_service.py" }, { @@ -4971,7 +4908,7 @@ "source_file": "main/service/user_service.py", "source_location": "L17", "id": "service_user_service_removeinactivesessions", - "community": 488, + "community": 110, "norm_label": "removeinactivesessions()" }, { @@ -4980,7 +4917,7 @@ "source_file": "main/service/user_service.py", "source_location": "L42", "id": "service_user_service_userservice", - "community": 488, + "community": 110, "norm_label": "userservice" }, { @@ -4989,7 +4926,7 @@ "source_file": "main/service/user_service.py", "source_location": "L44", "id": "service_user_service_initialize", - "community": 488, + "community": 110, "norm_label": "initialize()" }, { @@ -4998,23 +4935,23 @@ "source_file": "main/utils/connectivity.py", "source_location": "L1", "id": "main_utils_connectivity_py", - "community": 110, + "community": 491, "norm_label": "connectivity.py" }, { "label": "checkDatabaseConnection()", "file_type": "code", "source_file": "main/utils/connectivity.py", - "source_location": "L12", + "source_location": "L11", "id": "utils_connectivity_checkdatabaseconnection", - "community": 110, + "community": 491, "norm_label": "checkdatabaseconnection()" }, { "label": "checkServiceConnection()", "file_type": "code", "source_file": "main/utils/connectivity.py", - "source_location": "L41", + "source_location": "L40", "id": "utils_connectivity_checkserviceconnection", "community": 59, "norm_label": "checkserviceconnection()" @@ -5140,7 +5077,7 @@ "label": "setupLogging()", "file_type": "code", "source_file": "main/utils/logging_config.py", - "source_location": "L22", + "source_location": "L21", "id": "utils_logging_config_setuplogging", "community": 122, "norm_label": "setuplogging()" @@ -5149,16 +5086,25 @@ "label": "DiscordHandler", "file_type": "code", "source_file": "main/utils/logging_config.py", - "source_location": "L37", + "source_location": "L36", "id": "utils_logging_config_discordhandler", "community": 122, "norm_label": "discordhandler" }, + { + "label": ".__init__()", + "file_type": "code", + "source_file": "main/utils/logging_config.py", + "source_location": "L37", + "id": "utils_logging_config_discordhandler_init", + "community": 122, + "norm_label": ".__init__()" + }, { "label": ".emit()", "file_type": "code", "source_file": "main/utils/logging_config.py", - "source_location": "L38", + "source_location": "L41", "id": "utils_logging_config_discordhandler_emit", "community": 122, "norm_label": ".emit()" @@ -5167,7 +5113,7 @@ "label": "setupDiscordHandler()", "file_type": "code", "source_file": "main/utils/logging_config.py", - "source_location": "L55", + "source_location": "L66", "id": "utils_logging_config_setupdiscordhandler", "community": 122, "norm_label": "setupdiscordhandler()" @@ -5178,7 +5124,7 @@ "source_file": "main/utils/migrator.py", "source_location": "L1", "id": "main_utils_migrator_py", - "community": 110, + "community": 491, "norm_label": "migrator.py" }, { @@ -5187,7 +5133,7 @@ "source_file": "main/utils/migrator.py", "source_location": "L8", "id": "utils_migrator_runmigrations", - "community": 110, + "community": 491, "norm_label": "runmigrations()" }, { @@ -5232,7 +5178,7 @@ "source_file": "main/utils/roles.py", "source_location": "L1", "id": "main_utils_roles_py", - "community": 498, + "community": 131, "norm_label": "roles.py" }, { @@ -5241,7 +5187,7 @@ "source_file": "main/utils/roles.py", "source_location": "L5", "id": "utils_roles_permission", - "community": 498, + "community": 140, "norm_label": "permission" }, { @@ -5277,7 +5223,7 @@ "source_file": "main/utils/roles.py", "source_location": "L29", "id": "utils_roles_checkaccess", - "community": 498, + "community": 131, "norm_label": "checkaccess()" }, { @@ -5286,7 +5232,7 @@ "source_file": "main/utils/roles.py", "source_location": "L42", "id": "utils_roles_requirepermission", - "community": 498, + "community": 131, "norm_label": "requirepermission()" }, { @@ -5295,7 +5241,7 @@ "source_file": "main/utils/scheduler.py", "source_location": "L1", "id": "main_utils_scheduler_py", - "community": 500, + "community": 110, "norm_label": "scheduler.py" }, { @@ -5304,7 +5250,7 @@ "source_file": "main/utils/scheduler.py", "source_location": "L10", "id": "utils_scheduler_getsharedscheduler", - "community": 500, + "community": 110, "norm_label": "getsharedscheduler()" }, { @@ -5313,7 +5259,7 @@ "source_file": "main/utils/scheduler.py", "source_location": "L19", "id": "utils_scheduler_registerjob", - "community": 500, + "community": 110, "norm_label": "registerjob()" }, { @@ -5322,7 +5268,7 @@ "source_file": "main/utils/service_manager.py", "source_location": "L1", "id": "main_utils_service_manager_py", - "community": 222, + "community": 215, "norm_label": "service_manager.py" }, { @@ -5331,7 +5277,7 @@ "source_file": "main/utils/service_manager.py", "source_location": "L19", "id": "utils_service_manager_getapp", - "community": 222, + "community": 215, "norm_label": "getapp()" }, { @@ -5340,7 +5286,7 @@ "source_file": "main/utils/service_manager.py", "source_location": "L43", "id": "utils_service_manager_runall", - "community": 222, + "community": 215, "norm_label": "runall()" }, { @@ -5349,7 +5295,7 @@ "source_file": "main/utils/models/loader.py", "source_location": "L1", "id": "main_utils_models_loader_py", - "community": 541, + "community": 562, "norm_label": "loader.py" }, { @@ -5358,7 +5304,7 @@ "source_file": "main/utils/models/loader.py", "source_location": "L12", "id": "models_loader_getembeddingmodel", - "community": 541, + "community": 562, "norm_label": "getembeddingmodel()" }, { @@ -5910,6 +5856,60 @@ "community": 153, "norm_label": "graphify" }, + { + "label": "PONYTAIL.md", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L1", + "id": "ponytail_md", + "community": 509, + "norm_label": "ponytail.md" + }, + { + "label": "PONYTAIL.md \u2014 proposed cuts, NOT applied. Approve before any edit.", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L1", + "id": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", + "community": 509, + "norm_label": "ponytail.md \u2014 proposed cuts, not applied. approve before any edit." + }, + { + "label": "Proposed (awaiting approval)", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L6", + "id": "server_ponytail_proposed_awaiting_approval", + "community": 509, + "norm_label": "proposed (awaiting approval)" + }, + { + "label": "Disputed (already litigated \u2014 needs your ruling to proceed)", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L64", + "id": "server_ponytail_disputed_already_litigated_needs_your_ruling_to_proceed", + "community": 509, + "norm_label": "disputed (already litigated \u2014 needs your ruling to proceed)" + }, + { + "label": "Held out (your ignore rules \u2014 not proposed)", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L72", + "id": "server_ponytail_held_out_your_ignore_rules_not_proposed", + "community": 509, + "norm_label": "held out (your ignore rules \u2014 not proposed)" + }, + { + "label": "Refused", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L78", + "id": "server_ponytail_refused", + "community": 509, + "norm_label": "refused" + }, { "label": "README.md", "file_type": "document", @@ -5991,6 +5991,87 @@ "community": 163, "norm_label": "license" }, + { + "label": "SWARMS.md", + "file_type": "document", + "source_file": "SWARMS.md", + "source_location": "L1", + "id": "swarms_md", + "community": 263, + "norm_label": "swarms.md" + }, + { + "label": "SWARMS.md \u2014 subagent swarm playbook (OpenCode / Hermes)", + "file_type": "document", + "source_file": "SWARMS.md", + "source_location": "L1", + "id": "server_swarms_swarms_md_subagent_swarm_playbook_opencode_hermes", + "community": 263, + "norm_label": "swarms.md \u2014 subagent swarm playbook (opencode / hermes)" + }, + { + "label": "1. Prime owns the goal, lanes own the work", + "file_type": "document", + "source_file": "SWARMS.md", + "source_location": "L6", + "id": "server_swarms_1_prime_owns_the_goal_lanes_own_the_work", + "community": 263, + "norm_label": "1. prime owns the goal, lanes own the work" + }, + { + "label": "2. Dispatch: `delegate()`, one per lane, one turn", + "file_type": "document", + "source_file": "SWARMS.md", + "source_location": "L12", + "id": "server_swarms_2_dispatch_delegate_one_per_lane_one_turn", + "community": 263, + "norm_label": "2. dispatch: `delegate()`, one per lane, one turn" + }, + { + "label": "3. Delegate toolsets vary \u2014 verify each lane", + "file_type": "document", + "source_file": "SWARMS.md", + "source_location": "L20", + "id": "server_swarms_3_delegate_toolsets_vary_verify_each_lane", + "community": 263, + "norm_label": "3. delegate toolsets vary \u2014 verify each lane" + }, + { + "label": "4. Trust nothing \u2014 verify everything", + "file_type": "document", + "source_file": "SWARMS.md", + "source_location": "L26", + "id": "server_swarms_4_trust_nothing_verify_everything", + "community": 263, + "norm_label": "4. trust nothing \u2014 verify everything" + }, + { + "label": "5. Windows PowerShell survival", + "file_type": "document", + "source_file": "SWARMS.md", + "source_location": "L33", + "id": "server_swarms_5_windows_powershell_survival", + "community": 263, + "norm_label": "5. windows powershell survival" + }, + { + "label": "6. Finish per lane, not per swarm", + "file_type": "document", + "source_file": "SWARMS.md", + "source_location": "L39", + "id": "server_swarms_6_finish_per_lane_not_per_swarm", + "community": 263, + "norm_label": "6. finish per lane, not per swarm" + }, + { + "label": "7. Standing bans (this repo)", + "file_type": "document", + "source_file": "SWARMS.md", + "source_location": "L45", + "id": "server_swarms_7_standing_bans_this_repo", + "community": 263, + "norm_label": "7. standing bans (this repo)" + }, { "label": "TODO.md", "file_type": "document", @@ -6004,7 +6085,7 @@ "label": "User structure defined by string roles:", "file_type": "document", "source_file": "TODO.md", - "source_location": "L29", + "source_location": "L32", "id": "server_todo_user_structure_defined_by_string_roles", "community": 187, "norm_label": "user structure defined by string roles:" @@ -6013,7 +6094,7 @@ "label": "USER:", "file_type": "document", "source_file": "TODO.md", - "source_location": "L38", + "source_location": "L41", "id": "server_todo_user", "community": 187, "norm_label": "user:" @@ -6022,7 +6103,7 @@ "label": "PREMIUM:", "file_type": "document", "source_file": "TODO.md", - "source_location": "L41", + "source_location": "L44", "id": "server_todo_premium", "community": 187, "norm_label": "premium:" @@ -6031,7 +6112,7 @@ "label": "DEVELOPER:", "file_type": "document", "source_file": "TODO.md", - "source_location": "L44", + "source_location": "L47", "id": "server_todo_developer", "community": 187, "norm_label": "developer:" @@ -9285,6 +9366,150 @@ "community": 551, "norm_label": "part 2 \u2014 cache verdict: keep the dict, skip cashews" }, + { + "label": "2026-09-14-memory-postgres-pgvector-plan.md", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L1", + "id": "docs_superpowers_plans_2026_09_14_memory_postgres_pgvector_plan_md", + "community": 181, + "norm_label": "2026-09-14-memory-postgres-pgvector-plan.md" + }, + { + "label": "Memory Postgres-pgvector Migration Implementation Plan", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L1", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_memory_postgres_pgvector_migration_implementation_plan", + "community": 181, + "norm_label": "memory postgres-pgvector migration implementation plan" + }, + { + "label": "Global Constraints", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L13", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_global_constraints", + "community": 181, + "norm_label": "global constraints" + }, + { + "label": "Task 1: pgvector migration + backfill", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L24", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_task_1_pgvector_migration_backfill", + "community": 181, + "norm_label": "task 1: pgvector migration + backfill" + }, + { + "label": "code:python (\"\"\"add embedding vector column.\"\"\")", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L35", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_1", + "community": 181, + "norm_label": "code:python (\"\"\"add embedding vector column.\"\"\")" + }, + { + "label": "code:python (\"\"\"One-shot: embed rows with NULL embedding. Delete after ru)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L65", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_2", + "community": 181, + "norm_label": "code:python (\"\"\"one-shot: embed rows with null embedding. delete after ru)" + }, + { + "label": "code:bash (git add migrations/versions/xxxx_add_embedding_vector.py)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L74", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_3", + "community": 181, + "norm_label": "code:bash (git add migrations/versions/xxxx_add_embedding_vector.py)" + }, + { + "label": "Task 2: delete vector.py, rewrite search()", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L79", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_task_2_delete_vector_py_rewrite_search", + "community": 181, + "norm_label": "task 2: delete vector.py, rewrite search()" + }, + { + "label": "code:python (def searchpgvector(db: Session, userId: int, query: str, lim)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L97", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_4", + "community": 181, + "norm_label": "code:python (def searchpgvector(db: session, userid: int, query: str, lim)" + }, + { + "label": "code:bash (git add main/app/prometheus/memory.py main/app/prometheus/ve)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L134", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_5", + "community": 181, + "norm_label": "code:bash (git add main/app/prometheus/memory.py main/app/prometheus/ve)" + }, + { + "label": "Task 3: update the test files", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L139", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_task_3_update_the_test_files", + "community": 181, + "norm_label": "task 3: update the test files" + }, + { + "label": "code:python (def test_knn_result_shape(dbSession):)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L148", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_6", + "community": 181, + "norm_label": "code:python (def test_knn_result_shape(dbsession):)" + }, + { + "label": "code:bash (git add tests/)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L166", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_7", + "community": 181, + "norm_label": "code:bash (git add tests/)" + }, + { + "label": "Task 4: full test sweep (18 suites, postgres + CI parity)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L171", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_task_4_full_test_sweep_18_suites_postgres_ci_parity", + "community": 181, + "norm_label": "task 4: full test sweep (18 suites, postgres + ci parity)" + }, + { + "label": "Task 5: docs + close", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L185", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_task_5_docs_close", + "community": 181, + "norm_label": "task 5: docs + close" + }, + { + "label": "code:bash (git rm scripts/backfill_embedding_vector.py)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L189", + "id": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_8", + "community": 181, + "norm_label": "code:bash (git rm scripts/backfill_embedding_vector.py)" + }, { "label": "2026-09-04-wallet-design.md", "file_type": "document", @@ -9438,6 +9663,204 @@ "community": 94, "norm_label": "spec self-review" }, + { + "label": "getDeviceName()", + "file_type": "code", + "source_file": "main/app/authentication/session.py", + "source_location": "L14", + "community": 149, + "norm_label": "getdevicename()", + "id": "authentication_session_getdevicename" + }, + { + "label": "walk()", + "file_type": "code", + "source_file": "main/app/stocks_api/compress.py", + "source_location": "L46", + "community": 112, + "norm_label": "walk()", + "id": "stocks_api_compress_walk" + }, + { + "label": "toColumnar()", + "file_type": "code", + "source_file": "main/app/stocks_api/compress.py", + "source_location": "L75", + "community": 112, + "norm_label": "tocolumnar()", + "id": "stocks_api_compress_tocolumnar" + }, + { + "label": "fixHeaders()", + "file_type": "code", + "source_file": "main/app/stocks_api/compress.py", + "source_location": "L84", + "community": 112, + "norm_label": "fixheaders()", + "id": "stocks_api_compress_fixheaders" + }, + { + "label": "StocksQueryManager", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L54", + "community": 63, + "norm_label": "stocksquerymanager", + "id": "stocks_api_query_stocksquerymanager" + }, + { + "label": ".__init__()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L55", + "community": 63, + "norm_label": ".__init__()", + "id": "stocks_api_query_stocksquerymanager_init" + }, + { + "label": ".baseFrame()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L58", + "community": 63, + "norm_label": ".baseframe()", + "id": "stocks_api_query_stocksquerymanager_baseframe" + }, + { + "label": ".finalize()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L69", + "community": 63, + "norm_label": ".finalize()", + "id": "stocks_api_query_stocksquerymanager_finalize" + }, + { + "label": ".deserializeJsonColumns()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L109", + "community": 63, + "norm_label": ".deserializejsoncolumns()", + "id": "stocks_api_query_stocksquerymanager_deserializejsoncolumns" + }, + { + "label": ".filterBySearchTerms()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L136", + "community": 63, + "norm_label": ".filterbysearchterms()", + "id": "stocks_api_query_stocksquerymanager_filterbysearchterms" + }, + { + "label": ".queryHistorical()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L153", + "community": 63, + "norm_label": ".queryhistorical()", + "id": "stocks_api_query_stocksquerymanager_queryhistorical" + }, + { + "label": ".queryFundamental()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L220", + "community": 63, + "norm_label": ".queryfundamental()", + "id": "stocks_api_query_stocksquerymanager_queryfundamental" + }, + { + "label": ".queryCotations()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L284", + "community": 63, + "norm_label": ".querycotations()", + "id": "stocks_api_query_stocksquerymanager_querycotations" + }, + { + "label": ".queryLiveCotation()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L331", + "community": 63, + "norm_label": ".querylivecotation()", + "id": "stocks_api_query_stocksquerymanager_querylivecotation" + }, + { + "label": "getHistoricalFields()", + "file_type": "code", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L89", + "community": 80, + "norm_label": "gethistoricalfields()", + "id": "prometheus_compact_gethistoricalfields" + }, + { + "label": "getFundamentalColumns()", + "file_type": "code", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L93", + "community": 80, + "norm_label": "getfundamentalcolumns()", + "id": "prometheus_compact_getfundamentalcolumns" + }, + { + "label": "invalidateFieldData()", + "file_type": "code", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L97", + "community": 80, + "norm_label": "invalidatefielddata()", + "id": "prometheus_compact_invalidatefielddata" + }, + { + "label": "matrixKey()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L31", + "community": 53, + "norm_label": "matrixkey()", + "id": "prometheus_memory_matrixkey" + }, + { + "label": "matrixUserTag()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L38", + "community": 53, + "norm_label": "matrixusertag()", + "id": "prometheus_memory_matrixusertag" + }, + { + "label": "countTokensCached()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L450", + "community": 53, + "norm_label": "counttokenscached()", + "id": "prometheus_memory_counttokenscached" + }, + { + "label": "sync_cache()", + "file_type": "code", + "source_file": "main/app/stocks_api/sync_cache.py", + "source_location": "L13", + "community": 511, + "norm_label": "sync_cache()", + "id": "stocks_api_sync_cache_sync_cache" + }, + { + "label": "write_bytes()", + "file_type": "code", + "source_file": "main/app/prometheus/sandbox.py", + "source_location": "L194", + "community": 69, + "norm_label": "write_bytes()", + "id": "prometheus_sandbox_write_bytes" + }, { "label": "ensureFastmcp()", "file_type": "code", @@ -9488,7 +9911,7 @@ "file_type": "code", "source_file": "main/app/prometheus/memory.py", "source_location": "L333", - "community": 13, + "community": 53, "norm_label": "searchasync()", "id": "prometheus_memory_searchasync" }, @@ -9515,7 +9938,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L50", - "community": 152, + "community": 90, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_50" }, @@ -9533,7 +9956,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L112", - "community": 101, + "community": 500, "norm_label": "read a file from the workspace. args: path: path to the file (e.", "id": "prometheus_tools_rationale_112" }, @@ -9551,7 +9974,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L142", - "community": 523, + "community": 162, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_142" }, @@ -9605,7 +10028,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L49", - "community": 152, + "community": 90, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_49" }, @@ -9614,7 +10037,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L90", - "community": 101, + "community": 536, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", "id": "prometheus_tools_rationale_90" }, @@ -9623,7 +10046,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L111", - "community": 523, + "community": 500, "norm_label": "read a file from the workspace. args: path: path to the file (e.", "id": "prometheus_tools_rationale_111" }, @@ -9641,7 +10064,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L141", - "community": 523, + "community": 162, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_141" }, @@ -9668,7 +10091,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", - "community": 169, + "community": 54, "norm_label": "jsonbytesresponse", "id": "controller_stocksapi_controller_jsonbytesresponse" }, @@ -9677,7 +10100,7 @@ "file_type": "code", "source_file": "", "source_location": "", - "community": 169, + "community": 54, "norm_label": "fastapiresponse", "id": "fastapiresponse" }, @@ -9686,7 +10109,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L26", - "community": 169, + "community": 54, "norm_label": ".render()", "id": "controller_stocksapi_controller_jsonbytesresponse_render" }, @@ -9695,7 +10118,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L47", - "community": 512, + "community": 54, "norm_label": "discover available field names before querying /historical or /fundamental.", "id": "controller_stocksapi_controller_rationale_47" }, @@ -10523,7 +10946,7 @@ "file_type": "rationale", "source_file": "main/service/scraper_service.py", "source_location": "L23", - "community": 564, + "community": 72, "norm_label": "p5: register the scraper cron jobs on the shared scheduler. kept in this", "id": "service_scraper_service_rationale_23" }, @@ -10532,7 +10955,7 @@ "file_type": "code", "source_file": "main/service/user_service.py", "source_location": "L46", - "community": 488, + "community": 110, "norm_label": "registersessioncleanupjobs()", "id": "service_user_service_registersessioncleanupjobs" }, @@ -10541,7 +10964,7 @@ "file_type": "rationale", "source_file": "main/service/user_service.py", "source_location": "L47", - "community": 488, + "community": 110, "norm_label": "p5: register the session-cleanup job on the shared scheduler. kept in thi", "id": "service_user_service_rationale_47" }, @@ -11675,7 +12098,7 @@ "file_type": "code", "source_file": "main/service/prometheus_service.py", "source_location": "L60", - "community": 500, + "community": 110, "norm_label": "registermemorymaintenancejob()", "id": "service_prometheus_service_registermemorymaintenancejob" }, @@ -11684,7 +12107,7 @@ "file_type": "rationale", "source_file": "main/service/prometheus_service.py", "source_location": "L61", - "community": 500, + "community": 110, "norm_label": "p5: register memory maintenance on the shared scheduler. kept in this ser", "id": "service_prometheus_service_rationale_61" }, @@ -11693,7 +12116,7 @@ "file_type": "rationale", "source_file": "main/utils/scheduler.py", "source_location": "L1", - "community": 500, + "community": 110, "norm_label": "p5: single shared backgroundscheduler for all services. replaces the 4 per-serv", "id": "utils_scheduler_rationale_1" }, @@ -11702,7 +12125,7 @@ "file_type": "rationale", "source_file": "main/utils/scheduler.py", "source_location": "L33", - "community": 500, + "community": 110, "norm_label": "return the process-wide scheduler, starting it on first use.", "id": "utils_scheduler_rationale_33" }, @@ -11711,7 +12134,7 @@ "file_type": "rationale", "source_file": "main/utils/scheduler.py", "source_location": "L43", - "community": 500, + "community": 110, "norm_label": "register func on the shared scheduler (replaces any same-id job). trigger i", "id": "utils_scheduler_rationale_43" }, @@ -11720,7 +12143,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L36", - "community": 512, + "community": 54, "norm_label": "discover available field names before querying /historical or /fundamental.", "id": "controller_stocksapi_controller_rationale_36" }, @@ -11765,7 +12188,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L40", - "community": 512, + "community": 54, "norm_label": "discover available field names before querying /historical or /fundamental.", "id": "controller_stocksapi_controller_rationale_40" }, @@ -11846,7 +12269,7 @@ "file_type": "code", "source_file": "main/app/prometheus/compact.py", "source_location": "L89", - "community": 517, + "community": 544, "norm_label": "fieldregistry", "id": "prometheus_compact_fieldregistry" }, @@ -11855,7 +12278,7 @@ "file_type": "code", "source_file": "main/app/prometheus/compact.py", "source_location": "L94", - "community": 517, + "community": 544, "norm_label": ".buildurl()", "id": "prometheus_compact_fieldregistry_buildurl" }, @@ -11864,7 +12287,7 @@ "file_type": "code", "source_file": "main/app/prometheus/compact.py", "source_location": "L99", - "community": 517, + "community": 544, "norm_label": ".fetchfields()", "id": "prometheus_compact_fieldregistry_fetchfields" }, @@ -11873,7 +12296,7 @@ "file_type": "code", "source_file": "main/app/prometheus/compact.py", "source_location": "L120", - "community": 517, + "community": 544, "norm_label": ".getfields()", "id": "prometheus_compact_fieldregistry_getfields" }, @@ -11882,7 +12305,7 @@ "file_type": "code", "source_file": "main/app/prometheus/compact.py", "source_location": "L127", - "community": 517, + "community": 544, "norm_label": ".buildmetricregex()", "id": "prometheus_compact_fieldregistry_buildmetricregex" }, @@ -11891,7 +12314,7 @@ "file_type": "code", "source_file": "main/app/prometheus/compact.py", "source_location": "L134", - "community": 517, + "community": 544, "norm_label": ".getmetricregex()", "id": "prometheus_compact_fieldregistry_getmetricregex" }, @@ -11900,7 +12323,7 @@ "file_type": "code", "source_file": "main/app/prometheus/compact.py", "source_location": "L222", - "community": 80, + "community": 544, "norm_label": ".__init__()", "id": "prometheus_compact_prometheuscompactor_init" }, @@ -11927,7 +12350,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L54", - "community": 152, + "community": 90, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_54" }, @@ -11945,7 +12368,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L113", - "community": 523, + "community": 500, "norm_label": "read a file from the workspace. args: path: path to the file (e.", "id": "prometheus_tools_rationale_113" }, @@ -11963,7 +12386,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L143", - "community": 523, + "community": 162, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_143" }, @@ -11999,7 +12422,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L48", - "community": 512, + "community": 54, "norm_label": "discover available field names before querying /historical or /fundamental.", "id": "controller_stocksapi_controller_rationale_48" }, @@ -12044,7 +12467,7 @@ "file_type": "code", "source_file": "main/utils/service_manager.py", "source_location": "L15", - "community": 222, + "community": 215, "norm_label": "servicemanager", "id": "utils_service_manager_servicemanager" }, @@ -12206,7 +12629,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L135", - "community": 523, + "community": 162, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_135" }, @@ -12413,7 +12836,7 @@ "file_type": "code", "source_file": "main/app/prometheus/compact.py", "source_location": "L139", - "community": 517, + "community": 544, "norm_label": ".invalidate()", "id": "prometheus_compact_fieldregistry_invalidate" }, @@ -12422,7 +12845,7 @@ "file_type": "code", "source_file": "main/app/prometheus/compact.py", "source_location": "L145", - "community": 517, + "community": 544, "norm_label": ".warmup()", "id": "prometheus_compact_fieldregistry_warmup" }, @@ -12494,7 +12917,7 @@ "file_type": "code", "source_file": "main/app/user/user.py", "source_location": "L22", - "community": 181, + "community": 519, "norm_label": "todict()", "id": "user_user_todict" }, @@ -12503,7 +12926,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L24", - "community": 169, + "community": 54, "norm_label": "sends pre-serialized json bytes without re-encoding (cache-friendly).", "id": "controller_stocksapi_controller_rationale_24" }, @@ -12512,7 +12935,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L49", - "community": 512, + "community": 54, "norm_label": "discover available field names before querying /historical or /fundamental.", "id": "controller_stocksapi_controller_rationale_49" }, @@ -12557,7 +12980,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L1", - "community": 521, + "community": 560, "norm_label": "response_cache.py", "id": "main_app_stocks_api_response_cache_py" }, @@ -12566,7 +12989,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L19", - "community": 521, + "community": 560, "norm_label": "responsecache", "id": "stocks_api_response_cache_responsecache" }, @@ -12575,7 +12998,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L20", - "community": 521, + "community": 560, "norm_label": ".__init__()", "id": "stocks_api_response_cache_responsecache_init" }, @@ -12584,7 +13007,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L29", - "community": 521, + "community": 560, "norm_label": ".makekey()", "id": "stocks_api_response_cache_responsecache_makekey" }, @@ -12593,7 +13016,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L34", - "community": 521, + "community": 560, "norm_label": ".get()", "id": "stocks_api_response_cache_responsecache_get" }, @@ -12602,7 +13025,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/response_cache.py", "source_location": "L51", - "community": 521, + "community": 63, "norm_label": ".set()", "id": "stocks_api_response_cache_responsecache_set" }, @@ -12647,7 +13070,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L323", - "community": 169, + "community": 54, "norm_label": "generatekey()", "id": "controller_stocksapi_controller_generatekey" }, @@ -12656,7 +13079,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L30", - "community": 512, + "community": 54, "norm_label": "discover available field names before querying /historical or /fundamental.", "id": "controller_stocksapi_controller_rationale_30" }, @@ -13385,7 +13808,7 @@ "file_type": "code", "source_file": "main/app/prometheus/compact.py", "source_location": "L94", - "community": 517, + "community": 544, "norm_label": ".__new__()", "id": "prometheus_compact_fieldregistry_new" }, @@ -13403,7 +13826,7 @@ "file_type": "code", "source_file": "main/app/user/user.py", "source_location": "L19", - "community": 181, + "community": 519, "norm_label": "addrole()", "id": "user_user_addrole" }, @@ -13412,7 +13835,7 @@ "file_type": "code", "source_file": "main/app/user/user.py", "source_location": "L28", - "community": 181, + "community": 519, "norm_label": "hasrole()", "id": "user_user_hasrole" }, @@ -13421,7 +13844,7 @@ "file_type": "code", "source_file": "main/app/user/user.py", "source_location": "L44", - "community": 181, + "community": 519, "norm_label": "addroletouser()", "id": "user_user_addroletouser" }, @@ -14420,7 +14843,7 @@ "file_type": "code", "source_file": "main/app/prometheus/state.py", "source_location": "L14", - "community": 21, + "community": 112, "norm_label": ".set()", "id": "prometheus_state_harnessstate_set" }, @@ -14519,7 +14942,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L168", - "community": 523, + "community": 162, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_168" }, @@ -14699,7 +15122,7 @@ "file_type": "code", "source_file": "main/utils/connectivity.py", "source_location": "L13", - "community": 110, + "community": 491, "norm_label": "checksingledb()", "id": "utils_connectivity_checksingledb" }, @@ -14807,7 +15230,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L27", - "community": 512, + "community": 54, "norm_label": "discover available field names before querying /historical or /fundamental.", "id": "controller_stocksapi_controller_rationale_27" }, @@ -15887,7 +16310,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L44", - "community": 152, + "community": 90, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_44" }, @@ -15932,7 +16355,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L159", - "community": 523, + "community": 162, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_159" }, @@ -16634,7 +17057,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L26", - "community": 512, + "community": 54, "norm_label": "discover available field names before querying /historical or /fundamental.", "id": "controller_stocksapi_controller_rationale_26" }, @@ -22097,7 +22520,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L1", - "community": 527, + "community": 251, "norm_label": "conftest.py", "id": "tests_conftest_py" }, @@ -22106,7 +22529,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L13", - "community": 527, + "community": 251, "norm_label": "_reset_rate_limiter()", "id": "tests_conftest_reset_rate_limiter" }, @@ -22115,7 +22538,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L20", - "community": 527, + "community": 251, "norm_label": "pytest_configure()", "id": "tests_conftest_pytest_configure" }, @@ -22124,7 +22547,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L33", - "community": 527, + "community": 251, "norm_label": "_patch_secret_key()", "id": "tests_conftest_patch_secret_key" }, @@ -22133,7 +22556,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L48", - "community": 527, + "community": 251, "norm_label": "dbsession()", "id": "tests_conftest_dbsession" }, @@ -22142,7 +22565,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L60", - "community": 527, + "community": 251, "norm_label": "sampleuserdata()", "id": "tests_conftest_sampleuserdata" }, @@ -22151,7 +22574,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L71", - "community": 527, + "community": 251, "norm_label": "sampleapikeydata()", "id": "tests_conftest_sampleapikeydata" }, @@ -22160,7 +22583,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L76", - "community": 527, + "community": 251, "norm_label": "sampleprometheussessiondata()", "id": "tests_conftest_sampleprometheussessiondata" }, @@ -22169,7 +22592,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L81", - "community": 527, + "community": 251, "norm_label": "stocks_http_client()", "id": "tests_conftest_stocks_http_client" }, @@ -22178,7 +22601,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L106", - "community": 527, + "community": 251, "norm_label": "client()", "id": "tests_conftest_client" }, @@ -22187,7 +22610,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L14", - "community": 527, + "community": 251, "norm_label": "reset slowapi in-memory rate limiter between every test.", "id": "tests_conftest_rationale_14" }, @@ -22196,7 +22619,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L21", - "community": 527, + "community": 251, "norm_label": "set required env vars before test collection. config.py eagerly instantia", "id": "tests_conftest_rationale_21" }, @@ -22205,7 +22628,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L82", - "community": 527, + "community": 251, "norm_label": "testclient with stocks router + verifyapikey + getcurrentuser overrides.", "id": "tests_conftest_rationale_82" }, @@ -22214,7 +22637,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L107", - "community": 527, + "community": 251, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_107" }, @@ -22322,7 +22745,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L7", - "community": 8, + "community": 529, "norm_label": "testbuildsystempromptstate", "id": "tests_test_agent_state_integration_testbuildsystempromptstate" }, @@ -22331,7 +22754,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L8", - "community": 8, + "community": 529, "norm_label": ".test_build_system_prompt_no_state()", "id": "tests_test_agent_state_integration_testbuildsystempromptstate_test_build_system_prompt_no_state" }, @@ -22340,7 +22763,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L13", - "community": 8, + "community": 529, "norm_label": ".test_build_system_prompt_with_state()", "id": "tests_test_agent_state_integration_testbuildsystempromptstate_test_build_system_prompt_with_state" }, @@ -22349,7 +22772,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L21", - "community": 8, + "community": 529, "norm_label": ".test_build_system_prompt_empty_state()", "id": "tests_test_agent_state_integration_testbuildsystempromptstate_test_build_system_prompt_empty_state" }, @@ -22358,7 +22781,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L27", - "community": 8, + "community": 529, "norm_label": ".test_build_system_prompt_state_after_memories()", "id": "tests_test_agent_state_integration_testbuildsystempromptstate_test_build_system_prompt_state_after_memories" }, @@ -22367,7 +22790,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L37", - "community": 8, + "community": 529, "norm_label": ".test_build_system_prompt_multiple_state_entries()", "id": "tests_test_agent_state_integration_testbuildsystempromptstate_test_build_system_prompt_multiple_state_entries" }, @@ -22448,7 +22871,7 @@ "file_type": "rationale", "source_file": "tests/test_agent_state_integration.py", "source_location": "L9", - "community": 8, + "community": 529, "norm_label": "system prompt should work without state parameter.", "id": "tests_test_agent_state_integration_rationale_9" }, @@ -22457,7 +22880,7 @@ "file_type": "rationale", "source_file": "tests/test_agent_state_integration.py", "source_location": "L14", - "community": 8, + "community": 529, "norm_label": "system prompt should include state context when provided.", "id": "tests_test_agent_state_integration_rationale_14" }, @@ -22466,7 +22889,7 @@ "file_type": "rationale", "source_file": "tests/test_agent_state_integration.py", "source_location": "L22", - "community": 8, + "community": 529, "norm_label": "system prompt should not include state section when empty.", "id": "tests_test_agent_state_integration_rationale_22" }, @@ -22475,7 +22898,7 @@ "file_type": "rationale", "source_file": "tests/test_agent_state_integration.py", "source_location": "L28", - "community": 8, + "community": 529, "norm_label": "state section should appear after memories section.", "id": "tests_test_agent_state_integration_rationale_28" }, @@ -22484,7 +22907,7 @@ "file_type": "rationale", "source_file": "tests/test_agent_state_integration.py", "source_location": "L38", - "community": 8, + "community": 529, "norm_label": "all state entries should appear in the prompt.", "id": "tests_test_agent_state_integration_rationale_38" }, @@ -22628,7 +23051,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L220", - "community": 90, + "community": 136, "norm_label": "testverifyapikeyintegration", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration" }, @@ -22637,7 +23060,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L223", - "community": 90, + "community": 136, "norm_label": ".test_verify_api_key_success()", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration_test_verify_api_key_success" }, @@ -22646,7 +23069,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L238", - "community": 90, + "community": 136, "norm_label": ".test_verify_api_key_quota_exceeded()", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration_test_verify_api_key_quota_exceeded" }, @@ -22655,7 +23078,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L253", - "community": 90, + "community": 136, "norm_label": ".test_verify_api_key_invalid()", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration_test_verify_api_key_invalid" }, @@ -22664,7 +23087,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L264", - "community": 90, + "community": 136, "norm_label": ".test_verify_api_key_missing()", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration_test_verify_api_key_missing" }, @@ -22673,7 +23096,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L275", - "community": 90, + "community": 136, "norm_label": ".test_verify_api_key_disabled()", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration_test_verify_api_key_disabled" }, @@ -22772,7 +23195,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L221", - "community": 90, + "community": 136, "norm_label": "integration tests for the verifyapikey function.", "id": "tests_test_api_key_quota_atomic_rationale_221" }, @@ -22781,7 +23204,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L224", - "community": 90, + "community": 136, "norm_label": "test successful api key verification.", "id": "tests_test_api_key_quota_atomic_rationale_224" }, @@ -22790,7 +23213,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L239", - "community": 90, + "community": 136, "norm_label": "test api key verification when quota is exceeded.", "id": "tests_test_api_key_quota_atomic_rationale_239" }, @@ -22799,7 +23222,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L254", - "community": 90, + "community": 136, "norm_label": "test api key verification with invalid key.", "id": "tests_test_api_key_quota_atomic_rationale_254" }, @@ -22808,7 +23231,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L265", - "community": 90, + "community": 136, "norm_label": "test api key verification with missing key.", "id": "tests_test_api_key_quota_atomic_rationale_265" }, @@ -22817,7 +23240,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L276", - "community": 90, + "community": 136, "norm_label": "test that api key system can be disabled.", "id": "tests_test_api_key_quota_atomic_rationale_276" }, @@ -23015,7 +23438,7 @@ "file_type": "code", "source_file": "tests/test_config.py", "source_location": "L1", - "community": 215, + "community": 541, "norm_label": "test_config.py", "id": "tests_test_config_py" }, @@ -23168,7 +23591,7 @@ "file_type": "code", "source_file": "tests/test_connectivity_coverage.py", "source_location": "L114", - "community": 562, + "community": 564, "norm_label": "testcheckserviceconnection", "id": "tests_test_connectivity_coverage_testcheckserviceconnection" }, @@ -23267,7 +23690,7 @@ "file_type": "rationale", "source_file": "tests/test_connectivity_coverage.py", "source_location": "L115", - "community": 562, + "community": 564, "norm_label": "checkserviceconnection \u2014 success, not found, errors.", "id": "tests_test_connectivity_coverage_rationale_115" }, @@ -23303,7 +23726,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L57", - "community": 99, + "community": 16, "norm_label": "_make_prometheus_client()", "id": "tests_test_controllers_coverage_make_prometheus_client" }, @@ -23447,7 +23870,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L257", - "community": 498, + "community": 120, "norm_label": "testlogoutendpoint", "id": "tests_test_controllers_coverage_testlogoutendpoint" }, @@ -23816,7 +24239,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L849", - "community": 99, + "community": 16, "norm_label": "testprometheusgetsessions", "id": "tests_test_controllers_coverage_testprometheusgetsessions" }, @@ -23825,7 +24248,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L852", - "community": 99, + "community": 16, "norm_label": ".test_get_sessions()", "id": "tests_test_controllers_coverage_testprometheusgetsessions_test_get_sessions" }, @@ -23834,7 +24257,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L867", - "community": 99, + "community": 16, "norm_label": "testprometheuscreatesession", "id": "tests_test_controllers_coverage_testprometheuscreatesession" }, @@ -23843,7 +24266,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L870", - "community": 99, + "community": 16, "norm_label": ".test_create_session()", "id": "tests_test_controllers_coverage_testprometheuscreatesession_test_create_session" }, @@ -23915,7 +24338,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L997", - "community": 474, + "community": 231, "norm_label": "testprometheusdeletesession", "id": "tests_test_controllers_coverage_testprometheusdeletesession" }, @@ -23924,7 +24347,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1000", - "community": 474, + "community": 231, "norm_label": ".test_delete_session_success()", "id": "tests_test_controllers_coverage_testprometheusdeletesession_test_delete_session_success" }, @@ -23933,7 +24356,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1010", - "community": 474, + "community": 231, "norm_label": ".test_delete_session_not_found()", "id": "tests_test_controllers_coverage_testprometheusdeletesession_test_delete_session_not_found" }, @@ -23951,7 +24374,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1023", - "community": 99, + "community": 16, "norm_label": ".test_chat_new_session()", "id": "tests_test_controllers_coverage_testprometheuschat_test_chat_new_session" }, @@ -23960,7 +24383,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1042", - "community": 16, + "community": 104, "norm_label": ".test_chat_existing_session_verified()", "id": "tests_test_controllers_coverage_testprometheuschat_test_chat_existing_session_verified" }, @@ -23987,7 +24410,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1144", - "community": 498, + "community": 539, "norm_label": "teststocksapihealth", "id": "tests_test_controllers_coverage_teststocksapihealth" }, @@ -23996,7 +24419,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1147", - "community": 498, + "community": 539, "norm_label": ".test_health()", "id": "tests_test_controllers_coverage_teststocksapihealth_test_health" }, @@ -24005,7 +24428,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1158", - "community": 14, + "community": 563, "norm_label": "teststocksapihistorical", "id": "tests_test_controllers_coverage_teststocksapihistorical" }, @@ -24014,7 +24437,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1161", - "community": 14, + "community": 563, "norm_label": ".test_get_historical()", "id": "tests_test_controllers_coverage_teststocksapihistorical_test_get_historical" }, @@ -24023,7 +24446,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1172", - "community": 503, + "community": 14, "norm_label": "teststocksapifundamental", "id": "tests_test_controllers_coverage_teststocksapifundamental" }, @@ -24032,7 +24455,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1175", - "community": 503, + "community": 14, "norm_label": ".test_get_fundamental()", "id": "tests_test_controllers_coverage_teststocksapifundamental_test_get_fundamental" }, @@ -24212,7 +24635,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1410", - "community": 519, + "community": 524, "norm_label": ".test_invalid_token()", "id": "tests_test_controllers_coverage_testverifyaccesstoken_test_invalid_token" }, @@ -24221,7 +24644,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1422", - "community": 498, + "community": 114, "norm_label": "testextracttokenpayloadreraise", "id": "tests_test_controllers_coverage_testextracttokenpayloadreraise" }, @@ -24284,7 +24707,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L58", - "community": 99, + "community": 16, "norm_label": "return (client, app) with prometheus router and mocked deps.", "id": "tests_test_controllers_coverage_rationale_58" }, @@ -24392,7 +24815,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L258", - "community": 498, + "community": 120, "norm_label": "covers lines 107, 109-130, 133: logout token extraction and revocation.", "id": "tests_test_controllers_coverage_rationale_258" }, @@ -24410,7 +24833,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L281", - "community": 498, + "community": 120, "norm_label": "covers lines 111-113: token extracted from authorization bearer header.", "id": "tests_test_controllers_coverage_rationale_281" }, @@ -24680,7 +25103,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L850", - "community": 99, + "community": 16, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_850" }, @@ -24689,7 +25112,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L868", - "community": 99, + "community": 16, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_868" }, @@ -24761,7 +25184,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L998", - "community": 474, + "community": 231, "norm_label": "covers lines 95-98: delete /prometheus/sessions/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_998" }, @@ -24770,7 +25193,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1001", - "community": 474, + "community": 231, "norm_label": "covers lines 95-98: session deleted.", "id": "tests_test_controllers_coverage_rationale_1001" }, @@ -24779,7 +25202,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1011", - "community": 474, + "community": 231, "norm_label": "covers lines 96-97: session not found.", "id": "tests_test_controllers_coverage_rationale_1011" }, @@ -24797,7 +25220,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1024", - "community": 99, + "community": 16, "norm_label": "covers lines 118-119: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1024" }, @@ -24806,7 +25229,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1043", - "community": 16, + "community": 104, "norm_label": "covers lines 120-121: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1043" }, @@ -24833,7 +25256,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1145", - "community": 498, + "community": 539, "norm_label": "covers line 18: get /stocks/health.", "id": "tests_test_controllers_coverage_rationale_1145" }, @@ -24842,7 +25265,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1159", - "community": 14, + "community": 563, "norm_label": "covers line 35: get /stocks/historical.", "id": "tests_test_controllers_coverage_rationale_1159" }, @@ -24851,7 +25274,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1173", - "community": 503, + "community": 14, "norm_label": "covers line 47: get /stocks/fundamental.", "id": "tests_test_controllers_coverage_rationale_1173" }, @@ -25013,7 +25436,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1411", - "community": 519, + "community": 524, "norm_label": "covers lines 50-51: jwt.invalidtokenerror.", "id": "tests_test_controllers_coverage_rationale_1411" }, @@ -25022,7 +25445,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1423", - "community": 498, + "community": 114, "norm_label": "covers line 67: extracttokenpayload re-raises httpexception from verifyaccesstok", "id": "tests_test_controllers_coverage_rationale_1423" }, @@ -25616,7 +26039,7 @@ "file_type": "code", "source_file": "tests/test_error_handlers.py", "source_location": "L25", - "community": 120, + "community": 104, "norm_label": "app()", "id": "tests_test_error_handlers_app" }, @@ -25904,7 +26327,7 @@ "file_type": "code", "source_file": "tests/test_harness_state.py", "source_location": "L1", - "community": 215, + "community": 541, "norm_label": "test_harness_state.py", "id": "tests_test_harness_state_py" }, @@ -26012,7 +26435,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L1", - "community": 251, + "community": 541, "norm_label": "test_http_session_coverage.py", "id": "tests_test_http_session_coverage_py" }, @@ -26021,7 +26444,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L8", - "community": 251, + "community": 541, "norm_label": "testgetsession", "id": "tests_test_http_session_coverage_testgetsession" }, @@ -26030,7 +26453,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L9", - "community": 251, + "community": 541, "norm_label": ".test_returns_same_session()", "id": "tests_test_http_session_coverage_testgetsession_test_returns_same_session" }, @@ -26039,7 +26462,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L16", - "community": 251, + "community": 541, "norm_label": ".test_returns_requests_session()", "id": "tests_test_http_session_coverage_testgetsession_test_returns_requests_session" }, @@ -26048,7 +26471,7 @@ "file_type": "rationale", "source_file": "tests/test_http_session_coverage.py", "source_location": "L1", - "community": 251, + "community": 541, "norm_label": "tests for main/utils/http_session.py \u2014 covers all branches.", "id": "tests_test_http_session_coverage_rationale_1" }, @@ -26156,7 +26579,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L80", - "community": 560, + "community": 25, "norm_label": "testprometheussessionvalidation", "id": "tests_test_input_validation_testprometheussessionvalidation" }, @@ -26165,7 +26588,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L83", - "community": 560, + "community": 25, "norm_label": ".test_valid_create_session()", "id": "tests_test_input_validation_testprometheussessionvalidation_test_valid_create_session" }, @@ -26174,7 +26597,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L92", - "community": 560, + "community": 25, "norm_label": ".test_empty_title()", "id": "tests_test_input_validation_testprometheussessionvalidation_test_empty_title" }, @@ -26183,7 +26606,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L100", - "community": 560, + "community": 25, "norm_label": ".test_title_too_long()", "id": "tests_test_input_validation_testprometheussessionvalidation_test_title_too_long" }, @@ -26219,7 +26642,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L129", - "community": 544, + "community": 25, "norm_label": "testchatvalidation", "id": "tests_test_input_validation_testchatvalidation" }, @@ -26228,7 +26651,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L132", - "community": 544, + "community": 25, "norm_label": ".test_empty_text()", "id": "tests_test_input_validation_testchatvalidation_test_empty_text" }, @@ -26237,7 +26660,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L140", - "community": 544, + "community": 25, "norm_label": ".test_text_too_long()", "id": "tests_test_input_validation_testchatvalidation_test_text_too_long" }, @@ -26246,7 +26669,7 @@ "file_type": "code", "source_file": "tests/test_input_validation.py", "source_location": "L148", - "community": 544, + "community": 25, "norm_label": ".test_max_length_boundary()", "id": "tests_test_input_validation_testchatvalidation_test_max_length_boundary" }, @@ -26318,7 +26741,7 @@ "file_type": "rationale", "source_file": "tests/test_input_validation.py", "source_location": "L81", - "community": 560, + "community": 25, "norm_label": "post /prometheus/sessions \u2014 validates title via body(...)", "id": "tests_test_input_validation_rationale_81" }, @@ -26336,7 +26759,7 @@ "file_type": "rationale", "source_file": "tests/test_input_validation.py", "source_location": "L130", - "community": 544, + "community": 25, "norm_label": "post /prometheus/chat/stream \u2014 validates query via body(...)", "id": "tests_test_input_validation_rationale_130" }, @@ -26453,7 +26876,7 @@ "file_type": "code", "source_file": "tests/test_logging_config_coverage.py", "source_location": "L103", - "community": 122, + "community": 188, "norm_label": "testsetuplogging", "id": "tests_test_logging_config_coverage_testsetuplogging" }, @@ -26489,7 +26912,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L1", - "community": 140, + "community": 137, "norm_label": "test_memory_dedup.py", "id": "tests_test_memory_dedup_py" }, @@ -26498,7 +26921,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L8", - "community": 126, + "community": 137, "norm_label": "_create_memory()", "id": "tests_test_memory_dedup_create_memory" }, @@ -26507,7 +26930,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L12", - "community": 126, + "community": 137, "norm_label": "_count_memories()", "id": "tests_test_memory_dedup_count_memories" }, @@ -26516,7 +26939,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L20", - "community": 126, + "community": 137, "norm_label": "_get_memory()", "id": "tests_test_memory_dedup_get_memory" }, @@ -26525,7 +26948,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L28", - "community": 140, + "community": 137, "norm_label": "testexactsamekeyupdates", "id": "tests_test_memory_dedup_testexactsamekeyupdates" }, @@ -26534,7 +26957,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L29", - "community": 126, + "community": 137, "norm_label": ".test_exact_same_key_updates()", "id": "tests_test_memory_dedup_testexactsamekeyupdates_test_exact_same_key_updates" }, @@ -26552,7 +26975,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L37", - "community": 126, + "community": 137, "norm_label": ".test_similar_key_merges()", "id": "tests_test_memory_dedup_testsimilarkeymerges_test_similar_key_merges" }, @@ -26570,7 +26993,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L47", - "community": 126, + "community": 137, "norm_label": ".test_different_keys_no_merge()", "id": "tests_test_memory_dedup_testdifferentkeysnomerge_test_different_keys_no_merge" }, @@ -26579,7 +27002,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L55", - "community": 140, + "community": 137, "norm_label": "testmergeboostsscore", "id": "tests_test_memory_dedup_testmergeboostsscore" }, @@ -26588,7 +27011,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L56", - "community": 126, + "community": 137, "norm_label": ".test_merge_boosts_score()", "id": "tests_test_memory_dedup_testmergeboostsscore_test_merge_boosts_score" }, @@ -26597,7 +27020,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L64", - "community": 140, + "community": 137, "norm_label": "testmergeincrementsaccess", "id": "tests_test_memory_dedup_testmergeincrementsaccess" }, @@ -26606,7 +27029,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L65", - "community": 126, + "community": 137, "norm_label": ".test_merge_increments_access()", "id": "tests_test_memory_dedup_testmergeincrementsaccess_test_merge_increments_access" }, @@ -26624,7 +27047,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L74", - "community": 126, + "community": 137, "norm_label": ".test_threshold_boundary()", "id": "tests_test_memory_dedup_testthresholdboundary_test_threshold_boundary" }, @@ -26633,7 +27056,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L38", - "community": 126, + "community": 137, "norm_label": "keys with jaccard > 0.8 should merge.", "id": "tests_test_memory_dedup_rationale_38" }, @@ -26642,7 +27065,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L48", - "community": 126, + "community": 137, "norm_label": "keys with low similarity should not merge.", "id": "tests_test_memory_dedup_rationale_48" }, @@ -26651,7 +27074,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L75", - "community": 126, + "community": 137, "norm_label": "keys with jaccard <= 0.8 should not merge.", "id": "tests_test_memory_dedup_rationale_75" }, @@ -26660,7 +27083,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L1", - "community": 54, + "community": 518, "norm_label": "test_memory_maintenance.py", "id": "tests_test_memory_maintenance_py" }, @@ -26669,7 +27092,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L18", - "community": 54, + "community": 518, "norm_label": "brt()", "id": "tests_test_memory_maintenance_brt" }, @@ -26678,7 +27101,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L23", - "community": 54, + "community": 518, "norm_label": "create_memories()", "id": "tests_test_memory_maintenance_create_memories" }, @@ -26687,7 +27110,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L46", - "community": 54, + "community": 518, "norm_label": "testdecay", "id": "tests_test_memory_maintenance_testdecay" }, @@ -26696,7 +27119,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L47", - "community": 54, + "community": 518, "norm_label": ".test_active_memory_decays()", "id": "tests_test_memory_maintenance_testdecay_test_active_memory_decays" }, @@ -26705,7 +27128,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L54", - "community": 54, + "community": 518, "norm_label": ".test_zero_access_count_still_decays()", "id": "tests_test_memory_maintenance_testdecay_test_zero_access_count_still_decays" }, @@ -26714,7 +27137,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L61", - "community": 54, + "community": 518, "norm_label": ".test_high_score_decays_proportionally()", "id": "tests_test_memory_maintenance_testdecay_test_high_score_decays_proportionally" }, @@ -26723,7 +27146,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L67", - "community": 54, + "community": 518, "norm_label": ".test_very_low_score_stays_above_zero()", "id": "tests_test_memory_maintenance_testdecay_test_very_low_score_stays_above_zero" }, @@ -26732,7 +27155,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L74", - "community": 54, + "community": 518, "norm_label": ".test_multiple_users_all_decayed()", "id": "tests_test_memory_maintenance_testdecay_test_multiple_users_all_decayed" }, @@ -26741,7 +27164,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L84", - "community": 54, + "community": 518, "norm_label": "testarchive", "id": "tests_test_memory_maintenance_testarchive" }, @@ -26750,7 +27173,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L85", - "community": 54, + "community": 518, "norm_label": ".test_dead_memory_archived()", "id": "tests_test_memory_maintenance_testarchive_test_dead_memory_archived" }, @@ -26759,7 +27182,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L92", - "community": 54, + "community": 518, "norm_label": ".test_low_score_but_recent_not_archived()", "id": "tests_test_memory_maintenance_testarchive_test_low_score_but_recent_not_archived" }, @@ -26768,7 +27191,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L99", - "community": 54, + "community": 518, "norm_label": ".test_zero_access_but_high_score_not_archived()", "id": "tests_test_memory_maintenance_testarchive_test_zero_access_but_high_score_not_archived" }, @@ -26777,7 +27200,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L106", - "community": 54, + "community": 518, "norm_label": ".test_accessed_memory_not_archived()", "id": "tests_test_memory_maintenance_testarchive_test_accessed_memory_not_archived" }, @@ -26786,7 +27209,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L113", - "community": 54, + "community": 518, "norm_label": ".test_already_archived_not_double_archived()", "id": "tests_test_memory_maintenance_testarchive_test_already_archived_not_double_archived" }, @@ -26795,7 +27218,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L123", - "community": 54, + "community": 518, "norm_label": ".test_multiple_users_independent_archive()", "id": "tests_test_memory_maintenance_testarchive_test_multiple_users_independent_archive" }, @@ -26804,7 +27227,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L133", - "community": 54, + "community": 234, "norm_label": "testdecayandarchivetogether", "id": "tests_test_memory_maintenance_testdecayandarchivetogether" }, @@ -26813,7 +27236,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L134", - "community": 54, + "community": 234, "norm_label": ".test_decay_then_archive_check()", "id": "tests_test_memory_maintenance_testdecayandarchivetogether_test_decay_then_archive_check" }, @@ -26822,7 +27245,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L143", - "community": 54, + "community": 234, "norm_label": ".test_score_above_threshold_after_decay_not_archived()", "id": "tests_test_memory_maintenance_testdecayandarchivetogether_test_score_above_threshold_after_decay_not_archived" }, @@ -26831,7 +27254,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L150", - "community": 54, + "community": 234, "norm_label": ".test_score_just_below_threshold_archived()", "id": "tests_test_memory_maintenance_testdecayandarchivetogether_test_score_just_below_threshold_archived" }, @@ -26840,7 +27263,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L156", - "community": 54, + "community": 234, "norm_label": ".test_days_just_below_threshold_not_archived()", "id": "tests_test_memory_maintenance_testdecayandarchivetogether_test_days_just_below_threshold_not_archived" }, @@ -26849,7 +27272,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L163", - "community": 54, + "community": 234, "norm_label": ".test_days_just_above_threshold_archived()", "id": "tests_test_memory_maintenance_testdecayandarchivetogether_test_days_just_above_threshold_archived" }, @@ -26876,7 +27299,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L24", - "community": 54, + "community": 518, "norm_label": "helper to create memories with controlled basescore, lastaccessedat, accesscount", "id": "tests_test_memory_maintenance_rationale_24" }, @@ -26885,7 +27308,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L55", - "community": 54, + "community": 518, "norm_label": "decay applies to all active memories, not just accessed ones.", "id": "tests_test_memory_maintenance_rationale_55" }, @@ -26894,7 +27317,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L68", - "community": 54, + "community": 518, "norm_label": "basescore should never reach exactly 0 from decay alone.", "id": "tests_test_memory_maintenance_rationale_68" }, @@ -26903,7 +27326,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L86", - "community": 54, + "community": 518, "norm_label": "score below threshold + accesscount=0 + 90+ days \u2192 archived.", "id": "tests_test_memory_maintenance_rationale_86" }, @@ -26912,7 +27335,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L93", - "community": 54, + "community": 518, "norm_label": "low score but accessed recently \u2192 not archived.", "id": "tests_test_memory_maintenance_rationale_93" }, @@ -26921,7 +27344,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L100", - "community": 54, + "community": 518, "norm_label": "zero access but score still above threshold \u2192 not archived.", "id": "tests_test_memory_maintenance_rationale_100" }, @@ -26930,7 +27353,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L107", - "community": 54, + "community": 518, "norm_label": "even with low score, if accessed \u2192 not archived.", "id": "tests_test_memory_maintenance_rationale_107" }, @@ -26939,7 +27362,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L114", - "community": 54, + "community": 518, "norm_label": "already archived memories are skipped.", "id": "tests_test_memory_maintenance_rationale_114" }, @@ -26948,7 +27371,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L135", - "community": 54, + "community": 234, "norm_label": "decay happens first, then archive check with new scores.", "id": "tests_test_memory_maintenance_rationale_135" }, @@ -26957,7 +27380,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L144", - "community": 54, + "community": 234, "norm_label": "score that decays to >= threshold stays alive. 0.12 * 0.90 = 0.108 >= 0.1.", "id": "tests_test_memory_maintenance_rationale_144" }, @@ -26966,7 +27389,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L157", - "community": 54, + "community": 234, "norm_label": "89 days with low score \u2192 not archived (need > 90).", "id": "tests_test_memory_maintenance_rationale_157" }, @@ -26993,7 +27416,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L9", - "community": 571, + "community": 140, "norm_label": ".test_basic_user()", "id": "tests_test_memory_manager_testgetmemorylimit_test_basic_user" }, @@ -27011,7 +27434,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L15", - "community": 575, + "community": 574, "norm_label": ".test_admin_user()", "id": "tests_test_memory_manager_testgetmemorylimit_test_admin_user" }, @@ -27029,7 +27452,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L20", - "community": 140, + "community": 575, "norm_label": ".test_create()", "id": "tests_test_memory_manager_testupsertmemory_test_create" }, @@ -27047,7 +27470,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L40", - "community": 576, + "community": 140, "norm_label": ".test_unchanged()", "id": "tests_test_memory_manager_testupsertmemory_test_unchanged" }, @@ -27065,7 +27488,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L59", - "community": 578, + "community": 140, "norm_label": ".test_limit_not_enforced_without_roles()", "id": "tests_test_memory_manager_testupsertmemory_test_limit_not_enforced_without_roles" }, @@ -27074,7 +27497,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L66", - "community": 579, + "community": 140, "norm_label": ".test_upsert_with_embedding()", "id": "tests_test_memory_manager_testupsertmemory_test_upsert_with_embedding" }, @@ -27101,7 +27524,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L86", - "community": 140, + "community": 576, "norm_label": ".test_excludes_archived()", "id": "tests_test_memory_manager_testcountmemories_test_excludes_archived" }, @@ -27128,7 +27551,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L102", - "community": 570, + "community": 140, "norm_label": ".test_returns_memories()", "id": "tests_test_memory_manager_testgetusermemories_test_returns_memories" }, @@ -27137,7 +27560,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L109", - "community": 572, + "community": 140, "norm_label": ".test_pagination()", "id": "tests_test_memory_manager_testgetusermemories_test_pagination" }, @@ -27146,7 +27569,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L115", - "community": 573, + "community": 140, "norm_label": ".test_excludes_archived()", "id": "tests_test_memory_manager_testgetusermemories_test_excludes_archived" }, @@ -27164,7 +27587,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L126", - "community": 574, + "community": 140, "norm_label": ".test_soft_delete()", "id": "tests_test_memory_manager_testdeletememory_test_soft_delete" }, @@ -27290,7 +27713,7 @@ "file_type": "code", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L60", - "community": 21, + "community": 112, "norm_label": ".test_memory_tool_names_unchanged()", "id": "tests_test_memory_tools_wiring_testmemorytoolfunctions_test_memory_tool_names_unchanged" }, @@ -27299,7 +27722,7 @@ "file_type": "code", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L64", - "community": 49, + "community": 569, "norm_label": "testtoolregistry", "id": "tests_test_memory_tools_wiring_testtoolregistry" }, @@ -27308,7 +27731,7 @@ "file_type": "code", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L67", - "community": 49, + "community": 569, "norm_label": ".test_registry_contains_memory_tools()", "id": "tests_test_memory_tools_wiring_testtoolregistry_test_registry_contains_memory_tools" }, @@ -27317,7 +27740,7 @@ "file_type": "code", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L71", - "community": 49, + "community": 569, "norm_label": ".test_registry_values_are_callable()", "id": "tests_test_memory_tools_wiring_testtoolregistry_test_registry_values_are_callable" }, @@ -27326,7 +27749,7 @@ "file_type": "code", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L75", - "community": 49, + "community": 569, "norm_label": ".test_registry_matches_tool_names()", "id": "tests_test_memory_tools_wiring_testtoolregistry_test_registry_matches_tool_names" }, @@ -27335,7 +27758,7 @@ "file_type": "code", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L79", - "community": 487, + "community": 573, "norm_label": "testmakechatincludesmemorytools", "id": "tests_test_memory_tools_wiring_testmakechatincludesmemorytools" }, @@ -27353,7 +27776,7 @@ "file_type": "code", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L112", - "community": 487, + "community": 571, "norm_label": "testdispatchroutesmemorytools", "id": "tests_test_memory_tools_wiring_testdispatchroutesmemorytools" }, @@ -27407,7 +27830,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L65", - "community": 49, + "community": 569, "norm_label": "tool_registry pattern must work correctly.", "id": "tests_test_memory_tools_wiring_rationale_65" }, @@ -27416,7 +27839,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L80", - "community": 487, + "community": 573, "norm_label": "makechat must include memory_tools alongside mcp sessions.", "id": "tests_test_memory_tools_wiring_rationale_80" }, @@ -27425,7 +27848,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L113", - "community": 487, + "community": 571, "norm_label": "dispatchtoolcall must route memory tool names via tool_registry.", "id": "tests_test_memory_tools_wiring_rationale_113" }, @@ -28829,7 +29252,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L44", - "community": 231, + "community": 487, "norm_label": "testmemorytoolfunctions", "id": "tests_test_prometheus_tools_testmemorytoolfunctions" }, @@ -28838,7 +29261,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L45", - "community": 231, + "community": 487, "norm_label": ".test_search_memory_has_docstring()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_search_memory_has_docstring" }, @@ -28847,7 +29270,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L49", - "community": 231, + "community": 487, "norm_label": ".test_save_memory_has_docstring()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_save_memory_has_docstring" }, @@ -28856,7 +29279,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L53", - "community": 231, + "community": 487, "norm_label": ".test_search_memory_signature()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_search_memory_signature" }, @@ -28865,7 +29288,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L59", - "community": 231, + "community": 487, "norm_label": ".test_save_memory_signature()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_save_memory_signature" }, @@ -28874,7 +29297,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L66", - "community": 231, + "community": 487, "norm_label": ".test_search_memory_has_type_hints()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_search_memory_has_type_hints" }, @@ -28883,7 +29306,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L71", - "community": 231, + "community": 487, "norm_label": ".test_save_memory_has_type_hints()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_save_memory_has_type_hints" }, @@ -28892,7 +29315,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L77", - "community": 231, + "community": 487, "norm_label": ".test_memory_tools_is_list_of_callables()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_memory_tools_is_list_of_callables" }, @@ -28901,7 +29324,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L83", - "community": 231, + "community": 487, "norm_label": ".test_memory_tool_names_unchanged()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_memory_tool_names_unchanged" }, @@ -28991,7 +29414,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L126", - "community": 100, + "community": 572, "norm_label": "testgeminicompatibility", "id": "tests_test_prometheus_tools_testgeminicompatibility" }, @@ -29009,7 +29432,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L135", - "community": 100, + "community": 572, "norm_label": ".test_no_harnessstate_in_any_signature()", "id": "tests_test_prometheus_tools_testgeminicompatibility_test_no_harnessstate_in_any_signature" }, @@ -29063,7 +29486,7 @@ "file_type": "rationale", "source_file": "tests/test_prometheus_tools.py", "source_location": "L127", - "community": 100, + "community": 572, "norm_label": "every function in tool_registry must have gemini-safe signatures. custom cl", "id": "tests_test_prometheus_tools_rationale_127" }, @@ -29072,7 +29495,7 @@ "file_type": "rationale", "source_file": "tests/test_prometheus_tools.py", "source_location": "L136", - "community": 100, + "community": 572, "norm_label": "regression: harnessstate must never leak into tool signatures.", "id": "tests_test_prometheus_tools_rationale_136" }, @@ -29450,7 +29873,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L1", - "community": 67, + "community": 527, "norm_label": "test_roles.py", "id": "tests_test_roles_py" }, @@ -29459,7 +29882,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L4", - "community": 67, + "community": 527, "norm_label": "testpermission", "id": "tests_test_roles_testpermission" }, @@ -29468,7 +29891,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L5", - "community": 67, + "community": 527, "norm_label": ".test_permission_enum_values()", "id": "tests_test_roles_testpermission_test_permission_enum_values" }, @@ -29477,7 +29900,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L10", - "community": 67, + "community": 527, "norm_label": ".test_permission_all_includes_all()", "id": "tests_test_roles_testpermission_test_permission_all_includes_all" }, @@ -29486,7 +29909,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L17", - "community": 67, + "community": 527, "norm_label": "testroles", "id": "tests_test_roles_testroles" }, @@ -29495,7 +29918,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L18", - "community": 67, + "community": 527, "norm_label": ".test_user_role_has_basic_permissions()", "id": "tests_test_roles_testroles_test_user_role_has_basic_permissions" }, @@ -29504,7 +29927,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L23", - "community": 67, + "community": 527, "norm_label": ".test_user_role_missing_premium_permissions()", "id": "tests_test_roles_testroles_test_user_role_missing_premium_permissions" }, @@ -29513,7 +29936,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L27", - "community": 67, + "community": 527, "norm_label": ".test_premium_includes_user_permissions()", "id": "tests_test_roles_testroles_test_premium_includes_user_permissions" }, @@ -29522,7 +29945,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L31", - "community": 67, + "community": 527, "norm_label": ".test_premium_has_extra_permissions()", "id": "tests_test_roles_testroles_test_premium_has_extra_permissions" }, @@ -29531,7 +29954,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L35", - "community": 67, + "community": 527, "norm_label": ".test_developer_starter_includes_user()", "id": "tests_test_roles_testroles_test_developer_starter_includes_user" }, @@ -29540,7 +29963,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L39", - "community": 67, + "community": 527, "norm_label": ".test_developer_enterprise_includes_all()", "id": "tests_test_roles_testroles_test_developer_enterprise_includes_all" }, @@ -29549,7 +29972,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L43", - "community": 67, + "community": 527, "norm_label": ".test_admin_has_all_permissions()", "id": "tests_test_roles_testroles_test_admin_has_all_permissions" }, @@ -29558,7 +29981,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L48", - "community": 67, + "community": 527, "norm_label": ".test_check_access_admin_returns_true()", "id": "tests_test_roles_testroles_test_check_access_admin_returns_true" }, @@ -29567,7 +29990,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L52", - "community": 67, + "community": 527, "norm_label": ".test_check_access_user_with_permission()", "id": "tests_test_roles_testroles_test_check_access_user_with_permission" }, @@ -29576,7 +29999,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L56", - "community": 67, + "community": 527, "norm_label": ".test_check_access_user_without_permission()", "id": "tests_test_roles_testroles_test_check_access_user_without_permission" }, @@ -29585,7 +30008,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L60", - "community": 67, + "community": 527, "norm_label": ".test_check_access_premium_has_prometheus()", "id": "tests_test_roles_testroles_test_check_access_premium_has_prometheus" }, @@ -29594,7 +30017,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L64", - "community": 67, + "community": 527, "norm_label": ".test_check_access_case_insensitive()", "id": "tests_test_roles_testroles_test_check_access_case_insensitive" }, @@ -29603,7 +30026,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L68", - "community": 67, + "community": 527, "norm_label": ".test_check_access_invalid_role_ignored()", "id": "tests_test_roles_testroles_test_check_access_invalid_role_ignored" }, @@ -29612,7 +30035,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L72", - "community": 67, + "community": 527, "norm_label": ".test_check_access_empty_roles()", "id": "tests_test_roles_testroles_test_check_access_empty_roles" }, @@ -29621,7 +30044,7 @@ "file_type": "code", "source_file": "tests/test_roles.py", "source_location": "L76", - "community": 67, + "community": 527, "norm_label": ".test_check_access_multiple_roles()", "id": "tests_test_roles_testroles_test_check_access_multiple_roles" }, @@ -30224,7 +30647,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L6", - "community": 49, + "community": 222, "norm_label": "testsandboxtooldefinitions", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions" }, @@ -30233,7 +30656,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L7", - "community": 49, + "community": 222, "norm_label": ".test_execute_code_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_execute_code_in_registry" }, @@ -30242,7 +30665,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L10", - "community": 49, + "community": 222, "norm_label": ".test_read_file_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_read_file_in_registry" }, @@ -30251,7 +30674,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L13", - "community": 49, + "community": 222, "norm_label": ".test_write_file_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_write_file_in_registry" }, @@ -30260,7 +30683,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L16", - "community": 49, + "community": 222, "norm_label": ".test_list_files_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_list_files_in_registry" }, @@ -30269,7 +30692,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L19", - "community": 49, + "community": 222, "norm_label": ".test_execute_code_has_docstring()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_execute_code_has_docstring" }, @@ -31052,7 +31475,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L23", - "community": 21, + "community": 3, "norm_label": "_make_stocks_df()", "id": "tests_test_stocks_api_coverage_make_stocks_df" }, @@ -31403,7 +31826,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L419", - "community": 3, + "community": 535, "norm_label": ".test_deserialize_float_nan_direct()", "id": "tests_test_stocks_api_coverage_testdeserializejsoncolumns_test_deserialize_float_nan_direct" }, @@ -31412,7 +31835,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L433", - "community": 509, + "community": 126, "norm_label": ".test_deserialize_non_nan_float()", "id": "tests_test_stocks_api_coverage_testdeserializejsoncolumns_test_deserialize_non_nan_float" }, @@ -31430,7 +31853,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L451", - "community": 3, + "community": 488, "norm_label": ".test_deserialize_mixed_string_none_parses_json()", "id": "tests_test_stocks_api_coverage_testdeserializejsoncolumns_test_deserialize_mixed_string_none_parses_json" }, @@ -31439,7 +31862,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L473", - "community": 3, + "community": 520, "norm_label": ".test_deserialize_multiple_special_cols_with_none()", "id": "tests_test_stocks_api_coverage_testdeserializejsoncolumns_test_deserialize_multiple_special_cols_with_none" }, @@ -31448,7 +31871,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L498", - "community": 3, + "community": 488, "norm_label": "testfilterbysearchterms", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms" }, @@ -31457,7 +31880,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L501", - "community": 3, + "community": 488, "norm_label": "._make_manager()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_make_manager" }, @@ -31466,7 +31889,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L509", - "community": 3, + "community": 488, "norm_label": ".test_filter_empty_search_returns_all()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_empty_search_returns_all" }, @@ -31475,7 +31898,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L515", - "community": 3, + "community": 488, "norm_label": ".test_filter_ticker_index_hit()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_ticker_index_hit" }, @@ -31484,7 +31907,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L523", - "community": 3, + "community": 488, "norm_label": ".test_filter_multiple_terms_index()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_multiple_terms_index" }, @@ -31493,7 +31916,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L530", - "community": 3, + "community": 488, "norm_label": ".test_filter_no_index_match_fallback_to_str()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_no_index_match_fallback_to_str" }, @@ -31502,7 +31925,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L538", - "community": 3, + "community": 488, "norm_label": ".test_filter_fallback_multiple_terms()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_fallback_multiple_terms" }, @@ -31511,7 +31934,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L545", - "community": 3, + "community": 488, "norm_label": ".test_filter_case_insensitive()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_case_insensitive" }, @@ -31520,7 +31943,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L553", - "community": 21, + "community": 28, "norm_label": "testqueryhistorical", "id": "tests_test_stocks_api_coverage_testqueryhistorical" }, @@ -31529,7 +31952,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L556", - "community": 21, + "community": 63, "norm_label": "._make_manager()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_make_manager" }, @@ -31538,7 +31961,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L566", - "community": 21, + "community": 28, "norm_label": ".test_cache_not_initialized_raises_503()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_cache_not_initialized_raises_503" }, @@ -31547,7 +31970,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L574", - "community": 21, + "community": 3, "norm_label": ".test_basic_historical_query()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_basic_historical_query" }, @@ -31556,7 +31979,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L583", - "community": 21, + "community": 3, "norm_label": ".test_historical_with_search()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_with_search" }, @@ -31574,7 +31997,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L599", - "community": 21, + "community": 3, "norm_label": ".test_historical_with_dates()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_with_dates" }, @@ -31583,7 +32006,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L605", - "community": 21, + "community": 3, "norm_label": ".test_historical_with_order_by()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_with_order_by" }, @@ -31592,7 +32015,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L611", - "community": 21, + "community": 3, "norm_label": ".test_historical_with_limit()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_with_limit" }, @@ -31601,7 +32024,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L617", - "community": 263, + "community": 28, "norm_label": ".test_historical_no_historical_fields()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_no_historical_fields" }, @@ -31610,7 +32033,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L628", - "community": 21, + "community": 3, "norm_label": ".test_historical_sorts_by_time()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_sorts_by_time" }, @@ -31619,7 +32042,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L634", - "community": 21, + "community": 3, "norm_label": ".test_historical_deduplicates_by_ticker()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_deduplicates_by_ticker" }, @@ -31637,7 +32060,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L660", - "community": 136, + "community": 521, "norm_label": ".test_historical_with_invalid_dates()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_with_invalid_dates" }, @@ -31646,7 +32069,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L669", - "community": 21, + "community": 3, "norm_label": ".test_historical_search_with_no_results()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_search_with_no_results" }, @@ -31718,7 +32141,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L733", - "community": 21, + "community": 3, "norm_label": ".test_basic_fundamental_query()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_basic_fundamental_query" }, @@ -31727,7 +32150,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L741", - "community": 21, + "community": 3, "norm_label": ".test_fundamental_with_search()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_search" }, @@ -31736,7 +32159,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L748", - "community": 21, + "community": 3, "norm_label": ".test_fundamental_with_fields()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_fields" }, @@ -31745,7 +32168,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L754", - "community": 21, + "community": 3, "norm_label": ".test_fundamental_with_date_range()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_date_range" }, @@ -31754,7 +32177,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L760", - "community": 21, + "community": 3, "norm_label": ".test_fundamental_with_single_date()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_single_date" }, @@ -31763,7 +32186,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L766", - "community": 137, + "community": 39, "norm_label": ".test_fundamental_with_invalid_date()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_invalid_date" }, @@ -31772,7 +32195,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L776", - "community": 21, + "community": 3, "norm_label": ".test_fundamental_with_order_by()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_order_by" }, @@ -31781,7 +32204,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L782", - "community": 21, + "community": 3, "norm_label": ".test_fundamental_with_limit()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_limit" }, @@ -31790,7 +32213,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L788", - "community": 21, + "community": 3, "norm_label": ".test_fundamental_deduplicates_without_search()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_deduplicates_without_search" }, @@ -31799,7 +32222,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L796", - "community": 21, + "community": 3, "norm_label": ".test_fundamental_with_search_no_dedup()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_search_no_dedup" }, @@ -31817,7 +32240,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L819", - "community": 17, + "community": 39, "norm_label": ".test_fundamental_empty_search_string_no_dedup()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_empty_search_string_no_dedup" }, @@ -31826,7 +32249,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L828", - "community": 17, + "community": 39, "norm_label": ".test_fundamental_no_time_column()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_no_time_column" }, @@ -31835,7 +32258,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L841", - "community": 39, + "community": 17, "norm_label": ".test_fundamental_date_range_two_dates()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_date_range_two_dates" }, @@ -31862,7 +32285,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L882", - "community": 17, + "community": 39, "norm_label": ".test_fundamental_search_multiple_terms()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_search_multiple_terms" }, @@ -31871,7 +32294,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L890", - "community": 39, + "community": 17, "norm_label": ".test_fundamental_search_fallback_string_match()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_search_fallback_string_match" }, @@ -31880,7 +32303,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L898", - "community": 39, + "community": 17, "norm_label": ".test_fundamental_dates_one_date()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_dates_one_date" }, @@ -31889,7 +32312,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L913", - "community": 538, + "community": 21, "norm_label": ".test_fundamental_excludes_cotacao_10y()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_excludes_cotacao_10y" }, @@ -31907,7 +32330,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L963", - "community": 21, + "community": 3, "norm_label": ".test_fundamental_requires_search_fields_or_dates()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_requires_search_fields_or_dates" }, @@ -32087,7 +32510,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1169", - "community": 10, + "community": 3, "norm_label": "._make_manager()", "id": "tests_test_stocks_api_coverage_testquerylivecotation_make_manager" }, @@ -32159,7 +32582,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1265", - "community": 112, + "community": 22, "norm_label": ".test_http_route_search_required()", "id": "tests_test_stocks_api_coverage_testquerylivecotation_test_http_route_search_required" }, @@ -32195,7 +32618,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1315", - "community": 112, + "community": 568, "norm_label": ".test_cotations_search_required()", "id": "tests_test_stocks_api_coverage_testquerylivecotation_test_cotations_search_required" }, @@ -32213,7 +32636,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L24", - "community": 21, + "community": 3, "norm_label": "return a small dataframe with the columns the query module expects.", "id": "tests_test_stocks_api_coverage_rationale_24" }, @@ -32357,7 +32780,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L420", - "community": 3, + "community": 535, "norm_label": "replacenan handles direct float nan values (line 34).", "id": "tests_test_stocks_api_coverage_rationale_420" }, @@ -32366,7 +32789,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L434", - "community": 509, + "community": 126, "norm_label": "non-json-dict/list string is left as-is.", "id": "tests_test_stocks_api_coverage_rationale_434" }, @@ -32384,7 +32807,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L452", - "community": 3, + "community": 488, "norm_label": "regression: is_string_dtype fails when column has strings + none (pandas 2.x).", "id": "tests_test_stocks_api_coverage_rationale_452" }, @@ -32393,7 +32816,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L474", - "community": 3, + "community": 520, "norm_label": "all four special_cols should parse correctly when mixed with none.", "id": "tests_test_stocks_api_coverage_rationale_474" }, @@ -32402,7 +32825,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L499", - "community": 3, + "community": 488, "norm_label": "tests covering query.py lines 50-67.", "id": "tests_test_stocks_api_coverage_rationale_499" }, @@ -32411,7 +32834,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L554", - "community": 21, + "community": 28, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_554" }, @@ -32429,7 +32852,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L618", - "community": 263, + "community": 28, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_618" }, @@ -32447,7 +32870,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L661", - "community": 136, + "community": 521, "norm_label": "invalid date format raises exception (line 132).", "id": "tests_test_stocks_api_coverage_rationale_661" }, @@ -32474,7 +32897,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L694", - "community": 263, + "community": 28, "norm_label": "multiple search terms, all found in tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_694" }, @@ -32501,7 +32924,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L767", - "community": 137, + "community": 39, "norm_label": "invalid date -> inner 400 passes through (not wrapped as 500).", "id": "tests_test_stocks_api_coverage_rationale_767" }, @@ -32510,7 +32933,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L820", - "community": 17, + "community": 39, "norm_label": "search.strip() == '' should still dedup (line 181).", "id": "tests_test_stocks_api_coverage_rationale_820" }, @@ -32519,7 +32942,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L829", - "community": 17, + "community": 39, "norm_label": "dataframe without time column.", "id": "tests_test_stocks_api_coverage_rationale_829" }, @@ -32528,7 +32951,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L842", - "community": 137, + "community": 17, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_842" }, @@ -32555,7 +32978,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L883", - "community": 17, + "community": 39, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_883" }, @@ -32564,7 +32987,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L891", - "community": 39, + "community": 17, "norm_label": "search with no index match falls back to string startswith.", "id": "tests_test_stocks_api_coverage_rationale_891" }, @@ -32573,7 +32996,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L899", - "community": 39, + "community": 17, "norm_label": "len(daterange) == 1 -> per-ticker closest snapshot.", "id": "tests_test_stocks_api_coverage_rationale_899" }, @@ -32582,7 +33005,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L914", - "community": 538, + "community": 21, "norm_label": "cotacao 10y padrao and cotacao 10y ajustada belong to /cotations, not /fundament", "id": "tests_test_stocks_api_coverage_rationale_914" }, @@ -32654,7 +33077,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1266", - "community": 112, + "community": 22, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1266" }, @@ -32663,7 +33086,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1316", - "community": 112, + "community": 568, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1316" }, @@ -33680,7 +34103,7 @@ "file_type": "code", "source_file": "tests/test_thread_safety.py", "source_location": "L21", - "community": 522, + "community": 186, "norm_label": "testgetsession", "id": "tests_test_thread_safety_testgetsession" }, @@ -33689,7 +34112,7 @@ "file_type": "code", "source_file": "tests/test_thread_safety.py", "source_location": "L24", - "community": 522, + "community": 186, "norm_label": ".test_same_session_within_same_thread()", "id": "tests_test_thread_safety_testgetsession_test_same_session_within_same_thread" }, @@ -33698,7 +34121,7 @@ "file_type": "code", "source_file": "tests/test_thread_safety.py", "source_location": "L32", - "community": 522, + "community": 186, "norm_label": ".test_different_sessions_in_different_threads()", "id": "tests_test_thread_safety_testgetsession_test_different_sessions_in_different_threads" }, @@ -33707,7 +34130,7 @@ "file_type": "code", "source_file": "tests/test_thread_safety.py", "source_location": "L52", - "community": 522, + "community": 186, "norm_label": ".test_isolation_under_high_concurrency()", "id": "tests_test_thread_safety_testgetsession_test_isolation_under_high_concurrency" }, @@ -33716,7 +34139,7 @@ "file_type": "code", "source_file": "tests/test_thread_safety.py", "source_location": "L73", - "community": 522, + "community": 186, "norm_label": ".test_session_is_requests_session()", "id": "tests_test_thread_safety_testgetsession_test_session_is_requests_session" }, @@ -33797,7 +34220,7 @@ "file_type": "rationale", "source_file": "tests/test_thread_safety.py", "source_location": "L22", - "community": 522, + "community": 186, "norm_label": "verify that getsession() returns per-thread session instances.", "id": "tests_test_thread_safety_rationale_22" }, @@ -33806,7 +34229,7 @@ "file_type": "rationale", "source_file": "tests/test_thread_safety.py", "source_location": "L25", - "community": 522, + "community": 186, "norm_label": "calling getsession() twice in the same thread returns the same object.", "id": "tests_test_thread_safety_rationale_25" }, @@ -33815,7 +34238,7 @@ "file_type": "rationale", "source_file": "tests/test_thread_safety.py", "source_location": "L33", - "community": 522, + "community": 186, "norm_label": "two threads must not share a session object.", "id": "tests_test_thread_safety_rationale_33" }, @@ -33824,7 +34247,7 @@ "file_type": "rationale", "source_file": "tests/test_thread_safety.py", "source_location": "L53", - "community": 522, + "community": 186, "norm_label": "with 20 concurrent threads, every thread must get its own session.", "id": "tests_test_thread_safety_rationale_53" }, @@ -33833,7 +34256,7 @@ "file_type": "rationale", "source_file": "tests/test_thread_safety.py", "source_location": "L74", - "community": 522, + "community": 186, "norm_label": "the returned object must be a real requests.session.", "id": "tests_test_thread_safety_rationale_74" }, @@ -34004,7 +34427,7 @@ "file_type": "code", "source_file": "tests/test_user_deps.py", "source_location": "L1", - "community": 529, + "community": 474, "norm_label": "test_user_deps.py", "id": "tests_test_user_deps_py" }, @@ -35552,7 +35975,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1042", - "community": 16, + "community": 104, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1042" }, @@ -35579,7 +36002,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1138", - "community": 498, + "community": 539, "norm_label": "covers line 18: get /stocks/health.", "id": "tests_test_controllers_coverage_rationale_1138" }, @@ -35588,7 +36011,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1152", - "community": 14, + "community": 563, "norm_label": "covers line 35: get /stocks/historical.", "id": "tests_test_controllers_coverage_rationale_1152" }, @@ -35597,7 +36020,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1166", - "community": 503, + "community": 14, "norm_label": "covers line 47: get /stocks/fundamental.", "id": "tests_test_controllers_coverage_rationale_1166" }, @@ -35750,7 +36173,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1404", - "community": 519, + "community": 524, "norm_label": "covers lines 50-51: jwt.invalidtokenerror.", "id": "tests_test_controllers_coverage_rationale_1404" }, @@ -35885,7 +36308,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L42", - "community": 152, + "community": 90, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_42" }, @@ -35903,7 +36326,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L147", - "community": 523, + "community": 500, "norm_label": "read a file from the workspace. args: path: path to the file (e.", "id": "prometheus_tools_rationale_147" }, @@ -35912,7 +36335,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L171", - "community": 523, + "community": 162, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_171" }, @@ -35921,7 +36344,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L30", - "community": 126, + "community": 137, "norm_label": "keys with jaccard > 0.8 should merge.", "id": "tests_test_memory_dedup_rationale_30" }, @@ -35930,7 +36353,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L40", - "community": 126, + "community": 137, "norm_label": "keys with low similarity should not merge.", "id": "tests_test_memory_dedup_rationale_40" }, @@ -35939,7 +36362,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L67", - "community": 126, + "community": 137, "norm_label": "keys with jaccard <= 0.8 should not merge.", "id": "tests_test_memory_dedup_rationale_67" }, @@ -36209,7 +36632,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L131", - "community": 523, + "community": 500, "norm_label": "read a file from the sandbox filesystem. args: path: absolute pa", "id": "prometheus_tools_rationale_131" }, @@ -36407,7 +36830,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L130", - "community": 523, + "community": 500, "norm_label": "read a file from the sandbox filesystem. args: path: absolute pa", "id": "prometheus_tools_rationale_130" }, @@ -36416,7 +36839,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L7", - "community": 8, + "community": 543, "norm_label": "testagentsandboxintegration", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration" }, @@ -36425,7 +36848,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L8", - "community": 8, + "community": 543, "norm_label": ".test_build_system_prompt_includes_sandbox_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_includes_sandbox_instructions" }, @@ -36434,7 +36857,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L14", - "community": 8, + "community": 543, "norm_label": ".test_build_system_prompt_includes_state_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_includes_state_instructions" }, @@ -36443,7 +36866,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L19", - "community": 8, + "community": 543, "norm_label": ".test_build_system_prompt_with_state()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_with_state" }, @@ -36542,7 +36965,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L41", - "community": 152, + "community": 90, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_41" }, @@ -38756,7 +39179,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L119", - "community": 101, + "community": 100, "norm_label": "test_set_state_no_state_returns_error()", "id": "tests_test_prometheus_tools_test_set_state_no_state_returns_error" }, @@ -38774,7 +39197,7 @@ "file_type": "rationale", "source_file": "tests/test_prometheus_tools.py", "source_location": "L128", - "community": 100, + "community": 572, "norm_label": "every function in tool_registry must have gemini-safe signatures. custom cl", "id": "tests_test_prometheus_tools_rationale_128" }, @@ -38783,7 +39206,7 @@ "file_type": "rationale", "source_file": "tests/test_prometheus_tools.py", "source_location": "L137", - "community": 100, + "community": 572, "norm_label": "regression: harnessstate must never leak into tool signatures.", "id": "tests_test_prometheus_tools_rationale_137" }, @@ -38792,7 +39215,7 @@ "file_type": "code", "source_file": "main/app/prometheus/cache.py", "source_location": "L1", - "community": 162, + "community": 67, "norm_label": "cache.py", "id": "main_app_prometheus_cache_py" }, @@ -38801,7 +39224,7 @@ "file_type": "code", "source_file": "main/app/prometheus/cache.py", "source_location": "L7", - "community": 162, + "community": 67, "norm_label": "resultcache", "id": "prometheus_cache_resultcache" }, @@ -38810,7 +39233,7 @@ "file_type": "code", "source_file": "main/app/prometheus/cache.py", "source_location": "L8", - "community": 162, + "community": 67, "norm_label": ".__init__()", "id": "prometheus_cache_resultcache_init" }, @@ -38819,7 +39242,7 @@ "file_type": "code", "source_file": "main/app/prometheus/cache.py", "source_location": "L11", - "community": 162, + "community": 67, "norm_label": ".cachepath()", "id": "prometheus_cache_resultcache_cachepath" }, @@ -38828,7 +39251,7 @@ "file_type": "code", "source_file": "main/app/prometheus/cache.py", "source_location": "L15", - "community": 162, + "community": 67, "norm_label": ".get()", "id": "prometheus_cache_resultcache_get" }, @@ -38837,7 +39260,7 @@ "file_type": "code", "source_file": "main/app/prometheus/cache.py", "source_location": "L21", - "community": 162, + "community": 67, "norm_label": ".set()", "id": "prometheus_cache_resultcache_set" }, @@ -38846,7 +39269,7 @@ "file_type": "code", "source_file": "main/app/prometheus/cache.py", "source_location": "L31", - "community": 162, + "community": 67, "norm_label": ".invalidate()", "id": "prometheus_cache_resultcache_invalidate" }, @@ -38855,7 +39278,7 @@ "file_type": "code", "source_file": "main/app/prometheus/cache.py", "source_location": "L38", - "community": 162, + "community": 67, "norm_label": ".exists()", "id": "prometheus_cache_resultcache_exists" }, @@ -38900,7 +39323,7 @@ "file_type": "code", "source_file": "main/app/prometheus/tools.py", "source_location": "L139", - "community": 523, + "community": 162, "norm_label": "read_sandbox_file()", "id": "prometheus_tools_read_sandbox_file" }, @@ -38945,7 +39368,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L140", - "community": 523, + "community": 162, "norm_label": "read a file from the sandbox filesystem. args: path: absolute pa", "id": "prometheus_tools_rationale_140" }, @@ -38972,7 +39395,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L9", - "community": 8, + "community": 543, "norm_label": ".test_build_system_prompt_no_state()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_no_state" }, @@ -38981,7 +39404,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L20", - "community": 8, + "community": 543, "norm_label": ".test_build_system_prompt_empty_state()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_empty_state" }, @@ -38990,7 +39413,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L25", - "community": 8, + "community": 543, "norm_label": ".test_system_prompt_includes_state_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_system_prompt_includes_state_instructions" }, @@ -38999,7 +39422,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L30", - "community": 8, + "community": 543, "norm_label": ".test_system_prompt_includes_sandbox_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_system_prompt_includes_sandbox_instructions" }, @@ -39008,7 +39431,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L34", - "community": 8, + "community": 543, "norm_label": ".test_system_prompt_includes_cache_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_system_prompt_includes_cache_instructions" }, @@ -39017,7 +39440,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L38", - "community": 8, + "community": 543, "norm_label": ".test_makechat_uses_tool_registry()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_makechat_uses_tool_registry" }, @@ -39188,7 +39611,7 @@ "file_type": "code", "source_file": "tests/test_config_sandbox.py", "source_location": "L1", - "community": 215, + "community": 541, "norm_label": "test_config_sandbox.py", "id": "tests_test_config_sandbox_py" }, @@ -39197,7 +39620,7 @@ "file_type": "code", "source_file": "tests/test_config_sandbox.py", "source_location": "L5", - "community": 215, + "community": 102, "norm_label": "testsandboxconfig", "id": "tests_test_config_sandbox_testsandboxconfig" }, @@ -39206,7 +39629,7 @@ "file_type": "code", "source_file": "tests/test_config_sandbox.py", "source_location": "L6", - "community": 215, + "community": 102, "norm_label": ".test_sandbox_defaults()", "id": "tests_test_config_sandbox_testsandboxconfig_test_sandbox_defaults" }, @@ -39215,7 +39638,7 @@ "file_type": "code", "source_file": "tests/test_config_sandbox.py", "source_location": "L13", - "community": 215, + "community": 102, "norm_label": ".test_sandbox_fields_exist()", "id": "tests_test_config_sandbox_testsandboxconfig_test_sandbox_fields_exist" }, @@ -39224,7 +39647,7 @@ "file_type": "code", "source_file": "tests/test_config_sandbox.py", "source_location": "L21", - "community": 215, + "community": 102, "norm_label": ".test_sandbox_types()", "id": "tests_test_config_sandbox_testsandboxconfig_test_sandbox_types" }, @@ -39485,7 +39908,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L12", - "community": 49, + "community": 222, "norm_label": ".test_read_sandbox_file_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_read_sandbox_file_in_registry" }, @@ -39494,7 +39917,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L15", - "community": 49, + "community": 222, "norm_label": ".test_check_cache_in_registry()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_check_cache_in_registry" }, @@ -39503,7 +39926,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L23", - "community": 49, + "community": 222, "norm_label": ".test_read_sandbox_file_has_docstring()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_read_sandbox_file_has_docstring" }, @@ -39512,7 +39935,7 @@ "file_type": "code", "source_file": "tests/test_sandbox_tools.py", "source_location": "L28", - "community": 49, + "community": 222, "norm_label": ".test_check_cache_has_docstring()", "id": "tests_test_sandbox_tools_testsandboxtooldefinitions_test_check_cache_has_docstring" }, @@ -39845,7 +40268,7 @@ "file_type": "code", "source_file": "main/app/prometheus/cache.py", "source_location": "L19", - "community": 162, + "community": 67, "norm_label": "._cache_path()", "id": "prometheus_cache_resultcache_cache_path" }, @@ -39854,7 +40277,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/cache.py", "source_location": "L1", - "community": 162, + "community": 67, "norm_label": "resultcache \u2014 sha256-keyed file-based cache for computed results.", "id": "prometheus_cache_rationale_1" }, @@ -39863,7 +40286,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/cache.py", "source_location": "L10", - "community": 162, + "community": 67, "norm_label": "file-based cache keyed by sha256 of code. stores results as json under:", "id": "prometheus_cache_rationale_10" }, @@ -39872,7 +40295,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/cache.py", "source_location": "L24", - "community": 162, + "community": 67, "norm_label": "return cached result dict or none if miss.", "id": "prometheus_cache_rationale_24" }, @@ -39881,7 +40304,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/cache.py", "source_location": "L31", - "community": 162, + "community": 67, "norm_label": "store result with timestamp.", "id": "prometheus_cache_rationale_31" }, @@ -39890,7 +40313,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/cache.py", "source_location": "L42", - "community": 162, + "community": 67, "norm_label": "delete all cached results for a session.", "id": "prometheus_cache_rationale_42" }, @@ -39899,7 +40322,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/cache.py", "source_location": "L50", - "community": 162, + "community": 67, "norm_label": "check if a result exists for the given code.", "id": "prometheus_cache_rationale_50" }, @@ -40322,7 +40745,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L39", - "community": 152, + "community": 90, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_39" }, @@ -40385,7 +40808,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/state.py", "source_location": "L22", - "community": 21, + "community": 112, "norm_label": "store a value in state. marks state as changed for context injection.", "id": "prometheus_state_rationale_22" }, @@ -40448,7 +40871,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L38", - "community": 152, + "community": 90, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_38" }, @@ -40502,7 +40925,7 @@ "file_type": "code", "source_file": "main/app/prometheus/tools.py", "source_location": "L46", - "community": 541, + "community": 562, "norm_label": "executememorytool()", "id": "prometheus_tools_executememorytool" }, @@ -40511,7 +40934,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L29", - "community": 152, + "community": 90, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_29" }, @@ -40520,7 +40943,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L52", - "community": 126, + "community": 137, "norm_label": "keys with low similarity should not merge.", "id": "tests_test_memory_dedup_rationale_52" }, @@ -40529,7 +40952,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L85", - "community": 126, + "community": 137, "norm_label": "keys with jaccard <= 0.8 should not merge.", "id": "tests_test_memory_dedup_rationale_85" }, @@ -40646,7 +41069,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L52", - "community": 487, + "community": 573, "norm_label": "makechat must include memory_tools alongside mcp sessions.", "id": "tests_test_memory_tools_wiring_rationale_52" }, @@ -40655,7 +41078,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L89", - "community": 487, + "community": 571, "norm_label": "dispatchtoolcall must route memory tool names to executememorytool.", "id": "tests_test_memory_tools_wiring_rationale_89" }, @@ -40682,7 +41105,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L57", - "community": 487, + "community": 573, "norm_label": "makechat must include memory_tools alongside mcp sessions.", "id": "tests_test_memory_tools_wiring_rationale_57" }, @@ -40691,7 +41114,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L92", - "community": 487, + "community": 571, "norm_label": "dispatchtoolcall must route memory tool names to executememorytool.", "id": "tests_test_memory_tools_wiring_rationale_92" }, @@ -40709,7 +41132,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L23", - "community": 54, + "community": 518, "norm_label": "helper to create memories with controlled basescore, lastaccessedat, accesscount", "id": "tests_test_memory_maintenance_rationale_23" }, @@ -40718,7 +41141,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L54", - "community": 54, + "community": 518, "norm_label": "decay applies to all active memories, not just accessed ones.", "id": "tests_test_memory_maintenance_rationale_54" }, @@ -40727,7 +41150,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L67", - "community": 54, + "community": 518, "norm_label": "basescore should never reach exactly 0 from decay alone.", "id": "tests_test_memory_maintenance_rationale_67" }, @@ -40736,7 +41159,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L85", - "community": 54, + "community": 518, "norm_label": "score below threshold + accesscount=0 + 90+ days \u2192 archived.", "id": "tests_test_memory_maintenance_rationale_85" }, @@ -40745,7 +41168,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L92", - "community": 54, + "community": 518, "norm_label": "low score but accessed recently \u2192 not archived.", "id": "tests_test_memory_maintenance_rationale_92" }, @@ -40754,7 +41177,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L99", - "community": 54, + "community": 518, "norm_label": "zero access but score still above threshold \u2192 not archived.", "id": "tests_test_memory_maintenance_rationale_99" }, @@ -40763,7 +41186,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L106", - "community": 54, + "community": 518, "norm_label": "even with low score, if accessed \u2192 not archived.", "id": "tests_test_memory_maintenance_rationale_106" }, @@ -40772,7 +41195,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L113", - "community": 54, + "community": 518, "norm_label": "already archived memories are skipped.", "id": "tests_test_memory_maintenance_rationale_113" }, @@ -40781,7 +41204,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L134", - "community": 54, + "community": 234, "norm_label": "decay happens first, then archive check with new scores.", "id": "tests_test_memory_maintenance_rationale_134" }, @@ -40790,7 +41213,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L143", - "community": 54, + "community": 234, "norm_label": "score that decays to >= threshold stays alive. 0.11 * 0.95 = 0.1045 >= 0.1.", "id": "tests_test_memory_maintenance_rationale_143" }, @@ -40799,7 +41222,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L156", - "community": 54, + "community": 234, "norm_label": "89 days with low score \u2192 not archived (need > 90).", "id": "tests_test_memory_maintenance_rationale_156" }, @@ -40808,7 +41231,7 @@ "file_type": "code", "source_file": "main/utils/models/loader.py", "source_location": "L23", - "community": 541, + "community": 562, "norm_label": "embed()", "id": "models_loader_embed" }, @@ -40988,7 +41411,7 @@ "file_type": "code", "source_file": "main/utils/models/loader.py", "source_location": "L11", - "community": 541, + "community": 562, "norm_label": "_downloadmodel()", "id": "models_loader_downloadmodel" }, @@ -41195,7 +41618,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1405", - "community": 519, + "community": 524, "norm_label": "covers lines 50-51: jwt.invalidtokenerror.", "id": "tests_test_controllers_coverage_rationale_1405" }, @@ -41204,7 +41627,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1417", - "community": 498, + "community": 114, "norm_label": "covers line 67: extracttokenpayload re-raises httpexception from verifyaccesstok", "id": "tests_test_controllers_coverage_rationale_1417" }, @@ -41447,7 +41870,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L56", - "community": 487, + "community": 573, "norm_label": "makechat must include memory_tools alongside mcp sessions.", "id": "tests_test_memory_tools_wiring_rationale_56" }, @@ -41456,7 +41879,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L91", - "community": 487, + "community": 571, "norm_label": "dispatchtoolcall must route memory tool names to executememorytool.", "id": "tests_test_memory_tools_wiring_rationale_91" }, @@ -41780,7 +42203,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L48", - "community": 487, + "community": 573, "norm_label": "makechat must include memory_tools alongside mcp sessions.", "id": "tests_test_memory_tools_wiring_rationale_48" }, @@ -41789,7 +42212,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L76", - "community": 487, + "community": 571, "norm_label": "dispatchtoolcall must route memory tool names to executememorytool.", "id": "tests_test_memory_tools_wiring_rationale_76" }, @@ -41879,7 +42302,7 @@ "file_type": "code", "source_file": "main/controller/prometheus_controller.py", "source_location": "L177", - "community": 541, + "community": 562, "norm_label": "creatememory()", "id": "controller_prometheus_controller_creatememory" }, @@ -41906,7 +42329,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L10", - "community": 130, + "community": 86, "norm_label": "testmemorycontrollerroutes", "id": "tests_test_memory_controller_testmemorycontrollerroutes" }, @@ -41915,7 +42338,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L11", - "community": 130, + "community": 86, "norm_label": ".test_get_memories_endpoint_exists()", "id": "tests_test_memory_controller_testmemorycontrollerroutes_test_get_memories_endpoint_exists" }, @@ -41924,7 +42347,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L15", - "community": 130, + "community": 86, "norm_label": ".test_post_memories_endpoint_exists()", "id": "tests_test_memory_controller_testmemorycontrollerroutes_test_post_memories_endpoint_exists" }, @@ -41933,7 +42356,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L19", - "community": 130, + "community": 86, "norm_label": ".test_delete_memories_endpoint_exists()", "id": "tests_test_memory_controller_testmemorycontrollerroutes_test_delete_memories_endpoint_exists" }, @@ -41942,7 +42365,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L23", - "community": 130, + "community": 86, "norm_label": ".test_get_memories_rejects_unauthenticated()", "id": "tests_test_memory_controller_testmemorycontrollerroutes_test_get_memories_rejects_unauthenticated" }, @@ -41951,7 +42374,7 @@ "file_type": "code", "source_file": "tests/test_memory_controller.py", "source_location": "L38", - "community": 130, + "community": 86, "norm_label": ".test_get_memories_rejects_basic_user()", "id": "tests_test_memory_controller_testmemorycontrollerroutes_test_get_memories_rejects_basic_user" }, @@ -42563,7 +42986,7 @@ "file_type": "code", "source_file": "main/app/prometheus/memory.py", "source_location": "L138", - "community": 13, + "community": 53, "norm_label": "_fulltext_search()", "id": "prometheus_memory_fulltext_search" }, @@ -42689,7 +43112,7 @@ "file_type": "code", "source_file": "main/controller/prometheus_controller.py", "source_location": "L177", - "community": 541, + "community": 562, "norm_label": "create_memory()", "id": "controller_prometheus_controller_create_memory" }, @@ -42788,7 +43211,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L11", - "community": 130, + "community": 86, "norm_label": "verify memory endpoints exist and are wired correctly.", "id": "tests_test_memory_controller_rationale_11" }, @@ -42797,7 +43220,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L14", - "community": 130, + "community": 86, "norm_label": "get /prometheus/memories exists.", "id": "tests_test_memory_controller_rationale_14" }, @@ -42806,7 +43229,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L20", - "community": 130, + "community": 86, "norm_label": "post /prometheus/memories exists.", "id": "tests_test_memory_controller_rationale_20" }, @@ -42815,7 +43238,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L25", - "community": 130, + "community": 86, "norm_label": "delete /prometheus/memories/{id} exists.", "id": "tests_test_memory_controller_rationale_25" }, @@ -42824,7 +43247,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L30", - "community": 130, + "community": 86, "norm_label": "get /memories requires authentication.", "id": "tests_test_memory_controller_rationale_30" }, @@ -42833,7 +43256,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_controller.py", "source_location": "L47", - "community": 130, + "community": 86, "norm_label": "get /memories requires use_prometheus (basic user role denied).", "id": "tests_test_memory_controller_rationale_47" }, @@ -42914,7 +43337,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L11", - "community": 571, + "community": 140, "norm_label": "non-extended role gets basic limit.", "id": "tests_test_memory_manager_rationale_11" }, @@ -42932,7 +43355,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L19", - "community": 575, + "community": 574, "norm_label": "admin gets extended limit (has all permissions).", "id": "tests_test_memory_manager_rationale_19" }, @@ -42941,7 +43364,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L25", - "community": 140, + "community": 575, "norm_label": "creates a new memory.", "id": "tests_test_memory_manager_rationale_25" }, @@ -42959,7 +43382,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L43", - "community": 576, + "community": 140, "norm_label": "returns unchanged when value is identical.", "id": "tests_test_memory_manager_rationale_43" }, @@ -42977,7 +43400,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L61", - "community": 578, + "community": 140, "norm_label": "no role check when user_roles not provided.", "id": "tests_test_memory_manager_rationale_61" }, @@ -42986,7 +43409,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L69", - "community": 579, + "community": 140, "norm_label": "stores embedding alongside memory.", "id": "tests_test_memory_manager_rationale_69" }, @@ -43004,7 +43427,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L88", - "community": 140, + "community": 576, "norm_label": "archived memories not counted.", "id": "tests_test_memory_manager_rationale_88" }, @@ -43013,7 +43436,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L107", - "community": 570, + "community": 140, "norm_label": "returns paginated memories.", "id": "tests_test_memory_manager_rationale_107" }, @@ -43022,7 +43445,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L115", - "community": 572, + "community": 140, "norm_label": "offset and limit work.", "id": "tests_test_memory_manager_rationale_115" }, @@ -43031,7 +43454,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L122", - "community": 573, + "community": 140, "norm_label": "archived memories excluded.", "id": "tests_test_memory_manager_rationale_122" }, @@ -43040,7 +43463,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L135", - "community": 574, + "community": 140, "norm_label": "soft-deletes a memory.", "id": "tests_test_memory_manager_rationale_135" }, @@ -44165,7 +44588,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L1", - "community": 563, + "community": 186, "norm_label": "generation.py", "id": "main_app_prometheus_generation_py" }, @@ -44201,7 +44624,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L36", - "community": 563, + "community": 186, "norm_label": ".executeworkflow()", "id": "prometheus_generation_prometheusgenerator_executeworkflow" }, @@ -44273,7 +44696,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L13", - "community": 527, + "community": 251, "norm_label": "set required env vars before test collection. config.py eagerly instantia", "id": "tests_conftest_rationale_13" }, @@ -44282,7 +44705,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L74", - "community": 527, + "community": 251, "norm_label": "testclient with stocks router + verifyapikey + getcurrentuser overrides.", "id": "tests_conftest_rationale_74" }, @@ -44291,7 +44714,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L99", - "community": 527, + "community": 251, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_99" }, @@ -44453,7 +44876,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L846", - "community": 99, + "community": 16, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_846" }, @@ -44462,7 +44885,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L864", - "community": 99, + "community": 16, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_864" }, @@ -44534,7 +44957,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L994", - "community": 474, + "community": 231, "norm_label": "covers lines 95-98: delete /prometheus/sessions/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_994" }, @@ -44543,7 +44966,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L997", - "community": 474, + "community": 231, "norm_label": "covers lines 95-98: session deleted.", "id": "tests_test_controllers_coverage_rationale_997" }, @@ -44552,7 +44975,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1007", - "community": 474, + "community": 231, "norm_label": "covers lines 96-97: session not found.", "id": "tests_test_controllers_coverage_rationale_1007" }, @@ -44570,7 +44993,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1020", - "community": 99, + "community": 16, "norm_label": "covers lines 111-112: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1020" }, @@ -44579,7 +45002,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1038", - "community": 16, + "community": 104, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1038" }, @@ -44606,7 +45029,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1134", - "community": 498, + "community": 539, "norm_label": "covers line 18: get /stocks/health.", "id": "tests_test_controllers_coverage_rationale_1134" }, @@ -44615,7 +45038,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1148", - "community": 14, + "community": 563, "norm_label": "covers line 35: get /stocks/historical.", "id": "tests_test_controllers_coverage_rationale_1148" }, @@ -44624,7 +45047,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1162", - "community": 503, + "community": 14, "norm_label": "covers line 47: get /stocks/fundamental.", "id": "tests_test_controllers_coverage_rationale_1162" }, @@ -44768,7 +45191,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1401", - "community": 519, + "community": 524, "norm_label": "covers lines 50-51: jwt.invalidtokenerror.", "id": "tests_test_controllers_coverage_rationale_1401" }, @@ -44777,7 +45200,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1413", - "community": 498, + "community": 114, "norm_label": "covers line 67: extracttokenpayload re-raises httpexception from verifyaccesstok", "id": "tests_test_controllers_coverage_rationale_1413" }, @@ -45065,7 +45488,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L844", - "community": 99, + "community": 16, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_844" }, @@ -45074,7 +45497,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L862", - "community": 99, + "community": 16, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_862" }, @@ -45146,7 +45569,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L992", - "community": 474, + "community": 231, "norm_label": "covers lines 95-98: delete /prometheus/sessions/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_992" }, @@ -45155,7 +45578,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L995", - "community": 474, + "community": 231, "norm_label": "covers lines 95-98: session deleted.", "id": "tests_test_controllers_coverage_rationale_995" }, @@ -45164,7 +45587,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1005", - "community": 474, + "community": 231, "norm_label": "covers lines 96-97: session not found.", "id": "tests_test_controllers_coverage_rationale_1005" }, @@ -45182,7 +45605,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1018", - "community": 99, + "community": 16, "norm_label": "covers lines 111-112: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1018" }, @@ -45191,7 +45614,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1036", - "community": 16, + "community": 104, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1036" }, @@ -45218,7 +45641,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1133", - "community": 498, + "community": 539, "norm_label": "covers line 18: get /stocks/health.", "id": "tests_test_controllers_coverage_rationale_1133" }, @@ -45227,7 +45650,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1147", - "community": 14, + "community": 563, "norm_label": "covers line 35: get /stocks/historical.", "id": "tests_test_controllers_coverage_rationale_1147" }, @@ -45236,7 +45659,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1161", - "community": 503, + "community": 14, "norm_label": "covers line 47: get /stocks/fundamental.", "id": "tests_test_controllers_coverage_rationale_1161" }, @@ -45389,7 +45812,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1400", - "community": 519, + "community": 524, "norm_label": "covers lines 50-51: jwt.invalidtokenerror.", "id": "tests_test_controllers_coverage_rationale_1400" }, @@ -45398,7 +45821,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1412", - "community": 498, + "community": 114, "norm_label": "covers line 67: extracttokenpayload re-raises httpexception from verifyaccesstok", "id": "tests_test_controllers_coverage_rationale_1412" }, @@ -45506,7 +45929,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/query.py", "source_location": "L42", - "community": 63, + "community": 517, "norm_label": "parsecotationdates()", "id": "stocks_api_query_parsecotationdates" }, @@ -45857,7 +46280,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L496", - "community": 3, + "community": 535, "norm_label": "replacenan handles direct float nan values (line 34).", "id": "tests_test_stocks_api_coverage_rationale_496" }, @@ -45866,7 +46289,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L510", - "community": 509, + "community": 126, "norm_label": "non-json-dict/list string is left as-is.", "id": "tests_test_stocks_api_coverage_rationale_510" }, @@ -45884,7 +46307,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L528", - "community": 3, + "community": 488, "norm_label": "regression: is_string_dtype fails when column has strings + none (pandas 2.x).", "id": "tests_test_stocks_api_coverage_rationale_528" }, @@ -45893,7 +46316,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L550", - "community": 3, + "community": 520, "norm_label": "all four special_cols should parse correctly when mixed with none.", "id": "tests_test_stocks_api_coverage_rationale_550" }, @@ -45902,7 +46325,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L575", - "community": 3, + "community": 488, "norm_label": "tests covering query.py lines 50-67.", "id": "tests_test_stocks_api_coverage_rationale_575" }, @@ -45911,7 +46334,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L630", - "community": 21, + "community": 28, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_630" }, @@ -45938,7 +46361,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L737", - "community": 136, + "community": 521, "norm_label": "invalid date format raises exception (line 132).", "id": "tests_test_stocks_api_coverage_rationale_737" }, @@ -45992,7 +46415,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L843", - "community": 137, + "community": 39, "norm_label": "invalid date -> inner 400 passes through (not wrapped as 500).", "id": "tests_test_stocks_api_coverage_rationale_843" }, @@ -46001,7 +46424,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L896", - "community": 39, + "community": 17, "norm_label": "search.strip() == '' should still dedup (line 181).", "id": "tests_test_stocks_api_coverage_rationale_896" }, @@ -46010,7 +46433,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L905", - "community": 39, + "community": 17, "norm_label": "dataframe without time column.", "id": "tests_test_stocks_api_coverage_rationale_905" }, @@ -46019,7 +46442,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L918", - "community": 39, + "community": 17, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_918" }, @@ -46046,7 +46469,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L959", - "community": 17, + "community": 39, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_959" }, @@ -46055,7 +46478,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L967", - "community": 39, + "community": 17, "norm_label": "search with no index match falls back to string startswith.", "id": "tests_test_stocks_api_coverage_rationale_967" }, @@ -46064,7 +46487,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L975", - "community": 39, + "community": 17, "norm_label": "len(daterange) == 1 -> per-ticker closest snapshot.", "id": "tests_test_stocks_api_coverage_rationale_975" }, @@ -46073,7 +46496,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L990", - "community": 538, + "community": 21, "norm_label": "cotacao 10y padrao and cotacao 10y ajustada belong to /cotations, not /fundament", "id": "tests_test_stocks_api_coverage_rationale_990" }, @@ -46145,7 +46568,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1342", - "community": 112, + "community": 22, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1342" }, @@ -46154,7 +46577,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1392", - "community": 112, + "community": 568, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1392" }, @@ -46280,7 +46703,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1344", - "community": 112, + "community": 22, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1344" }, @@ -46289,7 +46712,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1394", - "community": 112, + "community": 568, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1394" }, @@ -46469,7 +46892,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1400", - "community": 112, + "community": 22, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1400" }, @@ -46478,7 +46901,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1468", - "community": 112, + "community": 568, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1468" }, @@ -46487,7 +46910,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L23", - "community": 21, + "community": 3, "norm_label": "return a small dataframe with the columns the query module expects.", "id": "tests_test_stocks_api_coverage_rationale_23" }, @@ -46622,7 +47045,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L495", - "community": 3, + "community": 535, "norm_label": "replacenan handles direct float nan values (line 34).", "id": "tests_test_stocks_api_coverage_rationale_495" }, @@ -46631,7 +47054,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L509", - "community": 509, + "community": 126, "norm_label": "non-json-dict/list string is left as-is.", "id": "tests_test_stocks_api_coverage_rationale_509" }, @@ -46649,7 +47072,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L527", - "community": 3, + "community": 488, "norm_label": "regression: is_string_dtype fails when column has strings + none (pandas 2.x).", "id": "tests_test_stocks_api_coverage_rationale_527" }, @@ -46658,7 +47081,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L549", - "community": 3, + "community": 520, "norm_label": "all four special_cols should parse correctly when mixed with none.", "id": "tests_test_stocks_api_coverage_rationale_549" }, @@ -46667,7 +47090,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L574", - "community": 3, + "community": 488, "norm_label": "tests covering query.py lines 50-67.", "id": "tests_test_stocks_api_coverage_rationale_574" }, @@ -46676,7 +47099,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L629", - "community": 21, + "community": 28, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_629" }, @@ -46694,7 +47117,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L693", - "community": 263, + "community": 28, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_693" }, @@ -46712,7 +47135,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L736", - "community": 136, + "community": 521, "norm_label": "invalid date format raises exception (line 132).", "id": "tests_test_stocks_api_coverage_rationale_736" }, @@ -46766,7 +47189,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L895", - "community": 17, + "community": 39, "norm_label": "search.strip() == '' should still dedup (line 181).", "id": "tests_test_stocks_api_coverage_rationale_895" }, @@ -46775,7 +47198,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L904", - "community": 17, + "community": 39, "norm_label": "dataframe without time column.", "id": "tests_test_stocks_api_coverage_rationale_904" }, @@ -46784,7 +47207,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L917", - "community": 39, + "community": 17, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_917" }, @@ -46802,7 +47225,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L956", - "community": 17, + "community": 39, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_956" }, @@ -46811,7 +47234,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L964", - "community": 39, + "community": 17, "norm_label": "search with no index match falls back to string startswith.", "id": "tests_test_stocks_api_coverage_rationale_964" }, @@ -46820,7 +47243,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L972", - "community": 39, + "community": 17, "norm_label": "len(daterange) == 1 -> single date filter.", "id": "tests_test_stocks_api_coverage_rationale_972" }, @@ -46829,7 +47252,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L986", - "community": 538, + "community": 21, "norm_label": "cotacao 10y padrao and cotacao 10y ajustada belong to /cotations, not /fundament", "id": "tests_test_stocks_api_coverage_rationale_986" }, @@ -46901,7 +47324,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1396", - "community": 112, + "community": 22, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1396" }, @@ -46910,7 +47333,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1464", - "community": 112, + "community": 568, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1464" }, @@ -46937,7 +47360,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1388", - "community": 112, + "community": 22, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1388" }, @@ -46946,7 +47369,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1456", - "community": 112, + "community": 568, "norm_label": "get /cotations without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1456" }, @@ -47045,7 +47468,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L832", - "community": 17, + "community": 39, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_832" }, @@ -47054,7 +47477,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L885", - "community": 17, + "community": 39, "norm_label": "search.strip() == '' should still dedup (line 181).", "id": "tests_test_stocks_api_coverage_rationale_885" }, @@ -47063,7 +47486,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L894", - "community": 17, + "community": 39, "norm_label": "dataframe without time column.", "id": "tests_test_stocks_api_coverage_rationale_894" }, @@ -47072,7 +47495,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L907", - "community": 39, + "community": 17, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_907" }, @@ -47090,7 +47513,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L946", - "community": 17, + "community": 39, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_946" }, @@ -47099,7 +47522,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L954", - "community": 39, + "community": 17, "norm_label": "search with no index match falls back to string startswith.", "id": "tests_test_stocks_api_coverage_rationale_954" }, @@ -47108,7 +47531,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L962", - "community": 39, + "community": 17, "norm_label": "len(daterange) == 1 -> single date filter.", "id": "tests_test_stocks_api_coverage_rationale_962" }, @@ -47117,7 +47540,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L976", - "community": 538, + "community": 21, "norm_label": "cotacao 10y padrao and cotacao 10y ajustada belong to /cotations, not /fundament", "id": "tests_test_stocks_api_coverage_rationale_976" }, @@ -47666,7 +48089,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/query.py", "source_location": "L49", - "community": 63, + "community": 517, "norm_label": "filtercotationdata()", "id": "stocks_api_query_filtercotationdata" }, @@ -47756,7 +48179,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/query.py", "source_location": "L45", - "community": 63, + "community": 517, "norm_label": "_parsecotationdate()", "id": "stocks_api_query_parsecotationdate" }, @@ -47765,7 +48188,7 @@ "file_type": "code", "source_file": "main/app/stocks_api/query.py", "source_location": "L55", - "community": 63, + "community": 517, "norm_label": "_filtercotationbydate()", "id": "stocks_api_query_filtercotationbydate" }, @@ -47783,7 +48206,7 @@ "file_type": "rationale", "source_file": "main/app/stocks_api/query.py", "source_location": "L46", - "community": 63, + "community": 517, "norm_label": "parse dd-mm-yyyy from cotacao 10y json data field. ponytail: stdlib datetime onl", "id": "stocks_api_query_rationale_46" }, @@ -47792,7 +48215,7 @@ "file_type": "rationale", "source_file": "main/app/stocks_api/query.py", "source_location": "L56", - "community": 63, + "community": 517, "norm_label": "filter cotacao 10y json entries by their inner data field (dd-mm-yyyy).", "id": "stocks_api_query_rationale_56" }, @@ -47810,7 +48233,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L63", - "community": 169, + "community": 54, "norm_label": "getrealtimecotation()", "id": "controller_stocksapi_controller_getrealtimecotation" }, @@ -47864,7 +48287,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L19", - "community": 563, + "community": 186, "norm_label": "sessionproxy", "id": "prometheus_generation_sessionproxy" }, @@ -47873,7 +48296,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L20", - "community": 563, + "community": 186, "norm_label": ".get()", "id": "prometheus_generation_sessionproxy_get" }, @@ -47882,7 +48305,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L23", - "community": 563, + "community": 186, "norm_label": ".post()", "id": "prometheus_generation_sessionproxy_post" }, @@ -47918,7 +48341,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", - "community": 169, + "community": 54, "norm_label": "apikeytest()", "id": "controller_stocksapi_controller_apikeytest" }, @@ -47972,7 +48395,7 @@ "file_type": "code", "source_file": "main/utils/http_session.py", "source_location": "L18", - "community": 491, + "community": 522, "norm_label": "cleanup()", "id": "utils_http_session_cleanup" }, @@ -47981,7 +48404,7 @@ "file_type": "code", "source_file": "main/utils/pagination.py", "source_location": "L1", - "community": 529, + "community": 474, "norm_label": "pagination.py", "id": "main_utils_pagination_py" }, @@ -47990,7 +48413,7 @@ "file_type": "code", "source_file": "main/utils/pagination.py", "source_location": "L4", - "community": 529, + "community": 474, "norm_label": "paginationparams", "id": "utils_pagination_paginationparams" }, @@ -47999,7 +48422,7 @@ "file_type": "code", "source_file": "main/utils/pagination.py", "source_location": "L5", - "community": 529, + "community": 474, "norm_label": ".__init__()", "id": "utils_pagination_paginationparams_init" }, @@ -48008,7 +48431,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L9", - "community": 527, + "community": 251, "norm_label": "set required env vars before test collection. config.py eagerly instantia", "id": "tests_conftest_rationale_9" }, @@ -48017,7 +48440,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L75", - "community": 527, + "community": 251, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_75" }, @@ -48125,7 +48548,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L236", - "community": 90, + "community": 136, "norm_label": "integration tests for the verifyapikey function.", "id": "tests_test_api_key_quota_atomic_rationale_236" }, @@ -48134,7 +48557,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L269", - "community": 90, + "community": 136, "norm_label": "test api key verification with invalid key.", "id": "tests_test_api_key_quota_atomic_rationale_269" }, @@ -48143,7 +48566,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L280", - "community": 90, + "community": 136, "norm_label": "test api key verification with missing key.", "id": "tests_test_api_key_quota_atomic_rationale_280" }, @@ -48152,7 +48575,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L291", - "community": 90, + "community": 136, "norm_label": "test that api key system can be disabled.", "id": "tests_test_api_key_quota_atomic_rationale_291" }, @@ -48557,7 +48980,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L889", - "community": 99, + "community": 16, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_889" }, @@ -48566,7 +48989,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L907", - "community": 99, + "community": 16, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_907" }, @@ -48638,7 +49061,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1037", - "community": 474, + "community": 231, "norm_label": "covers lines 95-98: delete /prometheus/sessions/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_1037" }, @@ -48647,7 +49070,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1040", - "community": 474, + "community": 231, "norm_label": "covers lines 95-98: session deleted.", "id": "tests_test_controllers_coverage_rationale_1040" }, @@ -48656,7 +49079,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1050", - "community": 474, + "community": 231, "norm_label": "covers lines 96-97: session not found.", "id": "tests_test_controllers_coverage_rationale_1050" }, @@ -48674,7 +49097,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1063", - "community": 99, + "community": 16, "norm_label": "covers lines 111-112: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1063" }, @@ -48683,7 +49106,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1081", - "community": 16, + "community": 104, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1081" }, @@ -48710,7 +49133,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1181", - "community": 498, + "community": 539, "norm_label": "covers line 18: get /stocks/health.", "id": "tests_test_controllers_coverage_rationale_1181" }, @@ -48728,7 +49151,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1206", - "community": 14, + "community": 563, "norm_label": "covers line 35: get /stocks/historical.", "id": "tests_test_controllers_coverage_rationale_1206" }, @@ -48737,7 +49160,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1220", - "community": 503, + "community": 14, "norm_label": "covers line 47: get /stocks/fundamental.", "id": "tests_test_controllers_coverage_rationale_1220" }, @@ -48836,7 +49259,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1459", - "community": 519, + "community": 524, "norm_label": "covers lines 50-51: jwt.invalidtokenerror.", "id": "tests_test_controllers_coverage_rationale_1459" }, @@ -48845,7 +49268,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1471", - "community": 498, + "community": 114, "norm_label": "covers line 67: extracttokenpayload re-raises httpexception from verifyaccesstok", "id": "tests_test_controllers_coverage_rationale_1471" }, @@ -48872,7 +49295,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L9", - "community": 251, + "community": 541, "norm_label": ".test_creates_new_session()", "id": "tests_test_http_session_coverage_testgetsession_test_creates_new_session" }, @@ -48881,7 +49304,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L28", - "community": 491, + "community": 522, "norm_label": "testcleanup", "id": "tests_test_http_session_coverage_testcleanup" }, @@ -48890,7 +49313,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L29", - "community": 491, + "community": 522, "norm_label": ".test_cleanup_closes_session()", "id": "tests_test_http_session_coverage_testcleanup_test_cleanup_closes_session" }, @@ -48899,7 +49322,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L37", - "community": 491, + "community": 522, "norm_label": ".test_cleanup_no_session()", "id": "tests_test_http_session_coverage_testcleanup_test_cleanup_no_session" }, @@ -48908,7 +49331,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L46", - "community": 491, + "community": 522, "norm_label": ".test_cleanup_exception_during_close()", "id": "tests_test_http_session_coverage_testcleanup_test_cleanup_exception_during_close" }, @@ -49439,7 +49862,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L494", - "community": 3, + "community": 535, "norm_label": "replacenan handles direct float nan values (line 34).", "id": "tests_test_stocks_api_coverage_rationale_494" }, @@ -49448,7 +49871,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L508", - "community": 509, + "community": 126, "norm_label": "non-json-dict/list string is left as-is.", "id": "tests_test_stocks_api_coverage_rationale_508" }, @@ -49466,7 +49889,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L526", - "community": 3, + "community": 488, "norm_label": "regression: is_string_dtype fails when column has strings + none (pandas 2.x).", "id": "tests_test_stocks_api_coverage_rationale_526" }, @@ -49475,7 +49898,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L548", - "community": 3, + "community": 520, "norm_label": "all four special_cols should parse correctly when mixed with none.", "id": "tests_test_stocks_api_coverage_rationale_548" }, @@ -49484,7 +49907,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L573", - "community": 3, + "community": 488, "norm_label": "tests covering query.py lines 50-67.", "id": "tests_test_stocks_api_coverage_rationale_573" }, @@ -49493,7 +49916,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L628", - "community": 21, + "community": 28, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_628" }, @@ -49511,7 +49934,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L692", - "community": 263, + "community": 28, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_692" }, @@ -49529,7 +49952,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L735", - "community": 136, + "community": 521, "norm_label": "invalid date format raises exception (line 132).", "id": "tests_test_stocks_api_coverage_rationale_735" }, @@ -49565,7 +49988,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L831", - "community": 137, + "community": 39, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_831" }, @@ -49574,7 +49997,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L884", - "community": 17, + "community": 39, "norm_label": "search.strip() == '' should still dedup (line 181).", "id": "tests_test_stocks_api_coverage_rationale_884" }, @@ -49583,7 +50006,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L893", - "community": 17, + "community": 39, "norm_label": "dataframe without time column.", "id": "tests_test_stocks_api_coverage_rationale_893" }, @@ -49592,7 +50015,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L906", - "community": 39, + "community": 17, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_906" }, @@ -49628,7 +50051,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L953", - "community": 39, + "community": 17, "norm_label": "search with no index match falls back to string startswith.", "id": "tests_test_stocks_api_coverage_rationale_953" }, @@ -49637,7 +50060,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L961", - "community": 39, + "community": 17, "norm_label": "len(daterange) == 1 -> single date filter.", "id": "tests_test_stocks_api_coverage_rationale_961" }, @@ -49790,7 +50213,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L731", - "community": 136, + "community": 521, "norm_label": "invalid date format raises exception (line 132).", "id": "tests_test_stocks_api_coverage_rationale_731" }, @@ -49835,7 +50258,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L827", - "community": 137, + "community": 39, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_827" }, @@ -49844,7 +50267,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L876", - "community": 17, + "community": 39, "norm_label": "search.strip() == '' should still dedup (line 181).", "id": "tests_test_stocks_api_coverage_rationale_876" }, @@ -49853,7 +50276,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L898", - "community": 39, + "community": 17, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_898" }, @@ -49880,7 +50303,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L937", - "community": 17, + "community": 39, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_937" }, @@ -49889,7 +50312,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L730", - "community": 136, + "community": 521, "norm_label": "invalid date format raises exception (line 132).", "id": "tests_test_stocks_api_coverage_rationale_730" }, @@ -49925,7 +50348,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L826", - "community": 137, + "community": 39, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_826" }, @@ -49934,7 +50357,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L874", - "community": 17, + "community": 46, "norm_label": "search.strip() == '' should still dedup (line 181).", "id": "tests_test_stocks_api_coverage_rationale_874" }, @@ -49952,7 +50375,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L935", - "community": 17, + "community": 39, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_935" }, @@ -49961,7 +50384,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L943", - "community": 39, + "community": 17, "norm_label": "search with no index match falls back to string startswith.", "id": "tests_test_stocks_api_coverage_rationale_943" }, @@ -49970,7 +50393,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L951", - "community": 39, + "community": 17, "norm_label": "len(daterange) == 1 -> single date filter.", "id": "tests_test_stocks_api_coverage_rationale_951" }, @@ -49979,7 +50402,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/generation.py", "source_location": "L20", - "community": 563, + "community": 186, "norm_label": "thread-safe proxy that delegates to per-thread sessions.", "id": "prometheus_generation_rationale_20" }, @@ -49988,7 +50411,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L582", - "community": 21, + "community": 28, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_582" }, @@ -50006,7 +50429,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L646", - "community": 263, + "community": 28, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_646" }, @@ -50024,7 +50447,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L684", - "community": 136, + "community": 521, "norm_label": "invalid date format raises exception (line 132).", "id": "tests_test_stocks_api_coverage_rationale_684" }, @@ -50060,7 +50483,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L780", - "community": 137, + "community": 39, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_780" }, @@ -50069,7 +50492,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L828", - "community": 17, + "community": 39, "norm_label": "search.strip() == '' should still dedup (line 181).", "id": "tests_test_stocks_api_coverage_rationale_828" }, @@ -50078,7 +50501,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L837", - "community": 17, + "community": 39, "norm_label": "dataframe without time column.", "id": "tests_test_stocks_api_coverage_rationale_837" }, @@ -50087,7 +50510,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L850", - "community": 39, + "community": 17, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_850" }, @@ -50105,7 +50528,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L889", - "community": 17, + "community": 39, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_889" }, @@ -50114,7 +50537,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L897", - "community": 39, + "community": 17, "norm_label": "search with no index match falls back to string startswith.", "id": "tests_test_stocks_api_coverage_rationale_897" }, @@ -50132,7 +50555,7 @@ "file_type": "rationale", "source_file": "tests/test_connectivity_coverage.py", "source_location": "L105", - "community": 562, + "community": 564, "norm_label": "checkserviceconnection \u2014 success, not found, errors.", "id": "tests_test_connectivity_coverage_rationale_105" }, @@ -50159,7 +50582,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L583", - "community": 21, + "community": 28, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_583" }, @@ -50177,7 +50600,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L647", - "community": 263, + "community": 28, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_647" }, @@ -50195,7 +50618,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L685", - "community": 136, + "community": 521, "norm_label": "invalid date format raises exception (line 132).", "id": "tests_test_stocks_api_coverage_rationale_685" }, @@ -50231,7 +50654,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L781", - "community": 137, + "community": 39, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_781" }, @@ -50240,7 +50663,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L838", - "community": 17, + "community": 39, "norm_label": "dataframe without time column.", "id": "tests_test_stocks_api_coverage_rationale_838" }, @@ -50249,7 +50672,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L851", - "community": 39, + "community": 17, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_851" }, @@ -50276,7 +50699,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L890", - "community": 17, + "community": 39, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_890" }, @@ -50339,7 +50762,7 @@ "file_type": "code", "source_file": "main/utils/errors.py", "source_location": "L65", - "community": 120, + "community": 104, "norm_label": "register_error_handlers()", "id": "utils_errors_register_error_handlers" }, @@ -50348,7 +50771,7 @@ "file_type": "code", "source_file": "main/utils/http_session.py", "source_location": "L9", - "community": 522, + "community": 186, "norm_label": "get_session()", "id": "utils_http_session_get_session" }, @@ -50357,7 +50780,7 @@ "file_type": "rationale", "source_file": "main/utils/http_session.py", "source_location": "L10", - "community": 522, + "community": 186, "norm_label": "return a requests.session for the current thread. sessions are created la", "id": "utils_http_session_rationale_10" }, @@ -50366,7 +50789,7 @@ "file_type": "rationale", "source_file": "main/utils/http_session.py", "source_location": "L23", - "community": 491, + "community": 522, "norm_label": "close the main thread's session at interpreter shutdown.", "id": "utils_http_session_rationale_23" }, @@ -50771,7 +51194,7 @@ "file_type": "rationale", "source_file": "main/utils/http_session.py", "source_location": "L9", - "community": 522, + "community": 186, "norm_label": "return a requests.session for the current thread. sessions are created la", "id": "utils_http_session_rationale_9" }, @@ -50798,7 +51221,7 @@ "file_type": "code", "source_file": "main/service/user_service.py", "source_location": "L35", - "community": 488, + "community": 110, "norm_label": "inactivesessionsscheduler()", "id": "service_user_service_inactivesessionsscheduler" }, @@ -51149,7 +51572,7 @@ "file_type": "rationale", "source_file": "main/utils/errors.py", "source_location": "L68", - "community": 120, + "community": 104, "norm_label": "register exception handlers on the fastapi app. note: httpexception and r", "id": "utils_errors_rationale_68" }, @@ -51239,7 +51662,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L489", - "community": 3, + "community": 535, "norm_label": "replacenan handles direct float nan values (line 34).", "id": "tests_test_stocks_api_coverage_rationale_489" }, @@ -51248,7 +51671,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L503", - "community": 509, + "community": 126, "norm_label": "non-json-dict/list string is left as-is.", "id": "tests_test_stocks_api_coverage_rationale_503" }, @@ -51266,7 +51689,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L522", - "community": 3, + "community": 488, "norm_label": "tests covering query.py lines 50-67.", "id": "tests_test_stocks_api_coverage_rationale_522" }, @@ -51275,7 +51698,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L577", - "community": 21, + "community": 28, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_577" }, @@ -51293,7 +51716,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L641", - "community": 263, + "community": 28, "norm_label": "no historical data columns -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_641" }, @@ -51302,7 +51725,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L679", - "community": 136, + "community": 521, "norm_label": "invalid date format raises exception (line 132).", "id": "tests_test_stocks_api_coverage_rationale_679" }, @@ -51347,7 +51770,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L775", - "community": 137, + "community": 39, "norm_label": "invalid date -> inner 400 caught by outer except -> 500.", "id": "tests_test_stocks_api_coverage_rationale_775" }, @@ -51356,7 +51779,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L823", - "community": 17, + "community": 39, "norm_label": "search.strip() == '' should still dedup (line 181).", "id": "tests_test_stocks_api_coverage_rationale_823" }, @@ -51365,7 +51788,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L845", - "community": 39, + "community": 17, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_845" }, @@ -51392,7 +51815,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L892", - "community": 39, + "community": 17, "norm_label": "search with no index match falls back to string startswith.", "id": "tests_test_stocks_api_coverage_rationale_892" }, @@ -51401,7 +51824,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L900", - "community": 39, + "community": 17, "norm_label": "len(daterange) == 1 -> single date filter.", "id": "tests_test_stocks_api_coverage_rationale_900" }, @@ -51410,7 +51833,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L62", - "community": 527, + "community": 251, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_62" }, @@ -51419,7 +51842,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L61", - "community": 527, + "community": 251, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_61" }, @@ -51428,7 +51851,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L57", - "community": 527, + "community": 251, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_57" }, @@ -51437,7 +51860,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L49", - "community": 527, + "community": 251, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_49" }, @@ -51662,7 +52085,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L185", - "community": 543, + "community": 161, "norm_label": "category 7: code quality (low)", "id": "server_code_review_report_category_7_code_quality_low" }, @@ -51671,7 +52094,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L187", - "community": 543, + "community": 161, "norm_label": "issue 7.1 \u2014 unused imports", "id": "server_code_review_report_issue_7_1_unused_imports" }, @@ -51680,7 +52103,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L194", - "community": 543, + "community": 161, "norm_label": "issue 7.2 \u2014 missing type hints", "id": "server_code_review_report_issue_7_2_missing_type_hints" }, @@ -51689,7 +52112,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L205", - "community": 543, + "community": 161, "norm_label": "issue 7.3 \u2014 `usermanager.__init__` does nothing", "id": "server_code_review_report_issue_7_3_usermanager_init_does_nothing" }, @@ -51698,7 +52121,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L210", - "community": 543, + "community": 161, "norm_label": "issue 7.4 \u2014 mixed async/sync in roles.py", "id": "server_code_review_report_issue_7_4_mixed_async_sync_in_roles_py" }, @@ -51707,7 +52130,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L217", - "community": 161, + "community": 538, "norm_label": "category 8: testing gaps (medium)", "id": "server_code_review_report_category_8_testing_gaps_medium" }, @@ -51716,7 +52139,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L219", - "community": 161, + "community": 538, "norm_label": "issue 8.1 \u2014 no integration tests for full request lifecycle", "id": "server_code_review_report_issue_8_1_no_integration_tests_for_full_request_lifecycle" }, @@ -51725,7 +52148,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L223", - "community": 161, + "community": 538, "norm_label": "issue 8.2 \u2014 no tests for scraper, stocks query, or cache", "id": "server_code_review_report_issue_8_2_no_tests_for_scraper_stocks_query_or_cache" }, @@ -51734,7 +52157,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L230", - "community": 161, + "community": 538, "norm_label": "issue 8.3 \u2014 no tests for google oauth callback", "id": "server_code_review_report_issue_8_3_no_tests_for_google_oauth_callback" }, @@ -51743,7 +52166,7 @@ "file_type": "document", "source_file": "CODE_REVIEW_REPORT.md", "source_location": "L234", - "community": 161, + "community": 538, "norm_label": "issue 8.4 \u2014 no tests for session cleanup", "id": "server_code_review_report_issue_8_4_no_tests_for_session_cleanup" }, @@ -51806,7 +52229,7 @@ "file_type": "rationale", "source_file": "main/utils/errors.py", "source_location": "L67", - "community": 120, + "community": 104, "norm_label": "register exception handlers on the fastapi app. note: httpexception and r", "id": "utils_errors_rationale_67" }, @@ -51977,7 +52400,7 @@ "file_type": "code", "source_file": "tests/test_stocks_cache.py", "source_location": "L135", - "community": 186, + "community": 512, "norm_label": "testqueryoptimization", "id": "tests_test_stocks_cache_testqueryoptimization" }, @@ -51986,7 +52409,7 @@ "file_type": "code", "source_file": "tests/test_stocks_cache.py", "source_location": "L138", - "community": 186, + "community": 512, "norm_label": ".test_all_optimizations_present()", "id": "tests_test_stocks_cache_testqueryoptimization_test_all_optimizations_present" }, @@ -51995,7 +52418,7 @@ "file_type": "code", "source_file": "tests/test_stocks_cache.py", "source_location": "L153", - "community": 186, + "community": 512, "norm_label": ".test_query_filter_uses_optimization()", "id": "tests_test_stocks_cache_testqueryoptimization_test_query_filter_uses_optimization" }, @@ -52067,7 +52490,7 @@ "file_type": "code", "source_file": "tests/test_stocks_cache.py", "source_location": "L299", - "community": 502, + "community": 570, "norm_label": "testfilterbysearchterms", "id": "tests_test_stocks_cache_testfilterbysearchterms" }, @@ -52076,7 +52499,7 @@ "file_type": "code", "source_file": "tests/test_stocks_cache.py", "source_location": "L302", - "community": 502, + "community": 570, "norm_label": ".test_filter_with_tickerindex()", "id": "tests_test_stocks_cache_testfilterbysearchterms_test_filter_with_tickerindex" }, @@ -52247,7 +52670,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L136", - "community": 186, + "community": 512, "norm_label": "integration tests for all query optimizations", "id": "tests_test_stocks_cache_rationale_136" }, @@ -52256,7 +52679,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L139", - "community": 186, + "community": 512, "norm_label": "all optimizations should be implemented", "id": "tests_test_stocks_cache_rationale_139" }, @@ -52265,7 +52688,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L154", - "community": 186, + "community": 512, "norm_label": "query filter should use ticker index", "id": "tests_test_stocks_cache_rationale_154" }, @@ -52337,7 +52760,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L300", - "community": 502, + "community": 570, "norm_label": "tests for optimized search filtering", "id": "tests_test_stocks_cache_rationale_300" }, @@ -52346,7 +52769,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L303", - "community": 502, + "community": 570, "norm_label": "filter should use ticker index for o(1) lookup", "id": "tests_test_stocks_cache_rationale_303" }, @@ -52535,7 +52958,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L138", - "community": 186, + "community": 512, "norm_label": "integration tests for all query optimizations", "id": "tests_test_stocks_cache_rationale_138" }, @@ -52544,7 +52967,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L141", - "community": 186, + "community": 512, "norm_label": "all optimizations should be implemented", "id": "tests_test_stocks_cache_rationale_141" }, @@ -52553,7 +52976,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L156", - "community": 186, + "community": 512, "norm_label": "query filter should use ticker index", "id": "tests_test_stocks_cache_rationale_156" }, @@ -52625,7 +53048,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L302", - "community": 502, + "community": 570, "norm_label": "tests for optimized search filtering", "id": "tests_test_stocks_cache_rationale_302" }, @@ -52634,7 +53057,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L305", - "community": 502, + "community": 570, "norm_label": "filter should use ticker index for o(1) lookup", "id": "tests_test_stocks_cache_rationale_305" }, @@ -52724,7 +53147,7 @@ "file_type": "code", "source_file": "tests/test_stocks_cache.py", "source_location": "L304", - "community": 502, + "community": 570, "norm_label": ".test_filter_with_tickerindex()", "id": "tests_test_stocks_cache_testfilterbysearchterms_test_filter_with_tickerIndex" }, @@ -52733,7 +53156,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L1", - "community": 490, + "community": 183, "norm_label": "test_stocks_optimization.py", "id": "tests_test_stocks_optimization_py" }, @@ -52742,7 +53165,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L17", - "community": 490, + "community": 503, "norm_label": "testtickerindex", "id": "tests_test_stocks_optimization_testtickerindex" }, @@ -52751,7 +53174,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L20", - "community": 490, + "community": 503, "norm_label": ".test_tickerindex_built_after_cache_load()", "id": "tests_test_stocks_optimization_testtickerindex_test_tickerIndex_built_after_cache_load" }, @@ -52760,7 +53183,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L28", - "community": 490, + "community": 503, "norm_label": ".test_tickerindex_contains_all_tickers()", "id": "tests_test_stocks_optimization_testtickerindex_test_tickerIndex_contains_all_tickers" }, @@ -52769,7 +53192,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L38", - "community": 490, + "community": 503, "norm_label": ".test_tickerindex_case_insensitive()", "id": "tests_test_stocks_optimization_testtickerindex_test_tickerIndex_case_insensitive" }, @@ -52778,7 +53201,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L47", - "community": 490, + "community": 503, "norm_label": ".test_ticker_lookup_returns_valid_index()", "id": "tests_test_stocks_optimization_testtickerindex_test_ticker_lookup_returns_valid_index" }, @@ -52787,7 +53210,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L58", - "community": 490, + "community": 503, "norm_label": ".test_tickerindex_rebuilt_on_cache_refresh()", "id": "tests_test_stocks_optimization_testtickerindex_test_tickerIndex_rebuilt_on_cache_refresh" }, @@ -52850,7 +53273,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L111", - "community": 490, + "community": 183, "norm_label": "testconnectionpool", "id": "tests_test_stocks_optimization_testconnectionpool" }, @@ -52859,7 +53282,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L114", - "community": 490, + "community": 183, "norm_label": ".test_stocks_engine_has_pool_configuration()", "id": "tests_test_stocks_optimization_testconnectionpool_test_stocks_engine_has_pool_configuration" }, @@ -52868,7 +53291,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L123", - "community": 490, + "community": 183, "norm_label": "testlazydeserialization", "id": "tests_test_stocks_optimization_testlazydeserialization" }, @@ -52877,7 +53300,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L126", - "community": 490, + "community": 183, "norm_label": ".test_query_manager_has_deserialize_method()", "id": "tests_test_stocks_optimization_testlazydeserialization_test_query_manager_has_deserialize_method" }, @@ -52886,7 +53309,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L137", - "community": 518, + "community": 183, "norm_label": "testqueryoptimization", "id": "tests_test_stocks_optimization_testqueryoptimization" }, @@ -52895,7 +53318,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L140", - "community": 518, + "community": 183, "norm_label": ".test_all_optimizations_present()", "id": "tests_test_stocks_optimization_testqueryoptimization_test_all_optimizations_present" }, @@ -52904,7 +53327,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L155", - "community": 518, + "community": 183, "norm_label": ".test_query_filter_uses_optimization()", "id": "tests_test_stocks_optimization_testqueryoptimization_test_query_filter_uses_optimization" }, @@ -52976,7 +53399,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L301", - "community": 524, + "community": 490, "norm_label": "testfilterbysearchterms", "id": "tests_test_stocks_optimization_testfilterbysearchterms" }, @@ -52985,7 +53408,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L304", - "community": 524, + "community": 490, "norm_label": ".test_filter_with_tickerindex()", "id": "tests_test_stocks_optimization_testfilterbysearchterms_test_filter_with_tickerIndex" }, @@ -52994,7 +53417,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L310", - "community": 539, + "community": 130, "norm_label": "testqueryperformance", "id": "tests_test_stocks_optimization_testqueryperformance" }, @@ -53003,7 +53426,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L313", - "community": 539, + "community": 130, "norm_label": ".test_query_response_time_under_1_second()", "id": "tests_test_stocks_optimization_testqueryperformance_test_query_response_time_under_1_second" }, @@ -53012,7 +53435,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L18", - "community": 490, + "community": 503, "norm_label": "tests for dynamic ticker index feature", "id": "tests_test_stocks_optimization_rationale_18" }, @@ -53021,7 +53444,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L21", - "community": 490, + "community": 503, "norm_label": "ticker index should be built when cache is loaded", "id": "tests_test_stocks_optimization_rationale_21" }, @@ -53030,7 +53453,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L29", - "community": 490, + "community": 503, "norm_label": "ticker index should contain all tickers from cache", "id": "tests_test_stocks_optimization_rationale_29" }, @@ -53039,7 +53462,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L39", - "community": 490, + "community": 503, "norm_label": "ticker index should be case-insensitive", "id": "tests_test_stocks_optimization_rationale_39" }, @@ -53048,7 +53471,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L48", - "community": 490, + "community": 503, "norm_label": "looking up ticker should return valid row index", "id": "tests_test_stocks_optimization_rationale_48" }, @@ -53057,7 +53480,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L59", - "community": 490, + "community": 503, "norm_label": "ticker index should be rebuilt when cache refreshes", "id": "tests_test_stocks_optimization_rationale_59" }, @@ -53120,7 +53543,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L112", - "community": 490, + "community": 183, "norm_label": "tests for connection pool configuration", "id": "tests_test_stocks_optimization_rationale_112" }, @@ -53129,7 +53552,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L115", - "community": 490, + "community": 183, "norm_label": "stocks engine should have optimized pool settings", "id": "tests_test_stocks_optimization_rationale_115" }, @@ -53138,7 +53561,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L124", - "community": 490, + "community": 183, "norm_label": "tests for lazy json deserialization", "id": "tests_test_stocks_optimization_rationale_124" }, @@ -53147,7 +53570,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L127", - "community": 490, + "community": 183, "norm_label": "query manager should have deserialize method", "id": "tests_test_stocks_optimization_rationale_127" }, @@ -53156,7 +53579,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L138", - "community": 518, + "community": 183, "norm_label": "integration tests for all query optimizations", "id": "tests_test_stocks_optimization_rationale_138" }, @@ -53165,7 +53588,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L141", - "community": 518, + "community": 183, "norm_label": "all optimizations should be implemented", "id": "tests_test_stocks_optimization_rationale_141" }, @@ -53174,7 +53597,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L156", - "community": 518, + "community": 183, "norm_label": "query filter should use ticker index", "id": "tests_test_stocks_optimization_rationale_156" }, @@ -53246,7 +53669,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L302", - "community": 524, + "community": 490, "norm_label": "tests for optimized search filtering", "id": "tests_test_stocks_optimization_rationale_302" }, @@ -53255,7 +53678,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L305", - "community": 524, + "community": 490, "norm_label": "filter should use ticker index for o(1) lookup", "id": "tests_test_stocks_optimization_rationale_305" }, @@ -53264,7 +53687,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L311", - "community": 539, + "community": 130, "norm_label": "performance tests for query operations", "id": "tests_test_stocks_optimization_rationale_311" }, @@ -53273,7 +53696,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L314", - "community": 539, + "community": 130, "norm_label": "query should respond within 1 second", "id": "tests_test_stocks_optimization_rationale_314" }, @@ -53291,7 +53714,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L173", - "community": 524, + "community": 490, "norm_label": "tests for optimized search filtering", "id": "tests_test_stocks_optimization_rationale_173" }, @@ -53300,7 +53723,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L176", - "community": 524, + "community": 490, "norm_label": "filter should use ticker index for o(1) lookup", "id": "tests_test_stocks_optimization_rationale_176" }, @@ -53309,7 +53732,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L182", - "community": 539, + "community": 130, "norm_label": "performance tests for query operations", "id": "tests_test_stocks_optimization_rationale_182" }, @@ -53318,7 +53741,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L185", - "community": 539, + "community": 130, "norm_label": "query should respond within 1 second", "id": "tests_test_stocks_optimization_rationale_185" }, @@ -53601,7 +54024,7 @@ "label": "FastAPI", "file_type": "rationale", "source_file": "README.md", - "community": 529, + "community": 474, "norm_label": "fastapi", "id": "fastapi" }, @@ -53745,7 +54168,7 @@ "label": "Pytest Testing", "file_type": "rationale", "source_file": "pyproject.toml", - "community": 215, + "community": 541, "norm_label": "pytest testing", "id": "pytest" }, @@ -58836,16 +59259,6 @@ "source": "main_app_authentication_session_py", "target": "authentication_session_sessionmanager" }, - { - "relation": "contains", - "confidence": "EXTRACTED", - "source_file": "main/app/authentication/session.py", - "source_location": "L17", - "weight": 1.0, - "confidence_score": 1.0, - "source": "main_app_authentication_session_py", - "target": "authentication_session_getdevicename" - }, { "relation": "contains", "confidence": "EXTRACTED", @@ -58926,6 +59339,16 @@ "source": "main_app_authentication_session_py", "target": "authentication_session_validatesession" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/authentication/session.py", + "source_location": "L17", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_authentication_session_py", + "target": "authentication_session_getdevicename" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -59675,6 +60098,16 @@ "source": "main_app_prometheus_agent_py", "target": "prometheus_agent_safefilter" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/agent.py", + "source_location": "L31", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_agent_py", + "target": "prometheus_agent_persistevent" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -59805,6 +60238,17 @@ "source": "main_app_prometheus_agent_py", "target": "prometheus_agent_chatsession" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/agent.py", + "source_location": "L344", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_agent_prometheus_streammessage", + "target": "prometheus_agent_persistevent" + }, { "relation": "calls", "context": "call", @@ -60776,121 +61220,121 @@ "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L119", + "source_location": "L133", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_gethistoricalfields" + "target": "prometheus_compact_getmetricregex" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L123", + "source_location": "L117", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_getfundamentalcolumns" + "target": "prometheus_compact_dedup" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L127", + "source_location": "L109", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_invalidatefielddata" + "target": "prometheus_compact_extracttickers" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L133", + "source_location": "L113", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_getmetricregex" + "target": "prometheus_compact_extractmetrics" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L117", + "source_location": "L123", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_dedup" + "target": "prometheus_compact_extractdecisions" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L109", + "source_location": "L137", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_extracttickers" + "target": "prometheus_compact_extractsnapshots" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L113", + "source_location": "L150", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_extractmetrics" + "target": "prometheus_compact_extracttoolcalls" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L123", + "source_location": "L166", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_extractdecisions" + "target": "prometheus_compact_buildsummary" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L137", + "source_location": "L186", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_extractsnapshots" + "target": "prometheus_compact_prometheuscompactor" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L150", + "source_location": "L119", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_extracttoolcalls" + "target": "prometheus_compact_gethistoricalfields" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L166", + "source_location": "L123", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_buildsummary" + "target": "prometheus_compact_getfundamentalcolumns" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L186", + "source_location": "L127", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_compact_py", - "target": "prometheus_compact_prometheuscompactor" + "target": "prometheus_compact_invalidatefielddata" }, { "relation": "contains", @@ -60994,10 +61438,10 @@ "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L120", + "source_location": "L136", "weight": 1.0, "confidence_score": 1.0, - "source": "prometheus_compact_gethistoricalfields", + "source": "prometheus_compact_getmetricregex", "target": "prometheus_compact_loadfielddata" }, { @@ -61005,10 +61449,10 @@ "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L124", + "source_location": "L120", "weight": 1.0, "confidence_score": 1.0, - "source": "prometheus_compact_getfundamentalcolumns", + "source": "prometheus_compact_gethistoricalfields", "target": "prometheus_compact_loadfielddata" }, { @@ -61016,10 +61460,10 @@ "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/compact.py", - "source_location": "L136", + "source_location": "L124", "weight": 1.0, "confidence_score": 1.0, - "source": "prometheus_compact_getmetricregex", + "source": "prometheus_compact_getfundamentalcolumns", "target": "prometheus_compact_loadfielddata" }, { @@ -61363,6 +61807,16 @@ "source": "main_app_prometheus_mcp_py", "target": "prometheus_mcp_buildclient" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/mcp.py", + "source_location": "L29", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_mcp_py", + "target": "prometheus_mcp_connect" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -61393,6 +61847,17 @@ "source": "main_app_prometheus_mcp_py", "target": "prometheus_mcp_parseservers" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/mcp.py", + "source_location": "L30", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_mcp_connect", + "target": "prometheus_mcp_buildclient" + }, { "relation": "calls", "context": "call", @@ -61426,6 +61891,28 @@ "source": "prometheus_mcp_buildclient", "target": "prometheus_mcp_ensurefastmcp" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/mcp.py", + "source_location": "L47", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_mcp_mcpclientpool_initialize", + "target": "prometheus_mcp_connect" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/mcp.py", + "source_location": "L84", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_mcp_mcpclientpool_reconnect", + "target": "prometheus_mcp_connect" + }, { "relation": "method", "confidence": "EXTRACTED", @@ -61551,26 +62038,6 @@ "source": "prometheus_mcp_mcpclientpool_reconnect", "target": "prometheus_mcp_parseservers" }, - { - "relation": "contains", - "confidence": "EXTRACTED", - "source_file": "main/app/prometheus/memory.py", - "source_location": "L41", - "weight": 1.0, - "confidence_score": 1.0, - "source": "main_app_prometheus_memory_py", - "target": "prometheus_memory_matrixkey" - }, - { - "relation": "contains", - "confidence": "EXTRACTED", - "source_file": "main/app/prometheus/memory.py", - "source_location": "L48", - "weight": 1.0, - "confidence_score": 1.0, - "source": "main_app_prometheus_memory_py", - "target": "prometheus_memory_matrixusertag" - }, { "relation": "contains", "confidence": "EXTRACTED", @@ -61641,6 +62108,16 @@ "source": "main_app_prometheus_memory_py", "target": "prometheus_memory_findsimilarkey" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L123", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_scorerow" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -61701,6 +62178,16 @@ "source": "main_app_prometheus_memory_py", "target": "prometheus_memory_countmemories" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L194", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_touch" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -61755,21 +62242,41 @@ "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/memory.py", - "source_location": "L342", + "source_location": "L318", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_memory_py", - "target": "prometheus_memory_counttokenscached" + "target": "prometheus_memory_extract" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/memory.py", - "source_location": "L318", + "source_location": "L41", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_memory_py", - "target": "prometheus_memory_extract" + "target": "prometheus_memory_matrixkey" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L48", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_matrixusertag" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L342", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_counttokenscached" }, { "relation": "contains", @@ -61996,21 +62503,21 @@ "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/memory.py", - "source_location": "L54", + "source_location": "L290", "weight": 1.0, "confidence_score": 1.0, - "source": "prometheus_memory_getmatrix", - "target": "prometheus_memory_matrixkey" + "source": "prometheus_memory_search", + "target": "prometheus_memory_getmatrix" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/memory.py", - "source_location": "L46", + "source_location": "L54", "weight": 1.0, "confidence_score": 1.0, - "source": "prometheus_memory_getmatrixasync", + "source": "prometheus_memory_getmatrix", "target": "prometheus_memory_matrixkey" }, { @@ -62024,28 +62531,6 @@ "source": "prometheus_memory_getmatrix", "target": "prometheus_memory_matrixusertag" }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/prometheus/memory.py", - "source_location": "L51", - "weight": 1.0, - "confidence_score": 1.0, - "source": "prometheus_memory_getmatrixasync", - "target": "prometheus_memory_matrixusertag" - }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/prometheus/memory.py", - "source_location": "L290", - "weight": 1.0, - "confidence_score": 1.0, - "source": "prometheus_memory_search", - "target": "prometheus_memory_getmatrix" - }, { "relation": "calls", "context": "call", @@ -62211,6 +62696,28 @@ "source": "prometheus_memory_findsimilarkey", "target": "prometheus_memory_normalize_key" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L140", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_scorerecency", + "target": "prometheus_memory_scorerow" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L159", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_scorecandidates", + "target": "prometheus_memory_scorerow" + }, { "relation": "calls", "context": "call", @@ -62218,9 +62725,9 @@ "source_file": "main/app/prometheus/memory.py", "source_location": "L314", "weight": 1.0, + "confidence_score": 1.0, "source": "prometheus_memory_search", - "target": "prometheus_memory_scorerecency", - "confidence_score": 1.0 + "target": "prometheus_memory_scorerecency" }, { "relation": "calls", @@ -62251,9 +62758,9 @@ "source_file": "main/app/prometheus/memory.py", "source_location": "L342", "weight": 1.0, + "confidence_score": 1.0, "source": "prometheus_memory_search", - "target": "prometheus_memory_scorecandidates", - "confidence_score": 1.0 + "target": "prometheus_memory_scorecandidates" }, { "relation": "calls", @@ -62277,6 +62784,17 @@ "source": "prometheus_memory_searchasync", "target": "prometheus_memory_scorecandidates" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L461", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_extract", + "target": "prometheus_memory_sumtokens" + }, { "relation": "calls", "context": "call", @@ -62565,6 +63083,17 @@ "source": "prometheus_memory_upsertmemoryasync", "target": "prometheus_memory_countmemories" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L227", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_upsertmemory", + "target": "prometheus_memory_touch" + }, { "relation": "calls", "context": "call", @@ -62876,24 +63405,24 @@ { "relation": "calls", "context": "call", - "confidence": "EXTRACTED", + "confidence": "INFERRED", + "confidence_score": 0.8, "source_file": "main/app/prometheus/memory.py", - "source_location": "L386", + "source_location": "L367", "weight": 1.0, - "confidence_score": 1.0, "source": "prometheus_memory_extract", - "target": "prometheus_memory_counttokenscached" + "target": "prometheus_vector_embed" }, { "relation": "calls", "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, + "confidence": "EXTRACTED", "source_file": "main/app/prometheus/memory.py", - "source_location": "L367", + "source_location": "L386", "weight": 1.0, + "confidence_score": 1.0, "source": "prometheus_memory_extract", - "target": "prometheus_vector_embed" + "target": "prometheus_memory_counttokenscached" }, { "relation": "contains", @@ -63019,41 +63548,41 @@ "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L186", + "source_location": "L197", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_sandbox_py", - "target": "prometheus_sandbox_write_bytes" + "target": "prometheus_sandbox_delete_file" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L197", + "source_location": "L215", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_sandbox_py", - "target": "prometheus_sandbox_delete_file" + "target": "prometheus_sandbox_synctosandbox" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L215", + "source_location": "L234", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_sandbox_py", - "target": "prometheus_sandbox_synctosandbox" + "target": "prometheus_sandbox_syncfromsandbox" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L234", + "source_location": "L186", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_prometheus_sandbox_py", - "target": "prometheus_sandbox_syncfromsandbox" + "target": "prometheus_sandbox_write_bytes" }, { "relation": "contains", @@ -63363,17 +63892,6 @@ "source": "prometheus_sandbox_list_files", "target": "prometheus_sandbox_hostpath" }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L188", - "weight": 1.0, - "confidence_score": 1.0, - "source": "prometheus_sandbox_write_bytes", - "target": "prometheus_sandbox_hostpath" - }, { "relation": "calls", "context": "call", @@ -63418,6 +63936,17 @@ "source": "controller_prometheus_controller_downloadworkspacefile", "target": "prometheus_sandbox_hostpath" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/sandbox.py", + "source_location": "L188", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_sandbox_write_bytes", + "target": "prometheus_sandbox_hostpath" + }, { "relation": "calls", "context": "call", @@ -64184,9 +64713,9 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L21", "weight": 1.0, + "confidence_score": 1.0, "source": "prometheus_tools_rationale_21", - "target": "prometheus_tools_search_memory", - "confidence_score": 1.0 + "target": "prometheus_tools_search_memory" }, { "relation": "rationale_for", @@ -64295,9 +64824,9 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L52", "weight": 1.0, + "confidence_score": 1.0, "source": "prometheus_tools_rationale_52", - "target": "prometheus_tools_save_memory", - "confidence_score": 1.0 + "target": "prometheus_tools_save_memory" }, { "relation": "calls", @@ -64417,9 +64946,9 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L94", "weight": 1.0, + "confidence_score": 1.0, "source": "prometheus_tools_rationale_94", - "target": "prometheus_tools_execute_code", - "confidence_score": 1.0 + "target": "prometheus_tools_execute_code" }, { "relation": "rationale_for", @@ -64507,9 +65036,9 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L115", "weight": 1.0, + "confidence_score": 1.0, "source": "prometheus_tools_rationale_115", - "target": "prometheus_tools_read_file", - "confidence_score": 1.0 + "target": "prometheus_tools_read_file" }, { "relation": "rationale_for", @@ -64597,9 +65126,9 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L129", "weight": 1.0, + "confidence_score": 1.0, "source": "prometheus_tools_rationale_129", - "target": "prometheus_tools_write_file", - "confidence_score": 1.0 + "target": "prometheus_tools_write_file" }, { "relation": "rationale_for", @@ -64697,9 +65226,9 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L145", "weight": 1.0, + "confidence_score": 1.0, "source": "prometheus_tools_rationale_145", - "target": "prometheus_tools_list_files", - "confidence_score": 1.0 + "target": "prometheus_tools_list_files" }, { "relation": "rationale_for", @@ -64787,9 +65316,9 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L158", "weight": 1.0, + "confidence_score": 1.0, "source": "prometheus_tools_rationale_158", - "target": "prometheus_tools_serve_file", - "confidence_score": 1.0 + "target": "prometheus_tools_serve_file" }, { "relation": "rationale_for", @@ -66973,71 +67502,71 @@ "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L51", + "source_location": "L59", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_stocks_api_compress_py", - "target": "stocks_api_compress_walk" + "target": "stocks_api_compress_compactvalue" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L59", + "source_location": "L98", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_stocks_api_compress_py", - "target": "stocks_api_compress_compactvalue" + "target": "stocks_api_compress_compactrow" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L80", + "source_location": "L126", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_stocks_api_compress_py", - "target": "stocks_api_compress_tocolumnar" + "target": "stocks_api_compress_compactcotations" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L89", + "source_location": "L160", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_stocks_api_compress_py", - "target": "stocks_api_compress_fixheaders" + "target": "stocks_api_compress_compressresponse" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L98", + "source_location": "L51", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_stocks_api_compress_py", - "target": "stocks_api_compress_compactrow" + "target": "stocks_api_compress_walk" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L126", + "source_location": "L80", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_stocks_api_compress_py", - "target": "stocks_api_compress_compactcotations" + "target": "stocks_api_compress_tocolumnar" }, { "relation": "contains", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/compress.py", - "source_location": "L160", + "source_location": "L89", "weight": 1.0, "confidence_score": 1.0, "source": "main_app_stocks_api_compress_py", - "target": "stocks_api_compress_compressresponse" + "target": "stocks_api_compress_fixheaders" }, { "relation": "calls", @@ -67105,17 +67634,6 @@ "source": "controller_stocksapi_controller_listfields", "target": "stocks_api_compress_getnest" }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/compress.py", - "source_location": "L179", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_compress_compressresponse", - "target": "stocks_api_compress_walk" - }, { "relation": "calls", "context": "call", @@ -67127,39 +67645,6 @@ "source": "stocks_api_compress_compactcotations", "target": "stocks_api_compress_compactvalue" }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/compress.py", - "source_location": "L181", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_compress_compressresponse", - "target": "stocks_api_compress_tocolumnar" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "main/app/stocks_api/compress.py", - "source_location": "L84", - "weight": 1.0, - "source": "stocks_api_compress_tocolumnar", - "target": "utils_roles_all" - }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/compress.py", - "source_location": "L185", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_compress_compressresponse", - "target": "stocks_api_compress_fixheaders" - }, { "relation": "calls", "context": "call", @@ -67237,6 +67722,39 @@ "source": "controller_stocksapi_controller_getlivecotation", "target": "stocks_api_compress_compressresponse" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/compress.py", + "source_location": "L179", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_compress_compressresponse", + "target": "stocks_api_compress_walk" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/compress.py", + "source_location": "L181", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_compress_compressresponse", + "target": "stocks_api_compress_tocolumnar" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/compress.py", + "source_location": "L185", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_compress_compressresponse", + "target": "stocks_api_compress_fixheaders" + }, { "relation": "imports_from", "context": "import", @@ -67543,6 +68061,106 @@ "source": "main_app_stocks_api_query_py", "target": "stocks_api_query_filtercotationcolumn" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L53", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_baseframe" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L66", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_validatefields" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L79", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_envelope" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L90", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_finalize" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L123", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_deserializejsoncolumns" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L151", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_filterbysearchterms" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L169", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_queryhistorical" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L226", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_queryfundamental" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L284", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_querycotations" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L325", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_querylivecotation" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -67593,6 +68211,28 @@ "source": "main_app_stocks_api_query_py", "target": "stocks_api_query_filtercotationbydate" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L86", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_envelope", + "target": "stocks_api_query_sanitizenanvalues" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L142", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_deserializejsoncolumns", + "target": "stocks_api_query_sanitizenanvalues" + }, { "relation": "calls", "context": "call", @@ -67648,6 +68288,17 @@ "source": "stocks_api_query_sanitizenanvalues", "target": "stocks_api_query_stocksquerymanager_querycotations" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L119", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_finalize", + "target": "stocks_api_query_filtercotationcolumn" + }, { "relation": "calls", "context": "call", @@ -67736,518 +68387,27 @@ "source": "stocks_api_query_filtercotationcolumn", "target": "tests_test_stocks_api_coverage_testquerycotations_test_cotations_filter_cotation_column_handles_non_list" }, - { - "relation": "method", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L15", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "stocks_api_query_stocksquerymanager_init" - }, - { - "relation": "method", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L58", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "stocks_api_query_stocksquerymanager_baseframe" - }, - { - "relation": "method", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L69", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "stocks_api_query_stocksquerymanager_finalize" - }, - { - "relation": "method", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L23", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "stocks_api_query_stocksquerymanager_deserializejsoncolumns" - }, - { - "relation": "method", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L52", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "stocks_api_query_stocksquerymanager_filterbysearchterms" - }, - { - "relation": "method", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L61", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "stocks_api_query_stocksquerymanager_queryhistorical" - }, - { - "relation": "method", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L126", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "stocks_api_query_stocksquerymanager_queryfundamental" - }, - { - "relation": "method", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L278", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "stocks_api_query_stocksquerymanager_querycotations" - }, - { - "relation": "method", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L348", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "stocks_api_query_stocksquerymanager_querylivecotation" - }, - { - "relation": "method", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L110", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "stocks_api_query_stocksquerymanager_executequery" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L729", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_teststockscachemanager" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L729", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testverifyapikey" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L729", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testgeneratesecurekey" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L729", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testcreatekey" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L729", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testdeserializejsoncolumns" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L729", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testfilterbysearchterms" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L729", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testqueryhistorical" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L729", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testqueryfundamental" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L989", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testquerycotations" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L1261", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testquerylivecotation" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L419", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testdeserializejsoncolumns_make_manager" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L530", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testfilterbysearchterms_make_manager" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L587", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testqueryhistorical_make_manager" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L731", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testqueryfundamental_make_manager" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L1017", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_does_not_mutate_cache_time_dtype" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L994", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testquerycotations_make_manager" - }, { "relation": "calls", "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_api_coverage.py", - "source_location": "L1266", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_api_coverage_testquerylivecotation_make_manager" - }, - { - "relation": "method", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L344", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "stocks_api_query_stocksquerymanager_queryrealtimecotation" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_cache.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_cache_testtickerindex" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_cache.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_cache_testquerycaching" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_cache.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_cache_testconnectionpool" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_cache.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_cache_testlazydeserialization" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_cache.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_cache_testqueryoptimization" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_cache.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_cache_testperformancebenchmarks" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_cache.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_cache_testfilterbysearchterms" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_cache.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_cache_testqueryperformance" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_cache.py", - "source_location": "L131", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_cache_testlazydeserialization_test_query_manager_has_deserialize_method" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_cache.py", - "source_location": "L160", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_cache_testqueryoptimization_test_query_filter_uses_optimization" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_optimization.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_optimization_testtickerindex" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_optimization.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_optimization_testquerycaching" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_optimization.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_optimization_testconnectionpool" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_optimization.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_optimization_testlazydeserialization" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_optimization.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_optimization_testqueryoptimization" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_optimization.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_optimization_testperformancebenchmarks" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_optimization.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_optimization_testfilterbysearchterms" - }, - { - "relation": "uses", - "confidence": "INFERRED", - "source_file": "tests/test_stocks_optimization.py", - "source_location": "L157", - "weight": 0.8, - "confidence_score": 0.5, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_optimization_testqueryperformance" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_optimization.py", - "source_location": "L131", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_optimization_testlazydeserialization_test_query_manager_has_deserialize_method" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "tests/test_stocks_optimization.py", - "source_location": "L160", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager", - "target": "tests_test_stocks_optimization_testqueryoptimization_test_query_filter_uses_optimization" - }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L163", + "source_location": "L179", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryhistorical", - "target": "stocks_api_query_stocksquerymanager_baseframe" + "source": "stocks_api_query_queryhistorical", + "target": "stocks_api_query_baseframe" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L230", + "source_location": "L236", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryfundamental", - "target": "stocks_api_query_stocksquerymanager_baseframe" + "source": "stocks_api_query_queryfundamental", + "target": "stocks_api_query_baseframe" }, { "relation": "calls", @@ -68257,74 +68417,63 @@ "source_location": "L290", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_querycotations", - "target": "stocks_api_query_stocksquerymanager_baseframe" + "source": "stocks_api_query_querycotations", + "target": "stocks_api_query_baseframe" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L84", + "source_location": "L189", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_finalize", - "target": "stocks_api_query_stocksquerymanager_filterbysearchterms" + "source": "stocks_api_query_queryhistorical", + "target": "stocks_api_query_validatefields" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L93", + "source_location": "L247", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_finalize", - "target": "stocks_api_query_stocksquerymanager_deserializejsoncolumns" + "source": "stocks_api_query_queryfundamental", + "target": "stocks_api_query_validatefields" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L202", + "source_location": "L120", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryhistorical", - "target": "stocks_api_query_stocksquerymanager_finalize" + "source": "stocks_api_query_finalize", + "target": "stocks_api_query_envelope" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L277", + "source_location": "L297", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryfundamental", - "target": "stocks_api_query_stocksquerymanager_finalize" + "source": "stocks_api_query_querycotations", + "target": "stocks_api_query_envelope" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L313", + "source_location": "L104", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_querycotations", - "target": "stocks_api_query_stocksquerymanager_finalize" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "main/app/stocks_api/query.py", - "source_location": "L97", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager_finalize", - "target": "stocks_api_util_parsedaterange" + "source": "stocks_api_query_finalize", + "target": "stocks_api_query_filterbysearchterms" }, { "relation": "calls", @@ -68334,85 +68483,74 @@ "source_location": "L113", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_deserializejsoncolumns", - "target": "stocks_api_query_stocksquerymanager_queryhistorical" + "source": "stocks_api_query_finalize", + "target": "stocks_api_query_deserializejsoncolumns" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L183", + "source_location": "L207", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_deserializejsoncolumns", - "target": "stocks_api_query_stocksquerymanager_queryfundamental" + "source": "stocks_api_query_queryhistorical", + "target": "stocks_api_query_finalize" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L315", + "source_location": "L276", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_deserializejsoncolumns", - "target": "stocks_api_query_stocksquerymanager_querycotations" + "source": "stocks_api_query_queryfundamental", + "target": "stocks_api_query_finalize" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L153", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_executequery", - "target": "stocks_api_query_stocksquerymanager_deserializejsoncolumns" - }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L151", + "source_location": "L306", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_filterbysearchterms", - "target": "stocks_api_query_stocksquerymanager_queryfundamental" + "source": "stocks_api_query_querycotations", + "target": "stocks_api_query_finalize" }, { "relation": "calls", "context": "call", - "confidence": "EXTRACTED", + "confidence": "INFERRED", + "confidence_score": 0.8, "source_file": "main/app/stocks_api/query.py", - "source_location": "L306", + "source_location": "L117", "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_filterbysearchterms", - "target": "stocks_api_query_stocksquerymanager_querycotations" + "source": "stocks_api_query_finalize", + "target": "stocks_api_util_parsedaterange" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L99", + "source_location": "L253", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_filterbysearchterms", - "target": "stocks_api_query_stocksquerymanager_queryhistorical" + "source": "stocks_api_query_queryfundamental", + "target": "stocks_api_query_filterbysearchterms" }, { "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "main/app/stocks_api/query.py", - "source_location": "L131", + "source_location": "L300", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_executequery", - "target": "stocks_api_query_stocksquerymanager_filterbysearchterms" + "source": "stocks_api_query_querycotations", + "target": "stocks_api_query_filterbysearchterms" }, { "relation": "calls", @@ -68420,9 +68558,9 @@ "confidence": "INFERRED", "confidence_score": 0.8, "source_file": "main/app/stocks_api/query.py", - "source_location": "L76", + "source_location": "L184", "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryhistorical", + "source": "stocks_api_query_queryhistorical", "target": "stocks_api_util_categorizecolumns" }, { @@ -68431,54 +68569,21 @@ "confidence": "INFERRED", "confidence_score": 0.8, "source_file": "main/app/stocks_api/query.py", - "source_location": "L124", + "source_location": "L193", "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryhistorical", + "source": "stocks_api_query_queryhistorical", "target": "stocks_api_util_parsedaterange" }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L204", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryhistorical", - "target": "stocks_api_query_stocksquerymanager_executequery" - }, { "relation": "calls", "context": "call", "confidence": "INFERRED", "confidence_score": 0.8, - "source_file": "main/app/stocks_api/query.py", - "source_location": "L137", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryhistorical", - "target": "stocks_api_response_cache_responsecache_set" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "main/app/stocks_api/query.py", - "source_location": "L133", - "weight": 1.0, - "source": "prometheus_state_harnessstate_set", - "target": "stocks_api_query_stocksquerymanager_queryhistorical" - }, - { - "relation": "calls", - "context": "call", - "confidence": "INFERRED", - "confidence_score": 0.8, - "source_file": "main/app/stocks_api/query.py", - "source_location": "L89", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L142", "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryhistorical", - "target": "stocks_api_util_parseyearinput" + "source": "controller_stocksapi_controller_gethistorical", + "target": "stocks_api_query_queryhistorical" }, { "relation": "calls", @@ -68486,9 +68591,9 @@ "confidence": "INFERRED", "confidence_score": 0.8, "source_file": "main/app/stocks_api/query.py", - "source_location": "L141", + "source_location": "L241", "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryfundamental", + "source": "stocks_api_query_queryfundamental", "target": "stocks_api_util_categorizecolumns" }, { @@ -68497,76 +68602,53 @@ "confidence": "INFERRED", "confidence_score": 0.8, "source_file": "main/app/stocks_api/query.py", - "source_location": "L197", + "source_location": "L258", "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryfundamental", + "source": "stocks_api_query_queryfundamental", "target": "stocks_api_util_parsedaterange" }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L277", - "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryfundamental", - "target": "stocks_api_query_stocksquerymanager_executequery" - }, { "relation": "calls", "context": "call", "confidence": "INFERRED", "confidence_score": 0.8, - "source_file": "main/app/stocks_api/query.py", - "source_location": "L217", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L212", "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager_queryfundamental", - "target": "stocks_api_response_cache_responsecache_set" + "source": "controller_stocksapi_controller_getfundamental", + "target": "stocks_api_query_queryfundamental" }, { "relation": "calls", "context": "call", "confidence": "INFERRED", "confidence_score": 0.8, - "source_file": "main/app/stocks_api/query.py", - "source_location": "L213", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L268", "weight": 1.0, - "source": "prometheus_state_harnessstate_set", - "target": "stocks_api_query_stocksquerymanager_queryfundamental" + "source": "controller_stocksapi_controller_getcotations", + "target": "stocks_api_query_querycotations" }, { "relation": "calls", "context": "call", "confidence": "INFERRED", "confidence_score": 0.8, - "source_file": "main/app/stocks_api/query.py", - "source_location": "L318", - "weight": 1.0, - "source": "stocks_api_query_stocksquerymanager_querycotations", - "target": "stocks_api_util_parsedaterange" - }, - { - "relation": "calls", - "context": "call", - "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L306", + "source_file": "main/controller/stocksapi_controller.py", + "source_location": "L313", "weight": 1.0, - "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_querycotations", - "target": "stocks_api_query_filtercotationdata" + "source": "controller_stocksapi_controller_getlivecotation", + "target": "stocks_api_query_querylivecotation" }, { - "relation": "calls", - "context": "call", + "relation": "contains", "confidence": "EXTRACTED", - "source_file": "main/app/stocks_api/query.py", - "source_location": "L321", + "source_file": "main/app/stocks_api/sync_cache.py", + "source_location": "L14", "weight": 1.0, "confidence_score": 1.0, - "source": "stocks_api_query_stocksquerymanager_querycotations", - "target": "stocks_api_query_filtercotationbydate" + "source": "main_app_stocks_api_sync_cache_py", + "target": "stocks_api_sync_cache_cache" }, { "relation": "contains", @@ -68808,6 +68890,28 @@ "source": "stocks_api_util_categorizecolumns", "target": "controller_stocksapi_controller_listfields" }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L76", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryhistorical", + "target": "stocks_api_util_categorizecolumns" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L141", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryfundamental", + "target": "stocks_api_util_categorizecolumns" + }, { "relation": "calls", "context": "call", @@ -68940,6 +69044,50 @@ "source": "stocks_api_util_parsedaterange", "target": "stocks_api_util_parsedate" }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L97", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager_finalize", + "target": "stocks_api_util_parsedaterange" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L124", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryhistorical", + "target": "stocks_api_util_parsedaterange" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L197", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryfundamental", + "target": "stocks_api_util_parsedaterange" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L318", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager_querycotations", + "target": "stocks_api_util_parsedaterange" + }, { "relation": "calls", "context": "call", @@ -74372,6 +74520,16 @@ "source": "main_utils_logging_config_py", "target": "utils_logging_config_setupdiscordhandler" }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/utils/logging_config.py", + "source_location": "L37", + "weight": 1.0, + "confidence_score": 1.0, + "source": "utils_logging_config_discordhandler", + "target": "utils_logging_config_discordhandler_init" + }, { "relation": "method", "confidence": "EXTRACTED", @@ -75169,6 +75327,17 @@ "source": "intflag", "target": "utils_roles_roles" }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/compress.py", + "source_location": "L84", + "weight": 1.0, + "source": "stocks_api_compress_tocolumnar", + "target": "utils_roles_all" + }, { "relation": "calls", "context": "call", @@ -76309,6 +76478,56 @@ "source": "server_agents_dev_commands", "target": "server_agents_ci_pipeline_order" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "PONYTAIL.md", + "source_location": "L1", + "weight": 1.0, + "confidence_score": 1.0, + "source": "ponytail_md", + "target": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "PONYTAIL.md", + "source_location": "L6", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", + "target": "server_ponytail_proposed_awaiting_approval" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "PONYTAIL.md", + "source_location": "L64", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", + "target": "server_ponytail_disputed_already_litigated_needs_your_ruling_to_proceed" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "PONYTAIL.md", + "source_location": "L72", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", + "target": "server_ponytail_held_out_your_ignore_rules_not_proposed" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "PONYTAIL.md", + "source_location": "L78", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", + "target": "server_ponytail_refused" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -76389,6 +76608,86 @@ "source": "server_readme_health_check", "target": "server_readme_codeblock_3" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "SWARMS.md", + "source_location": "L1", + "weight": 1.0, + "confidence_score": 1.0, + "source": "swarms_md", + "target": "server_swarms_swarms_md_subagent_swarm_playbook_opencode_hermes" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "SWARMS.md", + "source_location": "L6", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_swarms_swarms_md_subagent_swarm_playbook_opencode_hermes", + "target": "server_swarms_1_prime_owns_the_goal_lanes_own_the_work" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "SWARMS.md", + "source_location": "L12", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_swarms_swarms_md_subagent_swarm_playbook_opencode_hermes", + "target": "server_swarms_2_dispatch_delegate_one_per_lane_one_turn" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "SWARMS.md", + "source_location": "L20", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_swarms_swarms_md_subagent_swarm_playbook_opencode_hermes", + "target": "server_swarms_3_delegate_toolsets_vary_verify_each_lane" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "SWARMS.md", + "source_location": "L26", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_swarms_swarms_md_subagent_swarm_playbook_opencode_hermes", + "target": "server_swarms_4_trust_nothing_verify_everything" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "SWARMS.md", + "source_location": "L33", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_swarms_swarms_md_subagent_swarm_playbook_opencode_hermes", + "target": "server_swarms_5_windows_powershell_survival" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "SWARMS.md", + "source_location": "L39", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_swarms_swarms_md_subagent_swarm_playbook_opencode_hermes", + "target": "server_swarms_6_finish_per_lane_not_per_swarm" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "SWARMS.md", + "source_location": "L45", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_swarms_swarms_md_subagent_swarm_playbook_opencode_hermes", + "target": "server_swarms_7_standing_bans_this_repo" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -79929,6 +80228,156 @@ "source": "plans_2026_09_12_artifact_removal_cache_verdict_artifact_removal_matrix_cache_verdict_plan", "target": "plans_2026_09_12_artifact_removal_cache_verdict_part_2_cache_verdict_keep_the_dict_skip_cashews" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L1", + "weight": 1.0, + "confidence_score": 1.0, + "source": "docs_superpowers_plans_2026_09_14_memory_postgres_pgvector_plan_md", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_memory_postgres_pgvector_migration_implementation_plan" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L13", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_memory_postgres_pgvector_migration_implementation_plan", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_global_constraints" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L24", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_global_constraints", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_task_1_pgvector_migration_backfill" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L79", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_global_constraints", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_task_2_delete_vector_py_rewrite_search" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L139", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_global_constraints", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_task_3_update_the_test_files" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L171", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_global_constraints", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_task_4_full_test_sweep_18_suites_postgres_ci_parity" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L185", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_global_constraints", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_task_5_docs_close" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L35", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_task_1_pgvector_migration_backfill", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_1" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L65", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_task_1_pgvector_migration_backfill", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_2" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L74", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_task_1_pgvector_migration_backfill", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_3" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L97", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_task_2_delete_vector_py_rewrite_search", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_4" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L134", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_task_2_delete_vector_py_rewrite_search", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_5" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L148", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_task_3_update_the_test_files", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_6" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L166", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_task_3_update_the_test_files", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_7" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-14-memory-postgres-pgvector-plan.md", + "source_location": "L189", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_14_memory_postgres_pgvector_plan_task_5_docs_close", + "target": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_8" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -80089,6 +80538,794 @@ "source": "specs_2026_09_04_wallet_design_2_decision_design_a_pure_event_log_derive_at_read_time", "target": "specs_2026_09_04_wallet_design_approaches_considered" }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L15", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_init" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L58", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_baseframe" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L69", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_finalize" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L23", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_deserializejsoncolumns" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L52", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_filterbysearchterms" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L61", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_queryhistorical" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L126", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_queryfundamental" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L278", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_querycotations" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L348", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_querylivecotation" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L110", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_executequery" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L729", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_teststockscachemanager" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L729", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testverifyapikey" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L729", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testgeneratesecurekey" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L729", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testcreatekey" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L729", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testdeserializejsoncolumns" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L729", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testfilterbysearchterms" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L729", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testqueryhistorical" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L729", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testqueryfundamental" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L989", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testquerycotations" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L1261", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testquerylivecotation" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L419", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testdeserializejsoncolumns_make_manager" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L530", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testfilterbysearchterms_make_manager" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L587", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testqueryhistorical_make_manager" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L731", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testqueryfundamental_make_manager" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L1017", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_does_not_mutate_cache_time_dtype" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L994", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testquerycotations_make_manager" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_api_coverage.py", + "source_location": "L1266", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_api_coverage_testquerylivecotation_make_manager" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L344", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "stocks_api_query_stocksquerymanager_queryrealtimecotation" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_cache.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_cache_testtickerindex" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_cache.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_cache_testquerycaching" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_cache.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_cache_testconnectionpool" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_cache.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_cache_testlazydeserialization" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_cache.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_cache_testqueryoptimization" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_cache.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_cache_testperformancebenchmarks" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_cache.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_cache_testfilterbysearchterms" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_cache.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_cache_testqueryperformance" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_cache.py", + "source_location": "L131", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_cache_testlazydeserialization_test_query_manager_has_deserialize_method" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_cache.py", + "source_location": "L160", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_cache_testqueryoptimization_test_query_filter_uses_optimization" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_optimization.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_optimization_testtickerindex" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_optimization.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_optimization_testquerycaching" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_optimization.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_optimization_testconnectionpool" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_optimization.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_optimization_testlazydeserialization" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_optimization.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_optimization_testqueryoptimization" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_optimization.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_optimization_testperformancebenchmarks" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_optimization.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_optimization_testfilterbysearchterms" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "tests/test_stocks_optimization.py", + "source_location": "L157", + "weight": 0.8, + "confidence_score": 0.5, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_optimization_testqueryperformance" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_optimization.py", + "source_location": "L131", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_optimization_testlazydeserialization_test_query_manager_has_deserialize_method" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "tests/test_stocks_optimization.py", + "source_location": "L160", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager", + "target": "tests_test_stocks_optimization_testqueryoptimization_test_query_filter_uses_optimization" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L163", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryhistorical", + "target": "stocks_api_query_stocksquerymanager_baseframe" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L230", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryfundamental", + "target": "stocks_api_query_stocksquerymanager_baseframe" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L290", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_querycotations", + "target": "stocks_api_query_stocksquerymanager_baseframe" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L84", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_finalize", + "target": "stocks_api_query_stocksquerymanager_filterbysearchterms" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L93", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_finalize", + "target": "stocks_api_query_stocksquerymanager_deserializejsoncolumns" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L202", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryhistorical", + "target": "stocks_api_query_stocksquerymanager_finalize" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L277", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryfundamental", + "target": "stocks_api_query_stocksquerymanager_finalize" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L313", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_querycotations", + "target": "stocks_api_query_stocksquerymanager_finalize" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L113", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_deserializejsoncolumns", + "target": "stocks_api_query_stocksquerymanager_queryhistorical" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L183", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_deserializejsoncolumns", + "target": "stocks_api_query_stocksquerymanager_queryfundamental" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L315", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_deserializejsoncolumns", + "target": "stocks_api_query_stocksquerymanager_querycotations" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L153", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_executequery", + "target": "stocks_api_query_stocksquerymanager_deserializejsoncolumns" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L151", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_filterbysearchterms", + "target": "stocks_api_query_stocksquerymanager_queryfundamental" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L306", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_filterbysearchterms", + "target": "stocks_api_query_stocksquerymanager_querycotations" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L99", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_filterbysearchterms", + "target": "stocks_api_query_stocksquerymanager_queryhistorical" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L131", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_executequery", + "target": "stocks_api_query_stocksquerymanager_filterbysearchterms" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L204", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryhistorical", + "target": "stocks_api_query_stocksquerymanager_executequery" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L137", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryhistorical", + "target": "stocks_api_response_cache_responsecache_set" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L133", + "weight": 1.0, + "source": "prometheus_state_harnessstate_set", + "target": "stocks_api_query_stocksquerymanager_queryhistorical" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L89", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryhistorical", + "target": "stocks_api_util_parseyearinput" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L277", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryfundamental", + "target": "stocks_api_query_stocksquerymanager_executequery" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L217", + "weight": 1.0, + "source": "stocks_api_query_stocksquerymanager_queryfundamental", + "target": "stocks_api_response_cache_responsecache_set" + }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/stocks_api/query.py", + "source_location": "L213", + "weight": 1.0, + "source": "prometheus_state_harnessstate_set", + "target": "stocks_api_query_stocksquerymanager_queryfundamental" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L306", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_querycotations", + "target": "stocks_api_query_filtercotationdata" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L321", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_stocksquerymanager_querycotations", + "target": "stocks_api_query_filtercotationbydate" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L46", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_getmatrixasync", + "target": "prometheus_memory_matrixkey" + }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L51", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_getmatrixasync", + "target": "prometheus_memory_matrixusertag" + }, { "relation": "calls", "context": "call", @@ -135946,5 +137183,5 @@ "label": "User Authentication & Authorization" } ], - "built_at_commit": "8e244c48aba386cd3418415429062c9b01ab8b0d" + "built_at_commit": "c70c13418661d63720e47519841e95aaabdff09f" } \ No newline at end of file diff --git a/graphify-out/manifest.json b/graphify-out/manifest.json index 26fe68d..bcfef5a 100644 --- a/graphify-out/manifest.json +++ b/graphify-out/manifest.json @@ -10,13 +10,13 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\config.py": { - "mtime": 1789281902.8629024, - "ast_hash": "a9e0df3ac791a43734658c97fa8b5f16", + "mtime": 1789425836.284395, + "ast_hash": "ef2c8d0823152252266ff44bf4214a4f", "semantic_hash": "" }, "D:\\Repositories\\server\\run.py": { - "mtime": 1789266824.6521552, - "ast_hash": "7355f5c18bcf9d44dd7cc641270b32df", + "mtime": 1789366057.0017536, + "ast_hash": "35021368aa43aea573173c51037c5c80", "semantic_hash": "" }, "D:\\Repositories\\server\\frontend\\components.json": { @@ -215,8 +215,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\authentication\\session.py": { - "mtime": 1789266824.5969524, - "ast_hash": "6507469627574af836ec8caf56062999", + "mtime": 1789365900.6795783, + "ast_hash": "565419026a26fd31b95cadc85814e50d", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\authentication\\sso.py": { @@ -225,13 +225,13 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\authentication\\util.py": { - "mtime": 1789266824.5994601, - "ast_hash": "67a1157414105353b72219fbc0804fbb", + "mtime": 1789365931.8706675, + "ast_hash": "b797eff10d6300739b550248fe003dbf", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\agent.py": { - "mtime": 1789282177.9672518, - "ast_hash": "dd0ff02b01201cbe2f5144f9b95bab61", + "mtime": 1789368603.539152, + "ast_hash": "6e58d02ffd53d80c8e09e2c0b739abc7", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\chat.py": { @@ -240,23 +240,23 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\compact.py": { - "mtime": 1789266824.6014771, - "ast_hash": "955e54ce6de3039635c540c1ad0e4511", + "mtime": 1789364629.4688208, + "ast_hash": "0fac8d6ba047c209b14293afd2c940d8", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\mcp.py": { - "mtime": 1789282153.988783, - "ast_hash": "f2db9643cce48d937619f6ffe181a07b", + "mtime": 1789364804.2356262, + "ast_hash": "0fc31aca590f7a823892d76570edfc98", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\memory.py": { - "mtime": 1789282414.1017342, - "ast_hash": "fa53feb5163a2b399aaefa2b393794cf", + "mtime": 1789364400.0313132, + "ast_hash": "83e8d8faa47499a569ac4628802434d0", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\sandbox.py": { - "mtime": 1789278691.4397347, - "ast_hash": "de536b4a09d235508f0caf3e039a801f", + "mtime": 1789363629.931731, + "ast_hash": "cc5b2154f508462c4c2d1a90cc1074b0", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\stream_bus.py": { @@ -285,13 +285,13 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\cache.py": { - "mtime": 1789266824.609999, - "ast_hash": "b88e8c309402b9d68b54fb4954c4d706", + "mtime": 1789363514.5006788, + "ast_hash": "9f1efcf706a603e6bba46845bca86508", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\compress.py": { - "mtime": 1789266824.6110003, - "ast_hash": "06fef344001f68f7335f88d81bb0dc02", + "mtime": 1789365748.7463734, + "ast_hash": "bac7ddeafcf3f4e917d23e190f8d2a50", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\key.py": { @@ -300,18 +300,18 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\query.py": { - "mtime": 1789281924.4611645, - "ast_hash": "a4d94b431337c15d31c743ee6699a3a8", + "mtime": 1789368603.5401547, + "ast_hash": "fac4cd3310f0bb2bf7f5c6864bc78ee8", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\sync_cache.py": { - "mtime": 1789266824.6130083, - "ast_hash": "1bac9bc5d8d5977215ff7bc27eea5477", + "mtime": 1789363755.282281, + "ast_hash": "2868edb52460fde88cc704901c64254c", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\util.py": { - "mtime": 1789266824.6140084, - "ast_hash": "8c5c4bd501148c5eef30a1053def2712", + "mtime": 1789365853.1977775, + "ast_hash": "f25300eb19b8346657c558af17425018", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\user\\user.py": { @@ -320,8 +320,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\controller\\authentication_controller.py": { - "mtime": 1789266824.6160088, - "ast_hash": "c1ff3fd4aaaae1d2d03877cc298f260b", + "mtime": 1789365987.4456894, + "ast_hash": "b061f08825c0c4245d98f2b2c78a3bc3", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\controller\\prometheus_controller.py": { @@ -330,13 +330,13 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\controller\\stocksapi_controller.py": { - "mtime": 1789266824.618007, - "ast_hash": "b5bc6c647ad244d94e7ba69caba3c778", + "mtime": 1789365824.939239, + "ast_hash": "deb972bc1e3fc058d2c8db97113f86a0", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\controller\\user_controller.py": { - "mtime": 1789266824.6195102, - "ast_hash": "7cf59e6c85a74e74c377c9bf648eadb8", + "mtime": 1789365966.3660727, + "ast_hash": "3b2e912c481d62f9b638dddd68e142e3", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\models\\base.py": { @@ -405,8 +405,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\connectivity.py": { - "mtime": 1789266824.630044, - "ast_hash": "f5bb506f5374eab04ff6e761ffec1807", + "mtime": 1789366037.8517115, + "ast_hash": "b9c539f0db7e46481115e3c413fbd8d9", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\errors.py": { @@ -420,13 +420,13 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\logging_config.py": { - "mtime": 1789267774.022068, - "ast_hash": "8f7c2f17ff2d4f0f94116fb8c1bcfe64", + "mtime": 1789364981.4242673, + "ast_hash": "ccb86a65bfcc29d7c62b17ad061f9e21", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\migrator.py": { - "mtime": 1789266824.6340508, - "ast_hash": "7ef9216d73553fdad80095cfba9d1985", + "mtime": 1789366031.30065, + "ast_hash": "ef1d7dcf0379a24c24e182fb5a295a44", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\request_id.py": { @@ -525,8 +525,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\docker-compose.yml": { - "mtime": 1789278227.9939115, - "ast_hash": "bd9e5bbd860519a0b71bbac1fb076084", + "mtime": 1789363976.6625137, + "ast_hash": "6120b56e7d0d79dd57b0eb9b1cb452ef", "semantic_hash": "" }, "D:\\Repositories\\server\\forgevm.yaml": { @@ -534,6 +534,11 @@ "ast_hash": "061d7cea62f7e674af297ae3f858be8f", "semantic_hash": "" }, + "D:\\Repositories\\server\\PONYTAIL.md": { + "mtime": 1789363582.7935076, + "ast_hash": "e1223d3b181dd26939c82be5ed2c4adf", + "semantic_hash": "" + }, "D:\\Repositories\\server\\README.md": { "mtime": 1789266824.5528724, "ast_hash": "eefffc81bc23e76d2429b5d93525910e", @@ -544,9 +549,14 @@ "ast_hash": "ca468b8c46eaec66585c6626007b2e6a", "semantic_hash": "" }, + "D:\\Repositories\\server\\SWARMS.md": { + "mtime": 1789316049.401499, + "ast_hash": "1267348986aa2996b77607d894b554da", + "semantic_hash": "" + }, "D:\\Repositories\\server\\TODO.md": { - "mtime": 1789266936.1947691, - "ast_hash": "51f406e95762c717c42d8dbb9c339b63", + "mtime": 1789314412.2992828, + "ast_hash": "24bf5288ec1e573ec1172899b4dd2e8e", "semantic_hash": "" }, "D:\\Repositories\\server\\docs\\authentication.md": { @@ -614,6 +624,11 @@ "ast_hash": "3550ab946bbde47f55f47473cfb994e1", "semantic_hash": "" }, + "D:\\Repositories\\server\\docs\\superpowers\\plans\\2026-09-14-memory-postgres-pgvector-plan.md": { + "mtime": 1789364281.6991754, + "ast_hash": "74c6fb495a112e3f6db93a70c6265f21", + "semantic_hash": "" + }, "D:\\Repositories\\server\\docs\\superpowers\\specs\\2026-09-04-wallet-design.md": { "mtime": 1789266824.564381, "ast_hash": "3ad505fd6016388f87bd14fa8da4f40e", diff --git a/main/app/prometheus/sandbox.py b/main/app/prometheus/sandbox.py index 7beecbd..cadba6d 100644 --- a/main/app/prometheus/sandbox.py +++ b/main/app/prometheus/sandbox.py @@ -25,7 +25,9 @@ def getClient() -> AsyncClient: forgeUrl = Config.PROMETHEUS.FORGEVM_URL forgeToken = Config.PROMETHEUS.FORGEVM_API_TOKEN if forgeUrl and not forgeToken: - raise RuntimeError(f"FORGEVM_URL is set ({forgeUrl}) but FORGEVM_API_TOKEN is empty; set FORGEVM_API_TOKEN or unset FORGEVM_URL for local dev") + raise RuntimeError( + f"FORGEVM_URL is set ({forgeUrl}) but FORGEVM_API_TOKEN is empty; set FORGEVM_API_TOKEN or unset FORGEVM_URL for local dev" + ) return AsyncClient( base_url=forgeUrl, api_key=forgeToken or None, diff --git a/tests/test_api_key_quota_atomic.py b/tests/test_api_key_quota_atomic.py index 25c779c..735f792 100644 --- a/tests/test_api_key_quota_atomic.py +++ b/tests/test_api_key_quota_atomic.py @@ -32,7 +32,12 @@ def quotaUpdate(dbSession, apiKey): @pytest.fixture def sampleKeyData(): """Sample API key data for tests.""" - return {"apiKey": hashlib.sha256("test_key_12345".encode()).hexdigest(), "userId": 1, "requestLimit": 100, "currentUsage": 0} + return { + "apiKey": hashlib.sha256("test_key_12345".encode()).hexdigest(), + "userId": 1, + "requestLimit": 100, + "currentUsage": 0, + } class TestAtomicQuotaIncrement: diff --git a/tests/test_relevance_score.py b/tests/test_relevance_score.py index c0f8856..772256f 100644 --- a/tests/test_relevance_score.py +++ b/tests/test_relevance_score.py @@ -64,6 +64,7 @@ def test_ephemeral_old_loses_to_sticky_new(self): sticky_new = FakeMemory(score=14.0, lastAccessedAt=NOW) assert getRelevanceScore(sticky_new, NOW) > getRelevanceScore(ephemeral_old, NOW) + class TestDecayMonotonicity: def test_older_always_lower_score(self): scores = [] diff --git a/tests/test_roles.py b/tests/test_roles.py index ed3d8ec..c0ab497 100644 --- a/tests/test_roles.py +++ b/tests/test_roles.py @@ -9,6 +9,7 @@ def test_permission_enum_values(self): assert Permission.USE_PROMETHEUS > 0 assert Permission.PROMETHEUS_EXTENDED_MEMORIES > 0 + class TestRoles: def test_user_has_no_permissions(self): assert Roles.USER == Permission.NONE diff --git a/tests/test_sandbox_auth_gating.py b/tests/test_sandbox_auth_gating.py index 42a57a3..9ebb4fb 100644 --- a/tests/test_sandbox_auth_gating.py +++ b/tests/test_sandbox_auth_gating.py @@ -7,24 +7,29 @@ class TestSandboxAuthGating: def test_urlSetEmptyTokenRaises(self): - with patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_URL", "http://forgevm:7423"), patch.object( - sandboxModule.Config.PROMETHEUS, "FORGEVM_API_TOKEN", "" + with ( + patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_URL", "http://forgevm:7423"), + patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_API_TOKEN", ""), ): with pytest.raises(RuntimeError, match="FORGEVM_API_TOKEN"): sandboxModule.getClient() def test_urlSetWithTokenPassesThrough(self): - with patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_URL", "http://forgevm:7423"), patch.object( - sandboxModule.Config.PROMETHEUS, "FORGEVM_API_TOKEN", "secret" - ), patch.object(sandboxModule, "AsyncClient") as mockClient: + with ( + patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_URL", "http://forgevm:7423"), + patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_API_TOKEN", "secret"), + patch.object(sandboxModule, "AsyncClient") as mockClient, + ): client = sandboxModule.getClient() mockClient.assert_called_once_with(base_url="http://forgevm:7423", api_key="secret", timeout=30) assert client is mockClient.return_value def test_urlUnsetReturnsClient(self): - with patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_URL", ""), patch.object( - sandboxModule.Config.PROMETHEUS, "FORGEVM_API_TOKEN", "" - ), patch.object(sandboxModule, "AsyncClient") as mockClient: + with ( + patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_URL", ""), + patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_API_TOKEN", ""), + patch.object(sandboxModule, "AsyncClient") as mockClient, + ): client = sandboxModule.getClient() mockClient.assert_called_once_with(base_url="", api_key=None, timeout=30) assert client is mockClient.return_value diff --git a/tests/test_stocks_compress.py b/tests/test_stocks_compress.py index 07f631c..9fe28eb 100644 --- a/tests/test_stocks_compress.py +++ b/tests/test_stocks_compress.py @@ -291,8 +291,14 @@ class TestCompressResponse: "raw,tool,args,expected", [ ( - {"count": 2, "search": "PETR4", "fields": ["P/L"], "dates": "2024", - "type": "get_fundamental", "data": []}, + { + "count": 2, + "search": "PETR4", + "fields": ["P/L"], + "dates": "2024", + "type": "get_fundamental", + "data": [], + }, "get_fundamental", {"search": "PETR4", "fields": ["P/L"], "dates": "2024"}, {"data": []}, From 5ad08ba029a1925687e87f67f3278d5498f560e5 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 20:21:43 -0300 Subject: [PATCH 36/57] handled by the config --- graphify-out/GRAPH_REPORT.md | 46 ++++----- graphify-out/graph.json | 172 ++++++++++++++++----------------- graphify-out/manifest.json | 4 +- main/app/prometheus/compact.py | 2 +- main/app/prometheus/memory.py | 5 +- main/app/prometheus/sandbox.py | 10 +- 6 files changed, 116 insertions(+), 123 deletions(-) diff --git a/graphify-out/GRAPH_REPORT.md b/graphify-out/GRAPH_REPORT.md index d6b3ac9..e11bf26 100644 --- a/graphify-out/GRAPH_REPORT.md +++ b/graphify-out/GRAPH_REPORT.md @@ -1,7 +1,7 @@ # Graph Report - server (2026-09-14) ## Corpus Check -- 124 files · ~73,749 words +- 124 files · ~73,751 words - Verdict: corpus is large enough that graph structure adds value. ## Summary @@ -10,7 +10,7 @@ - Token cost: 0 input · 0 output ## Graph Freshness -- Built from commit: `c70c1341` +- Built from commit: `78084c0d` - Run `git rev-parse HEAD` and compare to check if the graph is stale. - Run `graphify update .` after code changes (no API cost). @@ -682,8 +682,8 @@ Cohesion: 0.06 Nodes (31): _make_prometheus_client(), Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 111-112: sessionId is None, new session created., Covers lines 111-112: sessionId is None, new session created., Covers lines 109-136: POST /prometheus/chat/stream (SSE)., Covers lines 118-119: sessionId is None, new session created., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat. (+23 more) ### Community 17 - "Community 17" -Cohesion: 0.07 -Nodes (26): Two dates in the range, both valid., Two dates in the range, both valid., Two dates in the range, both valid., Two dates in the range, both valid., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., search.strip() == '' should still dedup (line 181)., Search with no index match falls back to string startswith. (+18 more) +Cohesion: 0.11 +Nodes (17): Multiple search terms with tickerIndex., Multiple search terms with tickerIndex., Multiple search terms with tickerIndex., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., Multiple search terms with tickerIndex., Multiple search terms with tickerIndex. (+9 more) ### Community 18 - "Community 18" Cohesion: 0.07 @@ -770,8 +770,8 @@ Cohesion: 0.07 Nodes (27): code:json ([), code:javascript (const loadHistory = async (sid) => {), code:jsx (export default function MessageList({ messages, toolEvents, ), code:javascript (const loadHistory = async (sid) => {), code:jsx (export default function AgentLoop({ toolEvents, turnMetrics ), code:bash (git add frontend/src/App.jsx frontend/src/components/Message), code:bash (docker-compose up -d --build), code:sql (SELECT COUNT(*) FROM prometheus WHERE JSON_CONTAINS_PATH(his) (+19 more) ### Community 39 - "Community 39" -Cohesion: 0.06 -Nodes (31): Invalid date -> inner 400 passes through (not wrapped as 500)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500. (+23 more) +Cohesion: 0.05 +Nodes (40): Invalid date -> inner 400 passes through (not wrapped as 500)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500. (+32 more) ### Community 40 - "Community 40" Cohesion: 0.12 @@ -830,8 +830,8 @@ Cohesion: 0.1 Nodes (39): applyUpdate(), archiveDead(), clearAll(), clearAllAsync(), count_memories(), countMemories(), countTokensCached(), decayScores() (+31 more) ### Community 54 - "Community 54" -Cohesion: 0.11 -Nodes (14): generateKey(), JSONBytesResponse, listFields(), Sends pre-serialized JSON bytes without re-encoding (cache-friendly)., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental. (+6 more) +Cohesion: 0.2 +Nodes (10): listFields(), Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental. (+2 more) ### Community 55 - "Community 55" Cohesion: 0.11 @@ -934,8 +934,8 @@ Cohesion: 0.16 Nodes (18): buildSummary(), charCount(), countTokens(), dedup(), extractDecisions(), extractMetrics(), extractSnapshots(), extractTickers() (+10 more) ### Community 81 - "Community 81" -Cohesion: 0.15 -Nodes (13): getLiveCotation(), Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th (+5 more) +Cohesion: 0.09 +Nodes (17): generateKey(), getLiveCotation(), JSONBytesResponse, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Sends pre-serialized JSON bytes without re-encoding (cache-friendly)., Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th (+9 more) ### Community 82 - "Community 82" Cohesion: 0.15 @@ -1018,8 +1018,8 @@ Cohesion: 0.2 Nodes (12): execute_code(), Store a value in the harness state for this session. Use this to save inter, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Store a value in the harness state for this session. Use this to save inter (+4 more) ### Community 102 - "Community 102" -Cohesion: 0.12 -Nodes (11): BaseSettings, BaseMansaSettings, Config, DiscordSettings, MysqlSettings, PrometheusSettings, ScraperSettings, StocksApiSettings (+3 more) +Cohesion: 0.13 +Nodes (10): BaseSettings, BaseMansaSettings, DiscordSettings, MysqlSettings, PrometheusSettings, ScraperSettings, StocksApiSettings, UserSettings (+2 more) ### Community 103 - "Community 103" Cohesion: 0.13 @@ -1094,8 +1094,8 @@ Cohesion: 0.21 Nodes (12): code:python (import inspect), code:python (from main.app.prometheus.sandbox import SandboxManager), code:python (TOOL_REGISTRY: dict[str, Any] = {), code:python (## Code Sandbox (On-Demand)), code:bash (git add main/app/prometheus/agent.py), code:dockerfile (FROM python:3.11-slim), code:bash (git add Dockerfile.sandbox), Phase 6: Agent Integration (All Layers) (+4 more) ### Community 122 - "Community 122" -Cohesion: 0.15 -Nodes (10): test_setup_discord_handler_disabled(), test_setup_discord_handler_enabled(), Many concurrent emit() calls must not create more threads than max_workers., Verify that DiscordHandler submits to a bounded executor, not raw threads., The module-level discordExecutor must exist with max_workers <= 5., DiscordHandler.emit() must use discordExecutor.submit, not Thread.start., TestDiscordHandlerThreadPool, DiscordHandler (+2 more) +Cohesion: 0.14 +Nodes (11): Config, test_setup_discord_handler_disabled(), test_setup_discord_handler_enabled(), Many concurrent emit() calls must not create more threads than max_workers., Verify that DiscordHandler submits to a bounded executor, not raw threads., The module-level discordExecutor must exist with max_workers <= 5., DiscordHandler.emit() must use discordExecutor.submit, not Thread.start., TestDiscordHandlerThreadPool (+3 more) ### Community 123 - "Community 123" Cohesion: 0.17 @@ -1134,8 +1134,8 @@ Cohesion: 0.1 Nodes (17): Same input → same hash., Different inputs → different hashes., Returns 32-char hex string., pack → unpack preserves values., Empty list roundtrips., 384-dim vector packs to 1536 bytes., TestContentHash, TestPackUnpack (+9 more) ### Community 132 - "Community 132" -Cohesion: 0.5 -Nodes (4): code:python ("""add wallet_holdings and wallet_lots tables), code:python (import main.models.wallet), code:bash (git add migrations/versions/wallet_tables_20260904_add_walle), Task 2: Alembic migration for wallet tables +Cohesion: 0.25 +Nodes (7): code:python ("""add wallet_holdings and wallet_lots tables), code:python (import main.models.wallet), code:bash (git add migrations/versions/wallet_tables_20260904_add_walle), File Structure, Global Constraints, Task 2: Alembic migration for wallet tables, Wallet Management (Thoth/Iyagba) Implementation Plan ### Community 133 - "Community 133" Cohesion: 0.18 @@ -1518,8 +1518,8 @@ Cohesion: 0.4 Nodes (5): 8. Build Sequence (4 phases, each independently shippable), Phase 0 — Sandbox foundation (1-2 days, no user-facing change), Phase 1 — MCP exposure of STOCKS_API (1 day), Phase 2 — Refactor PROMETHEUS to agentic (3-5 days, the big one), Phase 3 — Hardening (1-2 days, can ship incrementally) ### Community 234 - "Community 234" -Cohesion: 0.14 -Nodes (11): memoryMaintenance(), Decay happens first, then archive check with new scores., Decay happens first, then archive check with new scores., Score that decays to >= threshold stays alive. 0.11 * 0.95 = 0.1045 >= 0.1., Score that decays to >= threshold stays alive. 0.12 * 0.90 = 0.108 >= 0.1., 89 days with low score → not archived (need > 90)., 89 days with low score → not archived (need > 90)., TestDecayAndArchiveTogether (+3 more) +Cohesion: 0.1 +Nodes (15): create_memories(), Decay happens first, then archive check with new scores., Decay happens first, then archive check with new scores., Score that decays to >= threshold stays alive. 0.11 * 0.95 = 0.1045 >= 0.1., Score that decays to >= threshold stays alive. 0.12 * 0.90 = 0.108 >= 0.1., 89 days with low score → not archived (need > 90)., 89 days with low score → not archived (need > 90)., Helper to create memories with controlled baseScore, lastAccessedAt, accessCount (+7 more) ### Community 236 - "Community 236" Cohesion: 0.5 @@ -1682,8 +1682,8 @@ Cohesion: 0.25 Nodes (4): Authentication System, Google OAuth, JWT Authentication, TestSessionExpiryConfig ### Community 497 - "Community 497" -Cohesion: 0.25 -Nodes (7): code:python (from dataclasses import dataclass), code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py ), code:python (from datetime import date), File Structure, Global Constraints, Task 3: Pure derivation math, Wallet Management (Thoth/Iyagba) Implementation Plan +Cohesion: 0.5 +Nodes (4): code:python (from dataclasses import dataclass), code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py ), code:python (from datetime import date), Task 3: Pure derivation math ### Community 498 - "Community 498" Cohesion: 0.06 @@ -1738,8 +1738,8 @@ Cohesion: 0.25 Nodes (14): baseFrame(), deserializeJsonColumns(), envelope(), filterBySearchTerms(), _filterCotationByDate(), filterCotationData(), finalize(), _parseCotationDate() (+6 more) ### Community 518 - "Community 518" -Cohesion: 0.08 -Nodes (19): create_memories(), Zero access but score still above threshold → not archived., Even with low score, if accessed → not archived., Even with low score, if accessed → not archived., Already archived memories are skipped., Already archived memories are skipped., Helper to create memories with controlled baseScore, lastAccessedAt, accessCount, Helper to create memories with controlled baseScore, lastAccessedAt, accessCount (+11 more) +Cohesion: 0.11 +Nodes (15): memoryMaintenance(), Zero access but score still above threshold → not archived., Even with low score, if accessed → not archived., Even with low score, if accessed → not archived., Already archived memories are skipped., Already archived memories are skipped., Score below threshold + accessCount=0 + 90+ days → archived., Score below threshold + accessCount=0 + 90+ days → archived. (+7 more) ### Community 519 - "Community 519" Cohesion: 0.57 @@ -1941,7 +1941,7 @@ _Questions this graph is uniquely positioned to answer:_ _High betweenness centrality (0.102) - this node is a cross-community bridge._ - **Why does `UserManager` connect `Community 498` to `Prometheus Agent`, `Community 519`, `Prometheus Memory`, `Community 140`, `Community 525`, `User Roles & Permissions`, `Community 141`, `Community 16`, `Community 528`, `Community 21`, `Community 22`, `Community 539`, `Community 28`, `Community 37`, `Community 47`, `Community 178`, `Community 563`, `Community 565`, `Community 567`, `Community 58`, `Community 61`, `Community 68`, `Community 208`, `Community 86`, `Community 221`, `Community 99`, `Community 231`, `Community 104`, `Community 488`, `Community 107`, `Community 493`, `Community 114`, `Community 120`, `Community 125`?** _High betweenness centrality (0.042) - this node is a cross-community bridge._ -- **Why does `Prometheus` connect `Community 116` to `Frontend Components`, `Device Detection`, `Community 138`, `Community 140`, `Frontend App Shell`, `Community 529`, `Community 151`, `Community 24`, `Community 543`, `Community 544`, `Community 52`, `Community 569`, `Community 571`, `Community 60`, `Community 573`, `Community 194`, `Community 67`, `Community 68`, `Community 80`, `Community 87`, `Community 88`, `Community 93`, `Community 102`, `Community 105`, `Community 125`?** +- **Why does `Prometheus` connect `Community 116` to `Frontend Components`, `Device Detection`, `Community 138`, `Community 140`, `Frontend App Shell`, `Community 529`, `Community 151`, `Community 24`, `Community 543`, `Community 544`, `Community 52`, `Community 569`, `Community 571`, `Community 60`, `Community 573`, `Community 194`, `Community 67`, `Community 68`, `Community 80`, `Community 87`, `Community 88`, `Community 93`, `Community 105`, `Community 122`, `Community 125`?** _High betweenness centrality (0.037) - this node is a cross-community bridge._ - **Are the 72 inferred relationships involving `StocksCacheManager` (e.g. with `TestStocksCacheManager` and `TestVerifyAPIKey`) actually correct?** _`StocksCacheManager` has 72 INFERRED edges - model-reasoned connections that need verification._ diff --git a/graphify-out/graph.json b/graphify-out/graph.json index 4c55292..e30c7f7 100644 --- a/graphify-out/graph.json +++ b/graphify-out/graph.json @@ -237,7 +237,7 @@ "source_file": "config.py", "source_location": "L91", "id": "server_config_config", - "community": 102, + "community": 122, "norm_label": "config" }, { @@ -3061,7 +3061,7 @@ "label": "hostPath()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L36", + "source_location": "L38", "id": "prometheus_sandbox_hostpath", "community": 69, "norm_label": "hostpath()" @@ -3070,7 +3070,7 @@ "label": "sandboxPath()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L50", + "source_location": "L52", "id": "prometheus_sandbox_sandboxpath", "community": 69, "norm_label": "sandboxpath()" @@ -3079,7 +3079,7 @@ "label": "SandboxManager", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L55", + "source_location": "L57", "id": "prometheus_sandbox_sandboxmanager", "community": 2, "norm_label": "sandboxmanager" @@ -3088,7 +3088,7 @@ "label": "create()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L57", + "source_location": "L59", "id": "prometheus_sandbox_create", "community": 69, "norm_label": "create()" @@ -3097,7 +3097,7 @@ "label": "destroy()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L73", + "source_location": "L75", "id": "prometheus_sandbox_destroy", "community": 69, "norm_label": "destroy()" @@ -3106,7 +3106,7 @@ "label": "getOrCreate()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L85", + "source_location": "L87", "id": "prometheus_sandbox_getorcreate", "community": 69, "norm_label": "getorcreate()" @@ -3115,7 +3115,7 @@ "label": "execute()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L132", + "source_location": "L134", "id": "prometheus_sandbox_execute", "community": 69, "norm_label": "execute()" @@ -3124,7 +3124,7 @@ "label": "read_file()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L168", + "source_location": "L170", "id": "prometheus_sandbox_read_file", "community": 69, "norm_label": "read_file()" @@ -3133,7 +3133,7 @@ "label": "write_file()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L175", + "source_location": "L177", "id": "prometheus_sandbox_write_file", "community": 69, "norm_label": "write_file()" @@ -3142,7 +3142,7 @@ "label": "list_files()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L189", + "source_location": "L191", "id": "prometheus_sandbox_list_files", "community": 69, "norm_label": "list_files()" @@ -3151,7 +3151,7 @@ "label": "delete_file()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L197", + "source_location": "L199", "id": "prometheus_sandbox_delete_file", "community": 69, "norm_label": "delete_file()" @@ -3160,7 +3160,7 @@ "label": "syncToSandbox()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L214", + "source_location": "L216", "id": "prometheus_sandbox_synctosandbox", "community": 69, "norm_label": "synctosandbox()" @@ -3169,7 +3169,7 @@ "label": "syncFromSandbox()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L233", + "source_location": "L235", "id": "prometheus_sandbox_syncfromsandbox", "community": 69, "norm_label": "syncfromsandbox()" @@ -4368,7 +4368,7 @@ "source_file": "main/controller/stocksapi_controller.py", "source_location": "L1", "id": "main_controller_stocksapi_controller_py", - "community": 54, + "community": 81, "norm_label": "stocksapi_controller.py" }, { @@ -4377,7 +4377,7 @@ "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", "id": "controller_stocksapi_controller_health", - "community": 54, + "community": 81, "norm_label": "health()" }, { @@ -4773,7 +4773,7 @@ "source_file": "main/service/prometheus_service.py", "source_location": "L23", "id": "service_prometheus_service_memorymaintenance", - "community": 234, + "community": 518, "norm_label": "memorymaintenance()" }, { @@ -8688,7 +8688,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L1", "id": "docs_superpowers_plans_2026_09_04_wallet_management_md", - "community": 497, + "community": 132, "norm_label": "2026-09-04-wallet-management.md" }, { @@ -8697,7 +8697,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L1", "id": "plans_2026_09_04_wallet_management_wallet_management_thoth_iyagba_implementation_plan", - "community": 497, + "community": 132, "norm_label": "wallet management (thoth/iyagba) implementation plan" }, { @@ -8706,7 +8706,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L13", "id": "plans_2026_09_04_wallet_management_global_constraints", - "community": 497, + "community": 132, "norm_label": "global constraints" }, { @@ -8715,7 +8715,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L35", "id": "plans_2026_09_04_wallet_management_file_structure", - "community": 497, + "community": 132, "norm_label": "file structure" }, { @@ -10091,7 +10091,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", - "community": 54, + "community": 81, "norm_label": "jsonbytesresponse", "id": "controller_stocksapi_controller_jsonbytesresponse" }, @@ -10100,7 +10100,7 @@ "file_type": "code", "source_file": "", "source_location": "", - "community": 54, + "community": 81, "norm_label": "fastapiresponse", "id": "fastapiresponse" }, @@ -10109,7 +10109,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L26", - "community": 54, + "community": 81, "norm_label": ".render()", "id": "controller_stocksapi_controller_jsonbytesresponse_render" }, @@ -12926,7 +12926,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L24", - "community": 54, + "community": 81, "norm_label": "sends pre-serialized json bytes without re-encoding (cache-friendly).", "id": "controller_stocksapi_controller_rationale_24" }, @@ -13070,7 +13070,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L323", - "community": 54, + "community": 81, "norm_label": "generatekey()", "id": "controller_stocksapi_controller_generatekey" }, @@ -27083,7 +27083,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L1", - "community": 518, + "community": 234, "norm_label": "test_memory_maintenance.py", "id": "tests_test_memory_maintenance_py" }, @@ -27092,7 +27092,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L18", - "community": 518, + "community": 234, "norm_label": "brt()", "id": "tests_test_memory_maintenance_brt" }, @@ -27101,7 +27101,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L23", - "community": 518, + "community": 234, "norm_label": "create_memories()", "id": "tests_test_memory_maintenance_create_memories" }, @@ -27110,7 +27110,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L46", - "community": 518, + "community": 234, "norm_label": "testdecay", "id": "tests_test_memory_maintenance_testdecay" }, @@ -27119,7 +27119,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L47", - "community": 518, + "community": 234, "norm_label": ".test_active_memory_decays()", "id": "tests_test_memory_maintenance_testdecay_test_active_memory_decays" }, @@ -27128,7 +27128,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L54", - "community": 518, + "community": 234, "norm_label": ".test_zero_access_count_still_decays()", "id": "tests_test_memory_maintenance_testdecay_test_zero_access_count_still_decays" }, @@ -27137,7 +27137,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L61", - "community": 518, + "community": 234, "norm_label": ".test_high_score_decays_proportionally()", "id": "tests_test_memory_maintenance_testdecay_test_high_score_decays_proportionally" }, @@ -27146,7 +27146,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L67", - "community": 518, + "community": 234, "norm_label": ".test_very_low_score_stays_above_zero()", "id": "tests_test_memory_maintenance_testdecay_test_very_low_score_stays_above_zero" }, @@ -27155,7 +27155,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L74", - "community": 518, + "community": 234, "norm_label": ".test_multiple_users_all_decayed()", "id": "tests_test_memory_maintenance_testdecay_test_multiple_users_all_decayed" }, @@ -27290,7 +27290,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L171", - "community": 234, + "community": 518, "norm_label": ".test_no_memories_does_not_crash()", "id": "tests_test_memory_maintenance_testemptydatabase_test_no_memories_does_not_crash" }, @@ -27299,7 +27299,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L24", - "community": 518, + "community": 234, "norm_label": "helper to create memories with controlled basescore, lastaccessedat, accesscount", "id": "tests_test_memory_maintenance_rationale_24" }, @@ -27308,7 +27308,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L55", - "community": 518, + "community": 234, "norm_label": "decay applies to all active memories, not just accessed ones.", "id": "tests_test_memory_maintenance_rationale_55" }, @@ -27317,7 +27317,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L68", - "community": 518, + "community": 234, "norm_label": "basescore should never reach exactly 0 from decay alone.", "id": "tests_test_memory_maintenance_rationale_68" }, @@ -32258,7 +32258,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L841", - "community": 17, + "community": 39, "norm_label": ".test_fundamental_date_range_two_dates()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_date_range_two_dates" }, @@ -32285,7 +32285,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L882", - "community": 39, + "community": 17, "norm_label": ".test_fundamental_search_multiple_terms()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_search_multiple_terms" }, @@ -32303,7 +32303,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L898", - "community": 17, + "community": 39, "norm_label": ".test_fundamental_dates_one_date()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_dates_one_date" }, @@ -32951,7 +32951,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L842", - "community": 17, + "community": 39, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_842" }, @@ -32978,7 +32978,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L883", - "community": 39, + "community": 17, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_883" }, @@ -32996,7 +32996,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L899", - "community": 17, + "community": 39, "norm_label": "len(daterange) == 1 -> per-ticker closest snapshot.", "id": "tests_test_stocks_api_coverage_rationale_899" }, @@ -34328,7 +34328,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L1", - "community": 234, + "community": 518, "norm_label": "test_type_aware_decay.py", "id": "tests_test_type_aware_decay_py" }, @@ -34337,7 +34337,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L11", - "community": 234, + "community": 518, "norm_label": "_create()", "id": "tests_test_type_aware_decay_create" }, @@ -34346,7 +34346,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L29", - "community": 234, + "community": 518, "norm_label": "testtypeawaredecay", "id": "tests_test_type_aware_decay_testtypeawaredecay" }, @@ -34355,7 +34355,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L30", - "community": 234, + "community": 518, "norm_label": ".test_preference_decays_slowly()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_preference_decays_slowly" }, @@ -34364,7 +34364,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L36", - "community": 234, + "community": 518, "norm_label": ".test_context_decays_fast()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_context_decays_fast" }, @@ -34373,7 +34373,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L42", - "community": 234, + "community": 518, "norm_label": ".test_analysis_decays_normally()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_analysis_decays_normally" }, @@ -34382,7 +34382,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L48", - "community": 234, + "community": 518, "norm_label": ".test_feedback_decays_medium()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_feedback_decays_medium" }, @@ -34391,7 +34391,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L54", - "community": 234, + "community": 518, "norm_label": ".test_unknown_type_uses_default()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_unknown_type_uses_default" }, @@ -34400,7 +34400,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L60", - "community": 234, + "community": 518, "norm_label": ".test_mixed_types_all_correct()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_mixed_types_all_correct" }, @@ -34409,7 +34409,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L76", - "community": 234, + "community": 518, "norm_label": ".test_preference_survives_longer()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_preference_survives_longer" }, @@ -34418,7 +34418,7 @@ "file_type": "rationale", "source_file": "tests/test_type_aware_decay.py", "source_location": "L77", - "community": 234, + "community": 518, "norm_label": "after 10 cycles, preference (0.99^10) > context (0.90^10).", "id": "tests_test_type_aware_decay_rationale_77" }, @@ -41132,7 +41132,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L23", - "community": 518, + "community": 234, "norm_label": "helper to create memories with controlled basescore, lastaccessedat, accesscount", "id": "tests_test_memory_maintenance_rationale_23" }, @@ -41141,7 +41141,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L54", - "community": 518, + "community": 234, "norm_label": "decay applies to all active memories, not just accessed ones.", "id": "tests_test_memory_maintenance_rationale_54" }, @@ -41150,7 +41150,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L67", - "community": 518, + "community": 234, "norm_label": "basescore should never reach exactly 0 from decay alone.", "id": "tests_test_memory_maintenance_rationale_67" }, @@ -46424,7 +46424,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L896", - "community": 17, + "community": 39, "norm_label": "search.strip() == '' should still dedup (line 181).", "id": "tests_test_stocks_api_coverage_rationale_896" }, @@ -46433,7 +46433,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L905", - "community": 17, + "community": 39, "norm_label": "dataframe without time column.", "id": "tests_test_stocks_api_coverage_rationale_905" }, @@ -46442,7 +46442,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L918", - "community": 17, + "community": 39, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_918" }, @@ -46469,7 +46469,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L959", - "community": 39, + "community": 17, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_959" }, @@ -46487,7 +46487,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L975", - "community": 17, + "community": 39, "norm_label": "len(daterange) == 1 -> per-ticker closest snapshot.", "id": "tests_test_stocks_api_coverage_rationale_975" }, @@ -47207,7 +47207,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L917", - "community": 17, + "community": 39, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_917" }, @@ -47225,7 +47225,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L956", - "community": 39, + "community": 17, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_956" }, @@ -47243,7 +47243,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L972", - "community": 17, + "community": 39, "norm_label": "len(daterange) == 1 -> single date filter.", "id": "tests_test_stocks_api_coverage_rationale_972" }, @@ -47495,7 +47495,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L907", - "community": 17, + "community": 39, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_907" }, @@ -47513,7 +47513,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L946", - "community": 39, + "community": 17, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_946" }, @@ -47531,7 +47531,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L962", - "community": 17, + "community": 39, "norm_label": "len(daterange) == 1 -> single date filter.", "id": "tests_test_stocks_api_coverage_rationale_962" }, @@ -48233,7 +48233,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L63", - "community": 54, + "community": 81, "norm_label": "getrealtimecotation()", "id": "controller_stocksapi_controller_getrealtimecotation" }, @@ -48341,7 +48341,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", - "community": 54, + "community": 81, "norm_label": "apikeytest()", "id": "controller_stocksapi_controller_apikeytest" }, @@ -50015,7 +50015,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L906", - "community": 17, + "community": 39, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_906" }, @@ -50042,7 +50042,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L945", - "community": 39, + "community": 17, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_945" }, @@ -50060,7 +50060,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L961", - "community": 17, + "community": 39, "norm_label": "len(daterange) == 1 -> single date filter.", "id": "tests_test_stocks_api_coverage_rationale_961" }, @@ -50276,7 +50276,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L898", - "community": 17, + "community": 39, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_898" }, @@ -50303,7 +50303,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L937", - "community": 39, + "community": 17, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_937" }, @@ -50375,7 +50375,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L935", - "community": 39, + "community": 17, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_935" }, @@ -50393,7 +50393,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L951", - "community": 17, + "community": 39, "norm_label": "len(daterange) == 1 -> single date filter.", "id": "tests_test_stocks_api_coverage_rationale_951" }, @@ -50510,7 +50510,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L850", - "community": 17, + "community": 39, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_850" }, @@ -50528,7 +50528,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L889", - "community": 39, + "community": 17, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_889" }, @@ -50672,7 +50672,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L851", - "community": 17, + "community": 39, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_851" }, @@ -50699,7 +50699,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L890", - "community": 39, + "community": 17, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_890" }, @@ -51788,7 +51788,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L845", - "community": 17, + "community": 39, "norm_label": "two dates in the range, both valid.", "id": "tests_test_stocks_api_coverage_rationale_845" }, @@ -51824,7 +51824,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L900", - "community": 17, + "community": 39, "norm_label": "len(daterange) == 1 -> single date filter.", "id": "tests_test_stocks_api_coverage_rationale_900" }, @@ -137183,5 +137183,5 @@ "label": "User Authentication & Authorization" } ], - "built_at_commit": "c70c13418661d63720e47519841e95aaabdff09f" + "built_at_commit": "78084c0d76c87622625b9986338e6ffe40c7a28c" } \ No newline at end of file diff --git a/graphify-out/manifest.json b/graphify-out/manifest.json index bcfef5a..cfed237 100644 --- a/graphify-out/manifest.json +++ b/graphify-out/manifest.json @@ -255,8 +255,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\sandbox.py": { - "mtime": 1789363629.931731, - "ast_hash": "cc5b2154f508462c4c2d1a90cc1074b0", + "mtime": 1789426167.0614476, + "ast_hash": "f01487f8c547d78045bba5405e7d7e1e", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\stream_bus.py": { diff --git a/main/app/prometheus/compact.py b/main/app/prometheus/compact.py index 949a12e..0ad9c14 100644 --- a/main/app/prometheus/compact.py +++ b/main/app/prometheus/compact.py @@ -16,7 +16,7 @@ EPISODE_TOKEN_BUDGET = 8000 EPISODE_CAP = 12 -FALLBACK_FIELDS = ("P/L", "P/VP", "ROE", "DY", "LPA", "VPA", "PRECO", "INVESTING SCORE") +FALLBACK_FIELDS = ("P/L", "P/VP", "ROE", "DY", "LPA", "VPA", "PRECO", "INVESTING SCORE") # improve ts DECISION_KEYWORDS = re.compile( r"(?:prefiro|prefere|quero|gostaria|sempre|nunca|quando|" diff --git a/main/app/prometheus/memory.py b/main/app/prometheus/memory.py index 5bc0cf3..767b84d 100644 --- a/main/app/prometheus/memory.py +++ b/main/app/prometheus/memory.py @@ -69,7 +69,6 @@ def clearAll() -> None: MEMORY_EXTRACTION_TOKEN_BUDGET = 32000 MEMORY_EXTRACT_FREE_CAP = 5 MEMORY_EXTRACT_PREMIUM_CAP = 10 -MEMORY_SEARCH_PREFILTER_CAP = 500 client = None @@ -286,7 +285,7 @@ def search( candidateRows = ( queryFilter.options(defer(cast(Any, PrometheusMemoryModel.embedding))) .order_by(PrometheusMemoryModel.score.desc()) - .limit(MEMORY_SEARCH_PREFILTER_CAP) + .limit(500) .all() ) if not candidateRows: @@ -319,7 +318,7 @@ def loadMatrix() -> tuple[list[int], np.ndarray]: logger.warning(f"Embedding scoring failed, using full-text and recency only: {e}") vecScores = [simById.get(cast(int, m.id), 0.0) for m in candidateRows] vecNorm = minMax(vecScores) - ftRows = cls.fullTextSearch(db, userId, query, MEMORY_SEARCH_PREFILTER_CAP) + ftRows = cls.fullTextSearch(db, userId, query, 500) ftRank = {r["id"]: 1.0 / (i + 1) for i, r in enumerate(ftRows)} now = datetime.now(timezone.utc) return scoreCandidates(candidateRows, vecNorm, simById, ftRank, now, limit) diff --git a/main/app/prometheus/sandbox.py b/main/app/prometheus/sandbox.py index cadba6d..5ba682f 100644 --- a/main/app/prometheus/sandbox.py +++ b/main/app/prometheus/sandbox.py @@ -22,15 +22,9 @@ def lockFor(userId: int) -> asyncio.Lock: def getClient() -> AsyncClient: - forgeUrl = Config.PROMETHEUS.FORGEVM_URL - forgeToken = Config.PROMETHEUS.FORGEVM_API_TOKEN - if forgeUrl and not forgeToken: - raise RuntimeError( - f"FORGEVM_URL is set ({forgeUrl}) but FORGEVM_API_TOKEN is empty; set FORGEVM_API_TOKEN or unset FORGEVM_URL for local dev" - ) return AsyncClient( - base_url=forgeUrl, - api_key=forgeToken or None, + base_url=Config.PROMETHEUS.FORGEVM_URL, + api_key=Config.PROMETHEUS.FORGEVM_API_TOKEN or None, timeout=30, ) From c6db3518ed17340ddaba169767559825ff16a111 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 22:06:39 -0300 Subject: [PATCH 37/57] doc --- AGENTS.md | 12 +- PONYTAIL.md | 90 -------------- graphify-out/GRAPH_REPORT.md | 28 ++--- graphify-out/graph.json | 156 ++++++++++++------------- graphify-out/manifest.json | 12 +- main/app/user/user.py | 3 +- main/service/authentication_service.py | 5 +- main/utils/models/loader.py | 3 - run.py | 11 +- 9 files changed, 119 insertions(+), 201 deletions(-) delete mode 100644 PONYTAIL.md diff --git a/AGENTS.md b/AGENTS.md index 537da36..869acb4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -55,4 +55,14 @@ Rules: - Before answering architecture or codebase questions, read graphify-out/GRAPH_REPORT.md for god nodes and community structure - If graphify-out/wiki/index.md exists, navigate it instead of reading raw files - For cross-module "how does X relate to Y" questions, prefer `graphify query ""`, `graphify path "" ""`, or `graphify explain ""` over grep — these traverse the graph's EXTRACTED + INFERRED edges instead of scanning files -- After modifying code files in this session, run `graphify update .` to keep the graph current (AST-only, no API cost) \ No newline at end of file +- After modifying code files in this session, run `graphify update .` to keep the graph current (AST-only, no API cost) + +## Swarm Delegation (default) + +- All 3+ step tasks: `create_goal` + `todowrite` lanes (one todo per lane) + `delegate()` fan-out, one call per lane in one turn. +- Background by default, blocking by exception (`task()` only for mutations prime must supervise). +- Every lane returns an envelope: `Status: / Mutations: / Edge-Cases: / Deliverables:` ≤300 words + `file:line`. +- Verify every lane: `git --no-pager log --oneline -N` + real test output. Never report a delegate's commits/tests as fact. +- One commit per lane (`simple-commits`: lowercase, one logical change). Full `.\ci.ps1` before push. +- Always `git --no-pager` on diff/log/show/status. Never `Get-Content -Wait` — poll with `Get-Content -Tail N`. +- Standing bans: NEVER run any `TestStocksCacheManager::test_getCachedStocks_*` (spawns real cache build, stalls ~1hr — always `-k "not test_getCachedStocks_"`); never run bare pytest, only `.\ci.ps1`; never touch `stash@{1}` or foreign stashes. \ No newline at end of file diff --git a/PONYTAIL.md b/PONYTAIL.md deleted file mode 100644 index 8b2e2b0..0000000 --- a/PONYTAIL.md +++ /dev/null @@ -1,90 +0,0 @@ -# PONYTAIL.md — proposed cuts, NOT applied. Approve before any edit. - -Status: PROPOSAL. Nothing below is cut. Reply approve (all / by line) or reject. -Format: ` . . [path]`. Ranked biggest cut first. - -## Proposed (awaiting approval) - -delete Merge test_prometheus_auth_coverage.py into resume/streammessage/controller/session tests; keep one file per area. [tests/test_prometheus_auth_coverage.py] (~450) -shrink Replace make_*_client helpers + per-test FastAPI builds with conftest fixtures. [tests/test_controllers_coverage.py] (~250) -shrink Collapse 5x make_manager/make_stocks_df helpers + overlapping query cases into shared helpers + parametrized cases. [tests/test_stocks_api_coverage.py] (~250) -shrink Parametrize single-assert guard classes into tables. [tests/test_stocks_compress.py] (~150) -delete Delete test_stocks_util.py; identical cases live in test_stocks_api_util_coverage.py. [tests/test_stocks_util.py] (~99) -stdlib Delete test_pagination.py dummy /items app; re-tests FastAPI validation, not app code. [tests/test_pagination.py] (~85) -shrink Extract repeated quota-update statement into one helper; 7 tests copy it. [tests/test_api_key_quota_atomic.py] (~80) -delete Delete TestMemoryToolFunctions/TestToolRegistry dupes; identical asserts in test_prometheus_tools.py. [tests/test_memory_tools_wiring.py] (~75) -shrink Parametrize decay-formula cases into one table. [tests/test_relevance_score.py] (~60) -shrink Parametrize one-liner mock chains via shared mockDb factory + tables. [tests/test_compact.py] (~55) -delete Merge TestConcurrentGetSession into TestGetSession; delete test_http_session_coverage.py. [tests/test_http_session_coverage.py] (~50) -shrink Triple appendHistory try/except; extract _persistEvent(db, sessionId, entry). [main/app/prometheus/agent.py] (~35) -stdlib logging.handlers QueueHandler/QueueListener replaces hand deque+Lock+Event+thread queue. [main/utils/logging_config.py] (~25) -shrink Move duplicated mock_forgevm() into conftest.py. [tests/test_sandbox.py] (~20) -delete Dual lru_cache getAbbr/getNest + rebuildAbbrevs + function-local import; compute inline. [main/app/stocks_api/compress.py] (~18) -stdlib Delete TestEbbinghausRetention; asserts math.exp() not app behavior. [tests/test_memory_maintenance.py] (~15) -delete CACHE_NESTED_PATH/sampleParts/sampleCols/nestedSample plumbing; sample the loaded frame. [main/app/stocks_api/cache.py] (~15) -shrink Duplicate existing/similar update blocks in upsertMemory; extract _touch helper. [main/app/prometheus/memory.py] (~14) -delete Lossy SUF suffixes + DF/DI year-stripping in compactValue; keep float rounding. [main/app/stocks_api/compress.py] (~14) -yagni Delete inspect.getsource text-scan test; asserts source absence not behavior. [tests/test_agent_sandbox_integration.py] (~13) -delete getHistoricalFields/getFundamentalColumns/invalidateFieldData; zero callers. [main/app/prometheus/compact.py] (~12) -shrink scoreRecency/scoreCandidates identical dict shape; extract _scoreRow. [main/app/prometheus/memory.py] (~12) -native Coverage-threshold inline XML parse; use coverage report --fail-under=80. [ci.ps1] (~12) -yagni StocksQueryManager single-instance class + snapshot() fallback; module functions suffice. [main/app/stocks_api/query.py] (~12) -delete getDeviceName + device/browser/os keys; createSession never populates them, always None. [main/app/authentication/session.py] (~11) -delete try/except ImportError fallback + comment block; raw import per project rule. [main/models/user.py:20-29] (~10) -yagni matrixKey/matrixUserTag single-use helpers; inline f-strings. [main/app/prometheus/memory.py] (~10, verify — may be gone post-P1) -stdlib parseDate/parseDateRange calendar logic; datetime.date.fromisoformat covers it. [main/app/stocks_api/util.py] (~10) -shrink Hand-rolled mypy capture block; use existing Run-Check. [ci.ps1] (~10) -shrink isSecureScheme try/except+split into one expression. [main/controller/authentication_controller.py] (~7) -shrink Logout token block; call extractTokenPayload. [main/controller/authentication_controller.py] (~7) -shrink Auto-fix triple ruff invocation; single ruff check --fix. [ci.ps1] (~8) -shrink loadFieldData isinstance branching; one-liner coercions. [main/app/prometheus/compact.py] (~8) -shrink Migrator chdir dance; pass cwd= to subprocess.run. [main/utils/migrator.py] (~6) -yagni FALLBACK_METRIC_RE + extractMetrics useRegistry param; sole caller passes True. [main/app/prometheus/compact.py] (~6) -delete forgevm.yaml defaults: block; app passes all four explicitly. [forgevm.yaml] (~6) -shrink initialize/reconnect duplicate steps; extract _connect. [main/app/prometheus/mcp.py] (~6) -stdlib orjson→json fallback + sniffing in deserializeJsonColumns; orjson-only. [main/app/stocks_api/query.py] (~6) -shrink buildTickerIndex loop + sortCacheFrame try/except; dict comprehension + single sort_values. [main/app/stocks_api/cache.py] (~6) -shrink createAccessToken tuple return; all callers discard 2nd element. [main/app/authentication/util.py] (~5) -delete decodeEmbeddings non-bytes branch; sole caller passes bytes only. [main/app/prometheus/vector.py] (~5) -delete exceptSessionId param + branch in revokeAllSessions; sole caller passes None. [main/app/authentication/session.py] (~4) -shrink checkServiceConnection double-except; collapse to one. [main/utils/connectivity.py] (~4) -shrink getMatrix redundant asyncio.run get after set; return fresh values. [main/app/prometheus/memory.py] (~4) -shrink countTokensCached one-line wrapper; inline. [main/app/prometheus/memory.py] (~4) -delete stocks-cache:/app/cache mount + volumes entry; .:/app bind covers it. [docker-compose.yml] (~3) -delete Unused StocksApiSettings KEY/DEFAULT_QUOTA/QUOTA_RESETDAYS fields. [config.py] (~3) - soon to be implemented, keep the KEY and consider removing the DEFAULT_QUOTA/QUOTA_RESETDAYS -delete includeInactive param + branch in getUserSessions; never True. [main/app/authentication/session.py] (~3) -shrink queryHistorical/queryFundamental/queryCotations triple blocks; one validateFields + envelope helper. [main/app/stocks_api/query.py] (~30) -delete TestSessionExpiryConfig; covered by TestSessionExpiration in test_sessions.py. [tests/test_auth_util.py] (~30) -delete --mount=type=cache paired with --no-cache-dir; keep one mechanism. [Dockerfile] (~2) -delete Unused import asyncio. [run.py] (~1) -delete mcp==1.29.0 pin; zero direct imports, transitive-only. [requirements.txt] (~1) - -Net proposed: ~2,200 lines + 1 dependency (mcp pin). - -## Disputed (already litigated — needs your ruling to proceed) - -shrink toColumnar/walk/fixHeaders generic h/d pipe-encoding; keep compactCotations nested h/d for cotation series (Alt C: gzip saves transport bytes, pipe-encoding saves LLM tokens — orthogonal). [main/app/stocks_api/compress.py] (~40) -delete sync_cache.py wrapper; use cashews @cache directly. [main/app/stocks_api/sync_cache.py] (~31) — you blessed shrink-only. (keep the decorator, refused or find a way to make @caceh async, dont create helper functions to make it work properly, the @cache should go above the controller func, not a different func at this case) -delete subprocess.run self-spawn + fcntl lock; direct build in thread. [main/app/stocks_api/cache.py] (~28) — restored deliberately (OOM risk). (building in the thread wouldnt stall the entire operation and also, if im running more than one instance of the server, they could clash or idk) -delete SandboxManager.write_bytes. [main/app/prometheus/sandbox.py] (~10) — restored, 3 workspace tests call it. (delete it, keep only write_file) -delete toVectorString/fromVectorString converters. [main/app/prometheus/vector.py] (~14) — kept for MySQL 9 compat read path. (consider making a plan to upgrade the mysql version in the container to 9 then afterwards, so we can properly replace it. keep for the last, after every change has been implemenmted) - -## Held out (your ignore rules — not proposed) - -shrink 10 repetitive try/except-nan blocks into one safe() helper. [main/app/scraper_b3/scraper.py] (~35) — scraper.py ignored. -delete historicalCotationProfits_Oceans14 + task slot. [main/app/scraper_b3/scraper.py] (~13) — scraper.py ignored. -shrink tagAlong triple-fallback regex into single pattern. [main/app/scraper_b3/scraper.py] (~6) — scraper.py ignored. - -## Refused - -delete Abbreviation engine autoAbbreviate/dedupAbbrev/generateAbbreviations/detectNestedFields; return full names, gzip covers size. [main/app/stocks_api/util.py] (~55) - the abbreviations serve the porpouse of compressing token outputs for ai agents that use the MCP for the stocks api -delete Manual pa.schema build + arrowTypeFor; pa.Table.from_pandas infers types. [main/app/stocks_api/cache.py] (~20) - possible negative performance outcomes -shrink search_memory/save_memory duplicate SessionLocal blocks; extract _withDb. [main/app/prometheus/tools.py] (~10) - bloated simplification -delete SessionManager.updateLastActive; zero callers. [main/app/authentication/session.py] (~8) - the api/frontend should log when a user is active and update this param so the /sessions track the current situation of user sessions -delete Manual Docker Compose curl-install; runners ship docker compose. [.github/workflows/ci.yml] (~5) - working well enough, dont change -shrink Single-entry strategy.matrix; hardcode python-version. [.github/workflows/ci.yml] (~4) - working well enough, dont change -shrink Two pip install steps in builder; merge into one. [Dockerfile] (~3) - working well enough, dont change -delete Duplicate Show API logs step; container-logs step covers it. [.github/workflows/ci.yml] (~3) - working well enough, dont change -delete DEVELOPER_STARTER/DEVELOPER_ENTERPRISE aliases; both equal USER, never assigned. [main/utils/roles.py] (~3) - keep, going to be implemented soon -delete Heredoc docker-compose.ci.yml; reuse root compose with env overrides. [.github/workflows/ci.yml] (~28) - working well enough, dont change -shrink Triple-3200 api port mappings; distinct defaults or one mapping. [docker-compose.yml] (~2) - working well enough, dont change \ No newline at end of file diff --git a/graphify-out/GRAPH_REPORT.md b/graphify-out/GRAPH_REPORT.md index e11bf26..471c52a 100644 --- a/graphify-out/GRAPH_REPORT.md +++ b/graphify-out/GRAPH_REPORT.md @@ -1,7 +1,7 @@ # Graph Report - server (2026-09-14) ## Corpus Check -- 124 files · ~73,751 words +- 124 files · ~73,721 words - Verdict: corpus is large enough that graph structure adds value. ## Summary @@ -10,7 +10,7 @@ - Token cost: 0 input · 0 output ## Graph Freshness -- Built from commit: `78084c0d` +- Built from commit: `5ad08ba0` - Run `git rev-parse HEAD` and compare to check if the graph is stale. - Run `graphify update .` after code changes (no API cost). @@ -683,7 +683,7 @@ Nodes (31): _make_prometheus_client(), Covers lines 114-115, 117-120, 122, 125: ### Community 17 - "Community 17" Cohesion: 0.11 -Nodes (17): Multiple search terms with tickerIndex., Multiple search terms with tickerIndex., Multiple search terms with tickerIndex., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., Multiple search terms with tickerIndex., Multiple search terms with tickerIndex. (+9 more) +Nodes (16): Multiple search terms with tickerIndex., Multiple search terms with tickerIndex., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., Multiple search terms with tickerIndex., Multiple search terms with tickerIndex., Search with no index match falls back to string startswith. (+8 more) ### Community 18 - "Community 18" Cohesion: 0.07 @@ -771,7 +771,7 @@ Nodes (27): code:json ([), code:javascript (const loadHistory = async (sid) => { ### Community 39 - "Community 39" Cohesion: 0.05 -Nodes (40): Invalid date -> inner 400 passes through (not wrapped as 500)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500. (+32 more) +Nodes (41): Invalid date -> inner 400 passes through (not wrapped as 500)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500. (+33 more) ### Community 40 - "Community 40" Cohesion: 0.12 @@ -830,8 +830,8 @@ Cohesion: 0.1 Nodes (39): applyUpdate(), archiveDead(), clearAll(), clearAllAsync(), count_memories(), countMemories(), countTokensCached(), decayScores() (+31 more) ### Community 54 - "Community 54" -Cohesion: 0.2 -Nodes (10): listFields(), Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental. (+2 more) +Cohesion: 0.11 +Nodes (14): generateKey(), JSONBytesResponse, listFields(), Sends pre-serialized JSON bytes without re-encoding (cache-friendly)., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental. (+6 more) ### Community 55 - "Community 55" Cohesion: 0.11 @@ -934,8 +934,8 @@ Cohesion: 0.16 Nodes (18): buildSummary(), charCount(), countTokens(), dedup(), extractDecisions(), extractMetrics(), extractSnapshots(), extractTickers() (+10 more) ### Community 81 - "Community 81" -Cohesion: 0.09 -Nodes (17): generateKey(), getLiveCotation(), JSONBytesResponse, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Sends pre-serialized JSON bytes without re-encoding (cache-friendly)., Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th (+9 more) +Cohesion: 0.15 +Nodes (13): getLiveCotation(), Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th (+5 more) ### Community 82 - "Community 82" Cohesion: 0.15 @@ -1135,7 +1135,7 @@ Nodes (17): Same input → same hash., Different inputs → different hashes., R ### Community 132 - "Community 132" Cohesion: 0.25 -Nodes (7): code:python ("""add wallet_holdings and wallet_lots tables), code:python (import main.models.wallet), code:bash (git add migrations/versions/wallet_tables_20260904_add_walle), File Structure, Global Constraints, Task 2: Alembic migration for wallet tables, Wallet Management (Thoth/Iyagba) Implementation Plan +Nodes (7): code:python (from dataclasses import dataclass), code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py ), code:python (from datetime import date), File Structure, Global Constraints, Task 3: Pure derivation math, Wallet Management (Thoth/Iyagba) Implementation Plan ### Community 133 - "Community 133" Cohesion: 0.18 @@ -1518,8 +1518,8 @@ Cohesion: 0.4 Nodes (5): 8. Build Sequence (4 phases, each independently shippable), Phase 0 — Sandbox foundation (1-2 days, no user-facing change), Phase 1 — MCP exposure of STOCKS_API (1 day), Phase 2 — Refactor PROMETHEUS to agentic (3-5 days, the big one), Phase 3 — Hardening (1-2 days, can ship incrementally) ### Community 234 - "Community 234" -Cohesion: 0.1 -Nodes (15): create_memories(), Decay happens first, then archive check with new scores., Decay happens first, then archive check with new scores., Score that decays to >= threshold stays alive. 0.11 * 0.95 = 0.1045 >= 0.1., Score that decays to >= threshold stays alive. 0.12 * 0.90 = 0.108 >= 0.1., 89 days with low score → not archived (need > 90)., 89 days with low score → not archived (need > 90)., Helper to create memories with controlled baseScore, lastAccessedAt, accessCount (+7 more) +Cohesion: 0.14 +Nodes (11): memoryMaintenance(), Decay happens first, then archive check with new scores., Decay happens first, then archive check with new scores., Score that decays to >= threshold stays alive. 0.11 * 0.95 = 0.1045 >= 0.1., Score that decays to >= threshold stays alive. 0.12 * 0.90 = 0.108 >= 0.1., 89 days with low score → not archived (need > 90)., 89 days with low score → not archived (need > 90)., TestDecayAndArchiveTogether (+3 more) ### Community 236 - "Community 236" Cohesion: 0.5 @@ -1683,7 +1683,7 @@ Nodes (4): Authentication System, Google OAuth, JWT Authentication, TestSessionE ### Community 497 - "Community 497" Cohesion: 0.5 -Nodes (4): code:python (from dataclasses import dataclass), code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py ), code:python (from datetime import date), Task 3: Pure derivation math +Nodes (4): code:python ("""add wallet_holdings and wallet_lots tables), code:python (import main.models.wallet), code:bash (git add migrations/versions/wallet_tables_20260904_add_walle), Task 2: Alembic migration for wallet tables ### Community 498 - "Community 498" Cohesion: 0.06 @@ -1738,8 +1738,8 @@ Cohesion: 0.25 Nodes (14): baseFrame(), deserializeJsonColumns(), envelope(), filterBySearchTerms(), _filterCotationByDate(), filterCotationData(), finalize(), _parseCotationDate() (+6 more) ### Community 518 - "Community 518" -Cohesion: 0.11 -Nodes (15): memoryMaintenance(), Zero access but score still above threshold → not archived., Even with low score, if accessed → not archived., Even with low score, if accessed → not archived., Already archived memories are skipped., Already archived memories are skipped., Score below threshold + accessCount=0 + 90+ days → archived., Score below threshold + accessCount=0 + 90+ days → archived. (+7 more) +Cohesion: 0.08 +Nodes (19): create_memories(), Zero access but score still above threshold → not archived., Even with low score, if accessed → not archived., Even with low score, if accessed → not archived., Already archived memories are skipped., Already archived memories are skipped., Helper to create memories with controlled baseScore, lastAccessedAt, accessCount, Helper to create memories with controlled baseScore, lastAccessedAt, accessCount (+11 more) ### Community 519 - "Community 519" Cohesion: 0.57 diff --git a/graphify-out/graph.json b/graphify-out/graph.json index e30c7f7..aeacec3 100644 --- a/graphify-out/graph.json +++ b/graphify-out/graph.json @@ -2872,7 +2872,7 @@ "label": "getClient()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L77", + "source_location": "L76", "id": "prometheus_memory_getclient", "community": 53, "norm_label": "getclient()" @@ -2881,7 +2881,7 @@ "label": "minMax()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L84", + "source_location": "L83", "id": "prometheus_memory_minmax", "community": 53, "norm_label": "minmax()" @@ -2890,7 +2890,7 @@ "label": "normalizeKey()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L93", + "source_location": "L92", "id": "prometheus_memory_normalizekey", "community": 53, "norm_label": "normalizekey()" @@ -2899,7 +2899,7 @@ "label": "findSimilarKey()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L100", + "source_location": "L99", "id": "prometheus_memory_findsimilarkey", "community": 53, "norm_label": "findsimilarkey()" @@ -2908,7 +2908,7 @@ "label": "scoreRow()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L123", + "source_location": "L122", "id": "prometheus_memory_scorerow", "community": 53, "norm_label": "scorerow()" @@ -2917,7 +2917,7 @@ "label": "scoreRecency()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L135", + "source_location": "L134", "id": "prometheus_memory_scorerecency", "community": 53, "norm_label": "scorerecency()" @@ -2926,7 +2926,7 @@ "label": "scoreCandidates()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L145", + "source_location": "L144", "id": "prometheus_memory_scorecandidates", "community": 53, "norm_label": "scorecandidates()" @@ -2935,7 +2935,7 @@ "label": "sumTokens()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L162", + "source_location": "L161", "id": "prometheus_memory_sumtokens", "community": 53, "norm_label": "sumtokens()" @@ -2944,7 +2944,7 @@ "label": "PrometheusMemory", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L177", + "source_location": "L176", "id": "prometheus_memory_prometheusmemory", "community": 140, "norm_label": "prometheusmemory" @@ -2953,7 +2953,7 @@ "label": "getMemoryLimit()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L179", + "source_location": "L178", "id": "prometheus_memory_getmemorylimit", "community": 53, "norm_label": "getmemorylimit()" @@ -2962,7 +2962,7 @@ "label": "countMemories()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L185", + "source_location": "L184", "id": "prometheus_memory_countmemories", "community": 53, "norm_label": "countmemories()" @@ -2971,7 +2971,7 @@ "label": "touch()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L194", + "source_location": "L193", "id": "prometheus_memory_touch", "community": 53, "norm_label": "touch()" @@ -2980,7 +2980,7 @@ "label": "upsertMemory()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L205", + "source_location": "L204", "id": "prometheus_memory_upsertmemory", "community": 53, "norm_label": "upsertmemory()" @@ -2989,7 +2989,7 @@ "label": "search()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L269", + "source_location": "L268", "id": "prometheus_memory_search", "community": 53, "norm_label": "search()" @@ -2998,7 +2998,7 @@ "label": "fullTextSearch()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L332", + "source_location": "L331", "id": "prometheus_memory_fulltextsearch", "community": 53, "norm_label": "fulltextsearch()" @@ -3007,7 +3007,7 @@ "label": "getUserMemories()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L390", + "source_location": "L389", "id": "prometheus_memory_getusermemories", "community": 27, "norm_label": "getusermemories()" @@ -3016,7 +3016,7 @@ "label": "deleteMemory()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L415", + "source_location": "L414", "id": "prometheus_memory_deletememory", "community": 53, "norm_label": "deletememory()" @@ -3025,7 +3025,7 @@ "label": "extract()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L433", + "source_location": "L432", "id": "prometheus_memory_extract", "community": 53, "norm_label": "extract()" @@ -3061,7 +3061,7 @@ "label": "hostPath()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L38", + "source_location": "L32", "id": "prometheus_sandbox_hostpath", "community": 69, "norm_label": "hostpath()" @@ -3070,7 +3070,7 @@ "label": "sandboxPath()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L52", + "source_location": "L46", "id": "prometheus_sandbox_sandboxpath", "community": 69, "norm_label": "sandboxpath()" @@ -3079,7 +3079,7 @@ "label": "SandboxManager", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L57", + "source_location": "L51", "id": "prometheus_sandbox_sandboxmanager", "community": 2, "norm_label": "sandboxmanager" @@ -3088,7 +3088,7 @@ "label": "create()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L59", + "source_location": "L53", "id": "prometheus_sandbox_create", "community": 69, "norm_label": "create()" @@ -3097,7 +3097,7 @@ "label": "destroy()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L75", + "source_location": "L69", "id": "prometheus_sandbox_destroy", "community": 69, "norm_label": "destroy()" @@ -3106,7 +3106,7 @@ "label": "getOrCreate()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L87", + "source_location": "L81", "id": "prometheus_sandbox_getorcreate", "community": 69, "norm_label": "getorcreate()" @@ -3115,7 +3115,7 @@ "label": "execute()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L134", + "source_location": "L128", "id": "prometheus_sandbox_execute", "community": 69, "norm_label": "execute()" @@ -3124,7 +3124,7 @@ "label": "read_file()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L170", + "source_location": "L164", "id": "prometheus_sandbox_read_file", "community": 69, "norm_label": "read_file()" @@ -3133,7 +3133,7 @@ "label": "write_file()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L177", + "source_location": "L171", "id": "prometheus_sandbox_write_file", "community": 69, "norm_label": "write_file()" @@ -3142,7 +3142,7 @@ "label": "list_files()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L191", + "source_location": "L185", "id": "prometheus_sandbox_list_files", "community": 69, "norm_label": "list_files()" @@ -3151,7 +3151,7 @@ "label": "delete_file()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L199", + "source_location": "L193", "id": "prometheus_sandbox_delete_file", "community": 69, "norm_label": "delete_file()" @@ -3160,7 +3160,7 @@ "label": "syncToSandbox()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L216", + "source_location": "L210", "id": "prometheus_sandbox_synctosandbox", "community": 69, "norm_label": "synctosandbox()" @@ -3169,7 +3169,7 @@ "label": "syncFromSandbox()", "file_type": "code", "source_file": "main/app/prometheus/sandbox.py", - "source_location": "L235", + "source_location": "L229", "id": "prometheus_sandbox_syncfromsandbox", "community": 69, "norm_label": "syncfromsandbox()" @@ -4368,7 +4368,7 @@ "source_file": "main/controller/stocksapi_controller.py", "source_location": "L1", "id": "main_controller_stocksapi_controller_py", - "community": 81, + "community": 54, "norm_label": "stocksapi_controller.py" }, { @@ -4377,7 +4377,7 @@ "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", "id": "controller_stocksapi_controller_health", - "community": 81, + "community": 54, "norm_label": "health()" }, { @@ -4773,7 +4773,7 @@ "source_file": "main/service/prometheus_service.py", "source_location": "L23", "id": "service_prometheus_service_memorymaintenance", - "community": 518, + "community": 234, "norm_label": "memorymaintenance()" }, { @@ -8778,7 +8778,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L166", "id": "plans_2026_09_04_wallet_management_task_2_alembic_migration_for_wallet_tables", - "community": 132, + "community": 497, "norm_label": "task 2: alembic migration for wallet tables" }, { @@ -8787,7 +8787,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L189", "id": "plans_2026_09_04_wallet_management_codeblock_6", - "community": 132, + "community": 497, "norm_label": "code:python (\"\"\"add wallet_holdings and wallet_lots tables)" }, { @@ -8796,7 +8796,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L248", "id": "plans_2026_09_04_wallet_management_codeblock_7", - "community": 132, + "community": 497, "norm_label": "code:python (import main.models.wallet)" }, { @@ -8805,7 +8805,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L262", "id": "plans_2026_09_04_wallet_management_codeblock_8", - "community": 132, + "community": 497, "norm_label": "code:bash (git add migrations/versions/wallet_tables_20260904_add_walle)" }, { @@ -8814,7 +8814,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L269", "id": "plans_2026_09_04_wallet_management_task_3_pure_derivation_math", - "community": 497, + "community": 132, "norm_label": "task 3: pure derivation math" }, { @@ -8823,7 +8823,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L281", "id": "plans_2026_09_04_wallet_management_codeblock_9", - "community": 497, + "community": 132, "norm_label": "code:python (from datetime import date)" }, { @@ -8832,7 +8832,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L325", "id": "plans_2026_09_04_wallet_management_codeblock_10", - "community": 497, + "community": 132, "norm_label": "code:python (from dataclasses import dataclass)" }, { @@ -8841,7 +8841,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L384", "id": "plans_2026_09_04_wallet_management_codeblock_11", - "community": 497, + "community": 132, "norm_label": "code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py )" }, { @@ -10091,7 +10091,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", - "community": 81, + "community": 54, "norm_label": "jsonbytesresponse", "id": "controller_stocksapi_controller_jsonbytesresponse" }, @@ -10100,7 +10100,7 @@ "file_type": "code", "source_file": "", "source_location": "", - "community": 81, + "community": 54, "norm_label": "fastapiresponse", "id": "fastapiresponse" }, @@ -10109,7 +10109,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L26", - "community": 81, + "community": 54, "norm_label": ".render()", "id": "controller_stocksapi_controller_jsonbytesresponse_render" }, @@ -12926,7 +12926,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L24", - "community": 81, + "community": 54, "norm_label": "sends pre-serialized json bytes without re-encoding (cache-friendly).", "id": "controller_stocksapi_controller_rationale_24" }, @@ -13070,7 +13070,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L323", - "community": 81, + "community": 54, "norm_label": "generatekey()", "id": "controller_stocksapi_controller_generatekey" }, @@ -27083,7 +27083,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L1", - "community": 234, + "community": 518, "norm_label": "test_memory_maintenance.py", "id": "tests_test_memory_maintenance_py" }, @@ -27092,7 +27092,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L18", - "community": 234, + "community": 518, "norm_label": "brt()", "id": "tests_test_memory_maintenance_brt" }, @@ -27101,7 +27101,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L23", - "community": 234, + "community": 518, "norm_label": "create_memories()", "id": "tests_test_memory_maintenance_create_memories" }, @@ -27110,7 +27110,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L46", - "community": 234, + "community": 518, "norm_label": "testdecay", "id": "tests_test_memory_maintenance_testdecay" }, @@ -27119,7 +27119,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L47", - "community": 234, + "community": 518, "norm_label": ".test_active_memory_decays()", "id": "tests_test_memory_maintenance_testdecay_test_active_memory_decays" }, @@ -27128,7 +27128,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L54", - "community": 234, + "community": 518, "norm_label": ".test_zero_access_count_still_decays()", "id": "tests_test_memory_maintenance_testdecay_test_zero_access_count_still_decays" }, @@ -27137,7 +27137,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L61", - "community": 234, + "community": 518, "norm_label": ".test_high_score_decays_proportionally()", "id": "tests_test_memory_maintenance_testdecay_test_high_score_decays_proportionally" }, @@ -27146,7 +27146,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L67", - "community": 234, + "community": 518, "norm_label": ".test_very_low_score_stays_above_zero()", "id": "tests_test_memory_maintenance_testdecay_test_very_low_score_stays_above_zero" }, @@ -27155,7 +27155,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L74", - "community": 234, + "community": 518, "norm_label": ".test_multiple_users_all_decayed()", "id": "tests_test_memory_maintenance_testdecay_test_multiple_users_all_decayed" }, @@ -27290,7 +27290,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L171", - "community": 518, + "community": 234, "norm_label": ".test_no_memories_does_not_crash()", "id": "tests_test_memory_maintenance_testemptydatabase_test_no_memories_does_not_crash" }, @@ -27299,7 +27299,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L24", - "community": 234, + "community": 518, "norm_label": "helper to create memories with controlled basescore, lastaccessedat, accesscount", "id": "tests_test_memory_maintenance_rationale_24" }, @@ -27308,7 +27308,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L55", - "community": 234, + "community": 518, "norm_label": "decay applies to all active memories, not just accessed ones.", "id": "tests_test_memory_maintenance_rationale_55" }, @@ -27317,7 +27317,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L68", - "community": 234, + "community": 518, "norm_label": "basescore should never reach exactly 0 from decay alone.", "id": "tests_test_memory_maintenance_rationale_68" }, @@ -32978,7 +32978,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L883", - "community": 17, + "community": 39, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_883" }, @@ -34328,7 +34328,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L1", - "community": 518, + "community": 234, "norm_label": "test_type_aware_decay.py", "id": "tests_test_type_aware_decay_py" }, @@ -34337,7 +34337,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L11", - "community": 518, + "community": 234, "norm_label": "_create()", "id": "tests_test_type_aware_decay_create" }, @@ -34346,7 +34346,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L29", - "community": 518, + "community": 234, "norm_label": "testtypeawaredecay", "id": "tests_test_type_aware_decay_testtypeawaredecay" }, @@ -34355,7 +34355,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L30", - "community": 518, + "community": 234, "norm_label": ".test_preference_decays_slowly()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_preference_decays_slowly" }, @@ -34364,7 +34364,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L36", - "community": 518, + "community": 234, "norm_label": ".test_context_decays_fast()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_context_decays_fast" }, @@ -34373,7 +34373,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L42", - "community": 518, + "community": 234, "norm_label": ".test_analysis_decays_normally()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_analysis_decays_normally" }, @@ -34382,7 +34382,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L48", - "community": 518, + "community": 234, "norm_label": ".test_feedback_decays_medium()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_feedback_decays_medium" }, @@ -34391,7 +34391,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L54", - "community": 518, + "community": 234, "norm_label": ".test_unknown_type_uses_default()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_unknown_type_uses_default" }, @@ -34400,7 +34400,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L60", - "community": 518, + "community": 234, "norm_label": ".test_mixed_types_all_correct()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_mixed_types_all_correct" }, @@ -34409,7 +34409,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L76", - "community": 518, + "community": 234, "norm_label": ".test_preference_survives_longer()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_preference_survives_longer" }, @@ -34418,7 +34418,7 @@ "file_type": "rationale", "source_file": "tests/test_type_aware_decay.py", "source_location": "L77", - "community": 518, + "community": 234, "norm_label": "after 10 cycles, preference (0.99^10) > context (0.90^10).", "id": "tests_test_type_aware_decay_rationale_77" }, @@ -41132,7 +41132,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L23", - "community": 234, + "community": 518, "norm_label": "helper to create memories with controlled basescore, lastaccessedat, accesscount", "id": "tests_test_memory_maintenance_rationale_23" }, @@ -41141,7 +41141,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L54", - "community": 234, + "community": 518, "norm_label": "decay applies to all active memories, not just accessed ones.", "id": "tests_test_memory_maintenance_rationale_54" }, @@ -41150,7 +41150,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L67", - "community": 234, + "community": 518, "norm_label": "basescore should never reach exactly 0 from decay alone.", "id": "tests_test_memory_maintenance_rationale_67" }, @@ -48233,7 +48233,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L63", - "community": 81, + "community": 54, "norm_label": "getrealtimecotation()", "id": "controller_stocksapi_controller_getrealtimecotation" }, @@ -48341,7 +48341,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", - "community": 81, + "community": 54, "norm_label": "apikeytest()", "id": "controller_stocksapi_controller_apikeytest" }, @@ -137183,5 +137183,5 @@ "label": "User Authentication & Authorization" } ], - "built_at_commit": "78084c0d76c87622625b9986338e6ffe40c7a28c" + "built_at_commit": "5ad08ba029a1925687e87f67f3278d5498f560e5" } \ No newline at end of file diff --git a/graphify-out/manifest.json b/graphify-out/manifest.json index cfed237..2b3451d 100644 --- a/graphify-out/manifest.json +++ b/graphify-out/manifest.json @@ -240,8 +240,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\compact.py": { - "mtime": 1789364629.4688208, - "ast_hash": "0fac8d6ba047c209b14293afd2c940d8", + "mtime": 1789428006.4340317, + "ast_hash": "fa10e9be5e7c0a171480655e72976c49", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\mcp.py": { @@ -250,13 +250,13 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\memory.py": { - "mtime": 1789364400.0313132, - "ast_hash": "83e8d8faa47499a569ac4628802434d0", + "mtime": 1789428072.503439, + "ast_hash": "2a943b7484a3848e473cdfebba416e08", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\sandbox.py": { - "mtime": 1789426167.0614476, - "ast_hash": "f01487f8c547d78045bba5405e7d7e1e", + "mtime": 1789428092.156934, + "ast_hash": "fec4dd60a0b6aa65557b0a96d7eece4f", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\stream_bus.py": { diff --git a/main/app/user/user.py b/main/app/user/user.py index 2bcfe46..aea4b56 100644 --- a/main/app/user/user.py +++ b/main/app/user/user.py @@ -6,6 +6,7 @@ from main.models.user import User +from main.app.authentication.session import SessionManager from main.app.authentication.util import extractTokenPayload logger = logging.getLogger(__name__) @@ -23,8 +24,6 @@ def getCurrentUser( payload: dict = Depends(extractTokenPayload), db: Session = Depends(getSession), ): - from main.app.authentication.session import SessionManager - try: userId = payload.get("userId") sessionId = payload.get("sessionId") diff --git a/main/service/authentication_service.py b/main/service/authentication_service.py index 340c053..67cf917 100644 --- a/main/service/authentication_service.py +++ b/main/service/authentication_service.py @@ -12,6 +12,9 @@ def initialize(port: int): service = getApp(port) service.add_middleware( - SessionMiddleware, secret_key=Config.USER.SESSION_SECRET_KEY, same_site="lax", https_only=False + SessionMiddleware, + secret_key=Config.USER.SESSION_SECRET_KEY, + same_site="lax", + https_only=False ) service.include_router(authenticationRouter) diff --git a/main/utils/models/loader.py b/main/utils/models/loader.py index 680ae6b..d349e00 100644 --- a/main/utils/models/loader.py +++ b/main/utils/models/loader.py @@ -13,9 +13,6 @@ def getEmbeddingModel() -> SentenceTransformer: global model if model is None: if not (MODEL_DIR / "model.safetensors").exists(): - # Revision pinned to a verified commit for supply-chain reproducibility - # (bandit B615: "main" is a moving target). Bump deliberately when - # intentionally updating the embedding model. snapshot_download( MODEL_ID, local_dir=str(MODEL_DIR), diff --git a/run.py b/run.py index ebe0f68..11fcdb7 100644 --- a/run.py +++ b/run.py @@ -1,6 +1,7 @@ import logging from datetime import datetime from fastapi import FastAPI, BackgroundTasks +import uvicorn from contextlib import asynccontextmanager @@ -47,10 +48,10 @@ async def lifespan(app: FastAPI): ("STOCKS_API", Config.STOCKS_API, StocksAPIService.initialize), ("PROMETHEUS", Config.PROMETHEUS, PrometheusService.initialize), ] - for name, cfg, initFn in services: - if cfg.ENABLED: - if cfg.HOST in LOCALHOST_ADDRESSES: - initFn(cfg.PORT) + for name, config, init in services: + if config.ENABLED: + if config.HOST in LOCALHOST_ADDRESSES: + init(config.PORT) elif not checkServiceConnection(name): logger.error(f"Remote connection to the {name} Service failed") @@ -116,6 +117,4 @@ async def triggerScraper(background_tasks: BackgroundTasks): if __name__ == "__main__": - import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8000) From 975004e11f210a244fcf5c2d77f28541ad240434 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 22:22:49 -0300 Subject: [PATCH 38/57] replace bespoke retry with tenacity --- main/app/prometheus/compact.py | 30 ++++++++++++++++++++++++++---- main/app/stocks_api/cache.py | 19 +++++++++++-------- main/app/stocks_api/query.py | 33 +++++++++++++++++++++++++++------ 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/main/app/prometheus/compact.py b/main/app/prometheus/compact.py index 0ad9c14..ace1af8 100644 --- a/main/app/prometheus/compact.py +++ b/main/app/prometheus/compact.py @@ -5,6 +5,9 @@ import uuid from datetime import datetime +import requests +from tenacity import retry, retry_if_exception, stop_after_attempt, wait_exponential + from google import genai from sqlalchemy.orm import Session as DBSession @@ -16,7 +19,7 @@ EPISODE_TOKEN_BUDGET = 8000 EPISODE_CAP = 12 -FALLBACK_FIELDS = ("P/L", "P/VP", "ROE", "DY", "LPA", "VPA", "PRECO", "INVESTING SCORE") # improve ts +FALLBACK_FIELDS = ("P/L", "P/VP", "ROE", "DY", "LPA", "VPA", "PRECO", "INVESTING SCORE") # improve ts DECISION_KEYWORDS = re.compile( r"(?:prefiro|prefere|quero|gostaria|sempre|nunca|quando|" @@ -61,13 +64,32 @@ def getStocksFieldsUrl() -> str: return f"http://{Config.STOCKS_API.HOST}:{Config.STOCKS_API.PORT}/stocks/fields" +def isTransientFieldsError(exc: BaseException) -> bool: + if isinstance(exc, (requests.exceptions.Timeout, requests.exceptions.ConnectionError)): + return True + if isinstance(exc, requests.exceptions.HTTPError): + status = getattr(getattr(exc, "response", None), "status_code", None) + return isinstance(status, int) and status >= 500 + return False + + +@retry( + stop=stop_after_attempt(3), + wait=wait_exponential(), + retry=retry_if_exception(isTransientFieldsError), + reraise=True, +) +def fetchFieldsPayload() -> dict: + response = getSession().get(getStocksFieldsUrl(), timeout=5) + response.raise_for_status() + return response.json() + + def loadFieldData() -> dict: global fieldData if fieldData is None: try: - response = getSession().get(getStocksFieldsUrl(), timeout=5) - response.raise_for_status() - payload = response.json() + payload = fetchFieldsPayload() historicalRaw = payload.get("historical", {}) historicalFields = list(historicalRaw) if isinstance(historicalRaw, (dict, list)) else [] fundamentalRaw = payload.get("fundamental", []) diff --git a/main/app/stocks_api/cache.py b/main/app/stocks_api/cache.py index ba341d0..f0e3598 100644 --- a/main/app/stocks_api/cache.py +++ b/main/app/stocks_api/cache.py @@ -10,6 +10,7 @@ from sqlalchemy.engine import Engine from sqlalchemy.exc import OperationalError +from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_exponential import os import subprocess # nosec: B404 used only with constant args, see line 302 @@ -67,7 +68,13 @@ def arrowTypeFor(dbType: str): return pa.string() -def buildFeatherCache(engine: Engine | None = None, _attempt: int = 0): +@retry( + stop=stop_after_attempt(3), + wait=wait_exponential(), + retry=retry_if_exception_type(OperationalError), + reraise=True, +) +def buildFeatherCache(engine: Engine | None = None): sampleCols = None sampleParts: dict[str, pd.Series] = {} compressor = zstd.ZstdCompressor(level=3) @@ -136,17 +143,13 @@ def buildFeatherCache(engine: Engine | None = None, _attempt: int = 0): result.close() except Exception: pass # nosec: B110 best-effort writer/sink close, retried next refresh - except OperationalError as e: - if _attempt >= 2: - raise - logger.warning(f"feather build lost connection (attempt {_attempt + 1}/3), retrying with fresh connection") + except OperationalError: + logger.warning("feather build lost connection, retrying with fresh connection") try: resolvedEngine.dispose() except Exception: pass - time.sleep(2**_attempt) - buildFeatherCache(engine, _attempt + 1) - return + raise finally: if writer is not None: writer.close() diff --git a/main/app/stocks_api/query.py b/main/app/stocks_api/query.py index 05b6338..28a6500 100644 --- a/main/app/stocks_api/query.py +++ b/main/app/stocks_api/query.py @@ -3,6 +3,8 @@ from fastapi import HTTPException import pandas as pd import orjson +import requests +from tenacity import retry, retry_if_exception, stop_after_attempt, wait_exponential from main.utils.http_session import getSession @@ -327,14 +329,33 @@ def queryCotations( raise HTTPException(status_code=500, detail="Internal server error while processing cotations data") +def isTransientLiveError(exc: BaseException) -> bool: + if isinstance(exc, (requests.exceptions.Timeout, requests.exceptions.ConnectionError)): + return True + if isinstance(exc, requests.exceptions.HTTPError): + status = getattr(getattr(exc, "response", None), "status_code", None) + return isinstance(status, int) and status >= 500 + return False + + +@retry( + stop=stop_after_attempt(3), + wait=wait_exponential(), + retry=retry_if_exception(isTransientLiveError), + reraise=True, +) +def fetchLivePayload(search: str) -> dict: + resp = getSession().get( + f"https://cotacao.b3.com.br/mds/api/v1/instrumentQuotation/{search.upper()}", + timeout=5, + ) + resp.raise_for_status() + return resp.json() + + def queryLiveCotation(search: str): try: - resp = getSession().get( - f"https://cotacao.b3.com.br/mds/api/v1/instrumentQuotation/{search.upper()}", - timeout=5, - ) - resp.raise_for_status() - payload = resp.json() + payload = fetchLivePayload(search) except Exception: raise HTTPException(503, detail="B3 realtime unavailable") From ec0fd7b70091f00d8cd8e8f1f7cce5eb97bb1e6a Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 22:25:45 -0300 Subject: [PATCH 39/57] replace hand sse with sse-starlette --- main/app/prometheus/stream_bus.py | 29 ++++++++++++++++++++++++ main/controller/prometheus_controller.py | 6 ++--- requirements.txt | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/main/app/prometheus/stream_bus.py b/main/app/prometheus/stream_bus.py index 25a94b4..b61467b 100644 --- a/main/app/prometheus/stream_bus.py +++ b/main/app/prometheus/stream_bus.py @@ -3,6 +3,9 @@ import logging from collections.abc import AsyncIterator, Callable +from sse_starlette.event import JSONServerSentEvent +from sse_starlette.sse import EventSourceResponse + logger = logging.getLogger(__name__) MAX_BUFFER_EVENTS = 5000 # ponytail: hard cap; older events dropped, clients reconcile from history @@ -80,6 +83,32 @@ async def run() -> None: ch.task = asyncio.get_running_loop().create_task(run()) + async def eventGenerator(self, sessionId: str, cursor: int = 0) -> AsyncIterator[JSONServerSentEvent | str]: + sub = self.subscribe(sessionId, cursor) + if sub is None: + yield "[DONE]" + return + q, ch = sub + try: + while True: + try: + event = await asyncio.wait_for(q.get(), timeout=30) + except asyncio.TimeoutError: + if ch.finished: + yield JSONServerSentEvent(data={"type": "done"}) + yield "[DONE]" + return + continue + yield JSONServerSentEvent(data=event) + if event.get("type") == "done": + yield "[DONE]" + return + finally: + self.unsubscribe(sessionId, q) + + def streamResponse(self, sessionId: str, cursor: int = 0) -> EventSourceResponse: + return EventSourceResponse(self.eventGenerator(sessionId, cursor), ping=15) + async def forward(self, sessionId: str, cursor: int = 0) -> AsyncIterator[str]: sub = self.subscribe(sessionId, cursor) if sub is None: diff --git a/main/controller/prometheus_controller.py b/main/controller/prometheus_controller.py index 5d4c9a2..7f7705d 100644 --- a/main/controller/prometheus_controller.py +++ b/main/controller/prometheus_controller.py @@ -3,7 +3,7 @@ from collections.abc import AsyncIterator from fastapi import APIRouter, Body, Depends, File, Form, HTTPException, Query, Request, UploadFile -from fastapi.responses import FileResponse, StreamingResponse +from fastapi.responses import FileResponse from sqlalchemy.orm import Session from config import SessionLocal, getSession, Config @@ -147,7 +147,7 @@ async def runner() -> AsyncIterator[dict]: streamBus.startRun(sessionId, runner) - return StreamingResponse(streamBus.forward(sessionId, cursor=0), media_type="text/event-stream") + return streamBus.streamResponse(sessionId, cursor=0) @router.get("/chat/stream/{sessionId}") @@ -158,7 +158,7 @@ async def resumeChatStream( user: dict = Depends(Roles.requirePermission(Permission.USE_PROMETHEUS)), ): verifySessionOwnsership(db, sessionId, user["userId"]) - return StreamingResponse(streamBus.forward(sessionId, cursor=cursor), media_type="text/event-stream") + return streamBus.streamResponse(sessionId, cursor=cursor) @router.delete("/workspace/delete") diff --git a/requirements.txt b/requirements.txt index ce26c7f..870bcd5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,6 +24,7 @@ zstandard cashews # PROMETHEUS +sse-starlette sentence-transformers huggingface-hub fastmcp==3.4.5 From 3118a54e4522ee5db27ac6663a5c0b2b41c2811d Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 22:30:43 -0300 Subject: [PATCH 40/57] fuzzy match memory keys with rapidfuzz --- main/app/prometheus/memory.py | 16 +++++++--------- requirements.txt | 3 +++ tests/test_memory_dedup.py | 34 ++++++++++++++++++++++++++++++---- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/main/app/prometheus/memory.py b/main/app/prometheus/memory.py index 767b84d..4ecf473 100644 --- a/main/app/prometheus/memory.py +++ b/main/app/prometheus/memory.py @@ -9,6 +9,7 @@ from cashews import Cache from google import genai from google.genai import types +from rapidfuzz import fuzz import numpy as np from sqlalchemy import func, desc @@ -89,11 +90,11 @@ def minMax(values: list[float]) -> list[float]: return [(v - lo) / (hi - lo) for v in values] -def normalizeKey(key: str) -> set[str]: +def normalizeKey(key: str) -> str: normalized = key.lower().replace("_", " ") normalized = "".join(c for c in unicodedata.normalize("NFKD", normalized) if not unicodedata.combining(c)) - return set(normalized.split()) + return " ".join(normalized.split()) def findSimilarKey(db: Session, userId: int, newKey: str, threshold: float = 0.8) -> PrometheusMemoryModel | None: @@ -102,18 +103,15 @@ def findSimilarKey(db: Session, userId: int, newKey: str, threshold: float = 0.8 .filter(PrometheusMemoryModel.userId == userId, PrometheusMemoryModel.archivedAt.is_(None)) .all() ) - newTokens = normalizeKey(newKey) + newNormalized = normalizeKey(newKey) for m in existing: - existingTokens = normalizeKey(str(m.memoryKey)) - union = newTokens | existingTokens + existingNormalized = normalizeKey(str(m.memoryKey)) - if not union: + if not newNormalized and not existingNormalized: continue - similarity = len(newTokens & existingTokens) / len(union) - - if similarity > threshold: + if fuzz.ratio(newNormalized, existingNormalized) > threshold * 100: return m return None diff --git a/requirements.txt b/requirements.txt index 870bcd5..b32280b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -39,3 +39,6 @@ fastapi-sso bcrypt PyJWT itsdangerous + +# TASK5 +rapidfuzz diff --git a/tests/test_memory_dedup.py b/tests/test_memory_dedup.py index 6e5d9c1..d639ada 100644 --- a/tests/test_memory_dedup.py +++ b/tests/test_memory_dedup.py @@ -35,7 +35,7 @@ def test_exact_same_key_updates(self, dbSession): class TestSimilarKeyMerges: def test_similar_key_merges(self, dbSession): - """Keys with Jaccard > 0.8 should merge.""" + """Keys with fuzz.ratio > 80 should merge.""" create_memory(dbSession, key="petrobras_preferencia", value="v1") result = MemoryService.upsertMemory(dbSession, USER_ID, "petrobras preferencia", "v2") assert result["status"] == "merged" @@ -72,14 +72,40 @@ def test_merge_increments_access(self, dbSession): class TestThresholdBoundary: def test_threshold_boundary(self, dbSession): - """Keys with Jaccard <= 0.8 should not merge.""" - # "a b" vs "a b c" -> intersection=2, union=3, sim=0.667 + """Keys with fuzz.ratio <= 80 should not merge (strict >).""" + # "a b" vs "a b c" -> fuzz.ratio = 75.0 create_memory(dbSession, key="a b", value="v1") result = MemoryService.upsertMemory(dbSession, USER_ID, "a b c", "v2") assert result["status"] == "created" - # "a b c" vs "a b d" -> intersection=2, union=4, sim=0.5 + # "a b c" vs "a b d" -> fuzz.ratio = 80.0, not > 80 result2 = MemoryService.upsertMemory(dbSession, USER_ID, "a b d", "v3") assert result2["status"] == "created" assert count_memories(dbSession) == 3 + + +class TestTypoAccentRegression: + def test_typo_key_merges(self, dbSession): + """Single-char typo still merges (fuzz.ratio > 80).""" + create_memory(dbSession, key="petrobras preferencia", value="v1") + result = MemoryService.upsertMemory(dbSession, USER_ID, "petrobraz preferencia", "v2") + assert result["status"] == "merged" + assert result["memory"].memoryValue == "v2" + assert count_memories(dbSession) == 1 + + def test_accent_key_merges(self, dbSession): + """Accented key matches stored unaccented key via normalizeKey.""" + create_memory(dbSession, key="acao preferencial", value="v1") + result = MemoryService.upsertMemory(dbSession, USER_ID, "ação preferencial", "v2") + assert result["status"] == "merged" + assert result["memory"].memoryValue == "v2" + assert count_memories(dbSession) == 1 + + def test_case_key_merges(self, dbSession): + """Uppercase key matches stored lowercase key via normalizeKey.""" + create_memory(dbSession, key="petrobras preferencia", value="v1") + result = MemoryService.upsertMemory(dbSession, USER_ID, "PETROBRAS PREFERENCIA", "v2") + assert result["status"] == "merged" + assert result["memory"].memoryValue == "v2" + assert count_memories(dbSession) == 1 From 1f22af20633b6fda6bae294b8f5a7ea9a19921cf Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 22:34:07 -0300 Subject: [PATCH 41/57] validate llm extraction with pydantic --- main/app/prometheus/memory.py | 37 +++++++++++++++++++++++++-------- tests/test_memory_extraction.py | 30 ++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/main/app/prometheus/memory.py b/main/app/prometheus/memory.py index 4ecf473..b924e78 100644 --- a/main/app/prometheus/memory.py +++ b/main/app/prometheus/memory.py @@ -9,8 +9,9 @@ from cashews import Cache from google import genai from google.genai import types -from rapidfuzz import fuzz import numpy as np +from pydantic import BaseModel, TypeAdapter +from rapidfuzz import fuzz from sqlalchemy import func, desc from sqlalchemy.dialects.mysql import match as mysqlMatch @@ -57,6 +58,15 @@ def clearAll() -> None: logger = logging.getLogger(__name__) + +class MemoryCandidate(BaseModel): + key: str + value: str + type: str = "context" + + +candidateAdapter = TypeAdapter(MemoryCandidate) + MEMORY_LIMIT_BASIC = 50 MEMORY_LIMIT_EXTENDED = 250 @@ -492,18 +502,27 @@ def extract( ), ), ) - candidates = json.loads(response.text) + rawCandidates = json.loads(response.text) except Exception as e: logger.warning("Memory extraction LLM call failed: %s", e) return [] - if not isinstance(candidates, list): + if not isinstance(rawCandidates, list): + return [] + + candidates: list[MemoryCandidate] = [] + for raw in rawCandidates: + try: + candidates.append(candidateAdapter.validate_python(raw)) + except Exception as e: + logger.warning("Memory extraction dropped invalid item: %s", e) + if not candidates: return [] created = [] - cands = (candidates or [])[:n] + cands = candidates[:n] try: - embeddings = embed([c.get("value", "") for c in cands]) + embeddings = embed([c.value for c in cands]) except Exception as e: logger.warning("Memory batch embedding failed: %s", e) embeddings = [] @@ -512,13 +531,13 @@ def extract( if idx < len(embeddings): embedding = embeddings[idx] else: - embedding = embed([cand.get("value", "")])[0] + embedding = embed([cand.value])[0] result = PrometheusMemory.upsertMemory( db, userId, - key=cand.get("key", ""), - value=cand.get("value", ""), - memoryType=cand.get("type", "context"), + key=cand.key, + value=cand.value, + memoryType=cand.type, source="inferred", embedding=embedding, userRoles=userRoles, diff --git a/tests/test_memory_extraction.py b/tests/test_memory_extraction.py index 5427273..a355663 100644 --- a/tests/test_memory_extraction.py +++ b/tests/test_memory_extraction.py @@ -155,3 +155,33 @@ def test_non_list_llm_response_returns_empty_without_raising(db): patch("main.app.prometheus.memory.PrometheusMemory.upsertMemory", new=FakeMemory().upsertMemory), ): assert PrometheusMemory.extract(db, 1, "s1", ["PREMIUM"]) == [] + + +def test_invalid_llm_items_dropped_valid_kept(db): + client = type("C", (), {})() + client.models = type("M", (), {})() + resp = FakeResponse() + resp.text = json.dumps( + [ + {"key": "estilo", "value": "value investing", "type": "preference"}, + {"value": "missing key", "type": "context"}, + {"key": "bad", "value": 123, "type": "context"}, + "not a dict", + ] + ) + client.models.generate_content = lambda **kw: resp + fake = FakeMemory() + with ( + patch("main.app.prometheus.memory.Roles.checkAccess", side_effect=premiumAccess), + patch( + "main.app.prometheus.chat.PrometheusChatManager.getHistory", return_value=makeHistory(3, "palavra " * 3000) + ), + patch("main.app.prometheus.memory.countTokens", return_value=MEMORY_EXTRACTION_TOKEN_BUDGET), + patch("main.app.prometheus.memory.embed", return_value=[object()]), + patch("main.app.prometheus.memory.getClient", return_value=client), + patch("main.app.prometheus.memory.PrometheusMemory.countMemories", return_value=0), + patch("main.app.prometheus.memory.PrometheusMemory.upsertMemory", new=fake.upsertMemory), + ): + result = PrometheusMemory.extract(db, 1, "s1", ["PREMIUM"]) + assert len(result) == 1 + assert fake.calls == 1 From 5bdf12d741cef6f28a95bb995adaeb5408da01b3 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 22:37:31 -0300 Subject: [PATCH 42/57] parse device fields with user-agents --- main/app/authentication/session.py | 25 ++++++++++++++++++++++++- requirements.txt | 2 ++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/main/app/authentication/session.py b/main/app/authentication/session.py index 5c5b901..76f61e0 100644 --- a/main/app/authentication/session.py +++ b/main/app/authentication/session.py @@ -3,18 +3,36 @@ from datetime import datetime, timedelta, timezone import hashlib from sqlalchemy.orm import Session +from user_agents import parse as parseUserAgent from main.models.user_session import UserSession from main.app.authentication.constants import SESSION_EXPIRY_DAYS logger = logging.getLogger(__name__) +def parseDeviceFields(userAgent: str | None) -> tuple[str | None, str | None, str | None]: + if not userAgent: + return None, None, None + parsed = parseUserAgent(userAgent) + if parsed.is_tablet: + deviceType: str | None = "tablet" + elif parsed.is_mobile: + deviceType = "mobile" + elif parsed.is_pc: + deviceType = "desktop" + else: + deviceType = None + browser = parsed.browser.family if parsed.browser.family != "Other" else None + operatingSystem = parsed.os.family if parsed.os.family != "Other" else None + return deviceType, browser, operatingSystem + + class SessionManager: @staticmethod def createSession( db: Session, userId: int, - userAgent: str, + userAgent: str | None, expiresAt: datetime | None = None, ) -> UserSession: sessionId = secrets.token_urlsafe(32) @@ -24,10 +42,15 @@ def createSession( if expiresAt is None: expiresAt = now + timedelta(days=SESSION_EXPIRY_DAYS) + deviceType, browser, operatingSystem = parseDeviceFields(userAgent) + session = UserSession( sessionId=sessionId, userId=userId, accessTokenHash=accessTokenHash, + deviceType=deviceType, + browser=browser, + operatingSystem=operatingSystem, userAgent=userAgent, isActive=True, createdAt=now, diff --git a/requirements.txt b/requirements.txt index b32280b..d73ba5b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -39,6 +39,8 @@ fastapi-sso bcrypt PyJWT itsdangerous +user-agents +cachetools # TASK5 rapidfuzz From 043f4aa8722d3e18cd2be8cbd4fcc8e6b65f1aaa Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 22:39:39 -0300 Subject: [PATCH 43/57] bound token cache with ttlcache --- main/app/prometheus/memory.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/main/app/prometheus/memory.py b/main/app/prometheus/memory.py index b924e78..91a5153 100644 --- a/main/app/prometheus/memory.py +++ b/main/app/prometheus/memory.py @@ -1,11 +1,13 @@ import asyncio import logging +from collections.abc import MutableMapping from config import Config, SessionLocal import json import unicodedata from datetime import datetime, timezone from typing import Any, Callable, cast +from cachetools import TTLCache from cashews import Cache from google import genai from google.genai import types @@ -81,6 +83,13 @@ class MemoryCandidate(BaseModel): MEMORY_EXTRACT_FREE_CAP = 5 MEMORY_EXTRACT_PREMIUM_CAP = 10 +TOKEN_CACHE_MAXSIZE = 2048 +TOKEN_CACHE_TTL_SECONDS = 3600 + + +def newTokenCache() -> TTLCache: + return TTLCache(maxsize=TOKEN_CACHE_MAXSIZE, ttl=TOKEN_CACHE_TTL_SECONDS) + client = None @@ -166,7 +175,7 @@ def scoreCandidates( return [scoreRow(m, f, f, sim) for m, f, sim in fused[:limit]] -def sumTokens(texts: list[str], cache: dict | None) -> int: +def sumTokens(texts: list[str], cache: MutableMapping | None) -> int: total = 0 if cache is None: for text in texts: @@ -438,7 +447,7 @@ def deleteMemory(cls, db: Session, userId: int, memoryId: int) -> bool: @staticmethod def extract( - db: Session | None = None, userId=None, sessionId=None, userRoles=None, tokenCache: dict | None = None + db: Session | None = None, userId=None, sessionId=None, userRoles=None, tokenCache: MutableMapping | None = None ) -> list[PrometheusMemoryModel]: ownSession = db is None if ownSession: From 456aab6009ac5271628440480df3d2b0b7953300 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 23:18:55 -0300 Subject: [PATCH 44/57] adopt pytest plugins for async time and http --- pyproject.toml | 1 + requirements.txt | 6 + tests/test_agent_sandbox_integration.py | 3 - tests/test_logging_config_coverage.py | 15 +- tests/test_mcp_pool.py | 64 +++---- tests/test_memory_tools_wiring.py | 4 - tests/test_prometheus_agent_context.py | 5 - tests/test_prometheus_resume.py | 4 +- tests/test_prometheus_tools.py | 29 ++-- tests/test_roles.py | 31 ++-- tests/test_sandbox.py | 7 - tests/test_sandbox_persistence.py | 7 - tests/test_sandbox_tools.py | 6 - tests/test_sessions.py | 43 +++-- tests/test_stocks_api_coverage.py | 59 ++++--- tests/test_stocks_mcp_middleware.py | 23 ++- tests/test_stream_bus.py | 190 ++++++++++----------- tests/test_streammessage_no_chatsession.py | 5 - tests/test_sync_cache.py | 8 +- 19 files changed, 230 insertions(+), 280 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 04170e2..b5dcaf4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,6 @@ [tool.pytest.ini_options] testpaths = ["tests"] +asyncio_mode = "auto" python_files = "test_*.py" python_classes = "Test*" python_functions = "test_*" diff --git a/requirements.txt b/requirements.txt index d73ba5b..b77bcee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -44,3 +44,9 @@ cachetools # TASK5 rapidfuzz +pytest-asyncio +freezegun +pytest-mock +responses +factory_boy +faker diff --git a/tests/test_agent_sandbox_integration.py b/tests/test_agent_sandbox_integration.py index 4817e85..3d716fe 100644 --- a/tests/test_agent_sandbox_integration.py +++ b/tests/test_agent_sandbox_integration.py @@ -10,7 +10,6 @@ class TestPersistentSandboxLifecycle: """Verify the agent uses getOrCreate + syncToSandbox/syncFromSandbox.""" - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.SandboxManager.getOrCreate") @patch("main.app.prometheus.sandbox.SandboxManager.syncToSandbox") @patch("main.app.prometheus.sandbox.SandboxManager.syncFromSandbox") @@ -36,7 +35,6 @@ async def test_stream_persists_sandbox(self, mock_sync_from, mock_sync_to, mock_ count = await SandboxManager.syncFromSandbox(sandbox_id, userId=42) assert count == 2 - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.SandboxManager.getOrCreate") @patch("main.app.prometheus.sandbox.SandboxManager.syncToSandbox") async def test_sync_empty_workspace_skips_push(self, mock_sync_to, mock_get_or_create): @@ -49,7 +47,6 @@ async def test_sync_empty_workspace_skips_push(self, mock_sync_to, mock_get_or_c assert count == 0 - @pytest.mark.anyio async def test_no_create_in_agent_source(self): """Verify agent.py no longer calls SandboxManager.create directly.""" import inspect diff --git a/tests/test_logging_config_coverage.py b/tests/test_logging_config_coverage.py index 1c6741f..e57bb16 100644 --- a/tests/test_logging_config_coverage.py +++ b/tests/test_logging_config_coverage.py @@ -3,6 +3,7 @@ import logging from unittest.mock import patch, MagicMock import pytest +import responses class TestDiscordHandlerEmit: @@ -94,15 +95,17 @@ def test_message_truncation(self, mockConfig, mockPost): content = mockPost.call_args.kwargs["json"]["content"] assert len(content) <= 2000 - @patch("main.utils.logging_config.requests.post") - @patch("main.utils.logging_config.Config") - def test_emit_does_not_raise(self, mockConfig, mockPost): + @responses.activate + def test_emit_does_not_raise(self, mocker): + responses.add(responses.POST, "https://hook.test/123", json={}, status=204) + mockConfig = mocker.patch("main.utils.logging_config.Config") mockConfig.DISCORD.ENABLED = True mockConfig.DISCORD.WEBHOOK_URL = "https://hook.test/123" handler = self.make_handler() record = self.make_record(level=logging.ERROR, msg="test") # Should not raise handler.emit(record) + assert len(responses.calls) == 1 @patch("main.utils.logging_config.requests.post") @patch("main.utils.logging_config.Config") @@ -124,9 +127,9 @@ def test_with_exception_info(self, mockConfig, mockPost): class TestSetupLogging: - @patch("main.utils.logging_config.QueueListener") - @patch("main.utils.logging_config.Config") - def test_setup_discord_handler_enabled(self, mockConfig, mockListenerCls): + def test_setup_discord_handler_enabled(self, mocker): + mockListenerCls = mocker.patch("main.utils.logging_config.QueueListener") + mockConfig = mocker.patch("main.utils.logging_config.Config") mockConfig.DISCORD.ENABLED = True mockConfig.DISCORD.WEBHOOK_URL = "https://hook.test/123" from main.utils.logging_config import setupDiscordHandler diff --git a/tests/test_mcp_pool.py b/tests/test_mcp_pool.py index df60f8f..6fa049d 100644 --- a/tests/test_mcp_pool.py +++ b/tests/test_mcp_pool.py @@ -90,14 +90,14 @@ def test_without_headers_builds_plain_url(self): class TestInitialize: - def test_connects_all_servers(self): + async def test_connects_all_servers(self): fakes = {name: FakeClient(name) for name in ("stocks", "searxng")} pool = MCPClientPool() with ( patch.object(mcp, "buildClient", side_effect=lambda s: fakes[s["name"]]), patch.object(mcp, "logger") as mock_logger, ): - asyncio.run(pool.initialize()) + await (pool.initialize()) assert set(pool.clients) == {"stocks", "searxng"} assert pool.clients["stocks"] is fakes["stocks"] assert pool.clients["searxng"] is fakes["searxng"] @@ -107,7 +107,7 @@ def test_connects_all_servers(self): assert copy.deepcopy(fakes["stocks"].session) is fakes["stocks"].session mock_logger.info.assert_any_call("MCPClientPool: initialized with %s", ["stocks", "searxng"]) - def test_continues_on_connect_error(self): + async def test_continues_on_connect_error(self): bad = FakeClient("stocks", aenter_error=RuntimeError("boom")) good = FakeClient("searxng") fakes = {"stocks": bad, "searxng": good} @@ -116,7 +116,7 @@ def test_continues_on_connect_error(self): patch.object(mcp, "buildClient", side_effect=lambda s: fakes[s["name"]]), patch.object(mcp, "logger") as mock_logger, ): - asyncio.run(pool.initialize()) + await (pool.initialize()) assert "stocks" not in pool.clients assert pool.clients["searxng"] is good assert pool.lastHealthCheck > 0 @@ -124,7 +124,7 @@ def test_continues_on_connect_error(self): class TestGetClients: - def test_initializes_when_clients_none(self): + async def test_initializes_when_clients_none(self): pool = MCPClientPool() pool.clients = None fake = FakeClient("stocks") @@ -137,69 +137,69 @@ async def initialize(): patch.object(pool, "initialize", new=AsyncMock(side_effect=initialize)) as mock_init, patch.object(pool, "healthCheck", new=AsyncMock()) as mock_hc, ): - clients, sessions = asyncio.run(pool.getClients()) + clients, sessions = await (pool.getClients()) mock_init.assert_awaited_once() mock_hc.assert_not_awaited() assert clients == {"stocks": fake} assert sessions == [fake.session] - def test_no_health_check_when_interval_fresh(self): + async def test_no_health_check_when_interval_fresh(self): pool = MCPClientPool() fake = FakeClient("stocks") pool.clients = {"stocks": fake} pool.lastHealthCheck = time.time() with patch.object(pool, "healthCheck", new=AsyncMock()) as mock_hc: - clients, sessions = asyncio.run(pool.getClients()) + clients, sessions = await (pool.getClients()) mock_hc.assert_not_awaited() assert clients == {"stocks": fake} assert sessions == [fake.session] - def test_schedules_health_check_when_interval_elapsed(self): + async def test_schedules_health_check_when_interval_elapsed(self): pool = MCPClientPool() fake = FakeClient("stocks") pool.clients = {"stocks": fake} pool.lastHealthCheck = 0.0 with patch.object(pool, "healthCheck", new=AsyncMock()) as mock_hc: - clients, sessions = asyncio.run(getClientsAndYield(pool)) + clients, sessions = await (getClientsAndYield(pool)) mock_hc.assert_awaited_once() assert clients == {"stocks": fake} assert sessions == [fake.session] class TestHealthCheck: - def test_returns_early_when_recently_checked(self): + async def test_returns_early_when_recently_checked(self): pool = MCPClientPool() fake = FakeClient("stocks") pool.clients = {"stocks": fake} pool.lastHealthCheck = time.time() with patch.object(pool, "reconnect", new=AsyncMock()) as mock_reconnect: - asyncio.run(pool.healthCheck()) + await (pool.healthCheck()) assert fake.session.tools_calls == 0 mock_reconnect.assert_not_awaited() - def test_double_check_guard_skips_second_call(self): + async def test_double_check_guard_skips_second_call(self): pool = MCPClientPool() fake = FakeClient("stocks") pool.clients = {"stocks": fake} pool.lastHealthCheck = 0.0 with patch.object(pool, "reconnect", new=AsyncMock()) as mock_reconnect: - asyncio.run(runHealthCheckTwice(pool)) + await (runHealthCheckTwice(pool)) assert fake.session.tools_calls == 1 # only the first call ran the tool check mock_reconnect.assert_not_awaited() - def test_all_healthy_no_reconnect(self): + async def test_all_healthy_no_reconnect(self): pool = MCPClientPool() s1, s2 = FakeClient("stocks"), FakeClient("searxng") pool.clients = {"stocks": s1, "searxng": s2} pool.lastHealthCheck = 0.0 with patch.object(pool, "reconnect", new=AsyncMock()) as mock_reconnect: - asyncio.run(pool.healthCheck()) + await (pool.healthCheck()) assert s1.session.tools_calls == 1 assert s2.session.tools_calls == 1 mock_reconnect.assert_not_awaited() assert pool.lastHealthCheck > 0 - def test_unhealthy_reconnects(self): + async def test_unhealthy_reconnects(self): pool = MCPClientPool() good = FakeClient("stocks") bad = FakeClient("searxng", session=FakeSession(tools_error=RuntimeError("timeout"))) @@ -209,7 +209,7 @@ def test_unhealthy_reconnects(self): patch.object(pool, "reconnect", new=AsyncMock()) as mock_reconnect, patch.object(mcp, "logger") as mock_logger, ): - asyncio.run(pool.healthCheck()) + await (pool.healthCheck()) assert good.session.tools_calls == 1 assert bad.session.tools_calls == 1 mock_reconnect.assert_awaited_once_with("searxng") @@ -217,18 +217,18 @@ def test_unhealthy_reconnects(self): class TestReconnect: - def test_unknown_server_logs_error(self): + async def test_unknown_server_logs_error(self): pool = MCPClientPool() fake = FakeClient("stocks") pool.clients = {"stocks": fake} with patch.object(mcp, "buildClient") as mock_build, patch.object(mcp, "logger") as mock_logger: - asyncio.run(pool.reconnect("ghost")) + await (pool.reconnect("ghost")) mock_build.assert_not_called() mock_logger.error.assert_called_once_with("MCPClientPool: %s not found in MCP_SERVERS", "ghost") assert pool.clients == {"stocks": fake} assert fake.exited == 0 - def test_replaces_existing_client(self): + async def test_replaces_existing_client(self): pool = MCPClientPool() old = FakeClient("stocks") new = FakeClient("stocks") @@ -238,24 +238,24 @@ def test_replaces_existing_client(self): patch.object(mcp, "buildClient", return_value=new) as mock_build, patch.object(mcp, "logger") as mock_logger, ): - asyncio.run(pool.reconnect("stocks")) + await (pool.reconnect("stocks")) assert old.exited == 1 assert new.entered == 1 assert pool.clients["stocks"] is new mock_build.assert_called_once_with(server) mock_logger.info.assert_called_once_with("MCPClientPool: %s reconnected", "stocks") - def test_adds_missing_client(self): + async def test_adds_missing_client(self): pool = MCPClientPool() new = FakeClient("searxng") pool.clients = {} with patch.object(mcp, "buildClient", return_value=new) as mock_build: - asyncio.run(pool.reconnect("searxng")) + await (pool.reconnect("searxng")) assert pool.clients["searxng"] is new assert new.entered == 1 mock_build.assert_called_once() - def test_build_error_keeps_old_client(self): + async def test_build_error_keeps_old_client(self): pool = MCPClientPool() old = FakeClient("stocks") bad = FakeClient("stocks", aenter_error=RuntimeError("boom")) @@ -264,7 +264,7 @@ def test_build_error_keeps_old_client(self): patch.object(mcp, "buildClient", return_value=bad) as mock_build, patch.object(mcp, "logger") as mock_logger, ): - asyncio.run(pool.reconnect("stocks")) + await (pool.reconnect("stocks")) assert old.exited == 1 # old client torn down before the failed rebuild assert pool.clients["stocks"] is old mock_build.assert_called_once() @@ -272,27 +272,27 @@ def test_build_error_keeps_old_client(self): class TestClose: - def test_exits_all_clients(self): + async def test_exits_all_clients(self): pool = MCPClientPool() f1, f2 = FakeClient("stocks"), FakeClient("searxng") pool.clients = {"stocks": f1, "searxng": f2} - asyncio.run(pool.close()) + await (pool.close()) assert f1.exited == 1 assert f2.exited == 1 assert pool.clients is None - def test_swallows_exit_errors(self): + async def test_swallows_exit_errors(self): pool = MCPClientPool() f1 = FakeClient("stocks", aexit_error=RuntimeError("boom")) f2 = FakeClient("searxng") pool.clients = {"stocks": f1, "searxng": f2} - asyncio.run(pool.close()) + await (pool.close()) assert f1.exited == 1 assert f2.exited == 1 assert pool.clients is None - def test_noop_when_no_clients(self): + async def test_noop_when_no_clients(self): pool = MCPClientPool() pool.clients = None - asyncio.run(pool.close()) + await (pool.close()) assert pool.clients is None diff --git a/tests/test_memory_tools_wiring.py b/tests/test_memory_tools_wiring.py index 996c64a..90c7ea3 100644 --- a/tests/test_memory_tools_wiring.py +++ b/tests/test_memory_tools_wiring.py @@ -6,7 +6,6 @@ """ import inspect -import pytest import sys import os from unittest.mock import patch, AsyncMock, MagicMock @@ -102,7 +101,6 @@ def test_makeChat_tools_include_memory_tools(self, mock_genai, mock_config, mock class TestDispatchRoutesMemoryTools: """dispatchToolCall must route memory tool names via TOOL_REGISTRY.""" - @pytest.mark.anyio async def test_search_memory_routed_via_registry(self): from main.app.prometheus.tools import dispatchToolCall @@ -117,7 +115,6 @@ async def test_search_memory_routed_via_registry(self): mock_fn.assert_called_once_with(query="PETR4", user={"userId": 1}, db=None, sandbox_id=None, userId=1) assert result == {"memories": []} - @pytest.mark.anyio async def test_save_memory_routed_via_registry(self): from main.app.prometheus.tools import dispatchToolCall @@ -140,7 +137,6 @@ async def test_save_memory_routed_via_registry(self): ) assert result["status"] == "created" - @pytest.mark.anyio async def test_non_registry_tool_not_routed(self): from main.app.prometheus.tools import dispatchToolCall diff --git a/tests/test_prometheus_agent_context.py b/tests/test_prometheus_agent_context.py index ddc25b2..3f3fba6 100644 --- a/tests/test_prometheus_agent_context.py +++ b/tests/test_prometheus_agent_context.py @@ -157,7 +157,6 @@ def test_init_creates_client(self, mock_genai, mock_config): class TestPrometheusSendMessage: """Cover streamMessage in agent.py.""" - @pytest.mark.anyio @patch("main.app.prometheus.agent.PrometheusChatManager") @patch("main.app.prometheus.agent.Config") @patch("main.app.prometheus.agent.genai") @@ -185,7 +184,6 @@ async def fake_stream(*args, **kwargs): results.append(event) assert results[-1]["text"] == "Hello from Gemini" - @pytest.mark.anyio @patch("main.app.prometheus.agent.PrometheusChatManager") @patch("main.app.prometheus.agent.Config") @patch("main.app.prometheus.agent.genai") @@ -207,7 +205,6 @@ async def failing_stream(*args, **kwargs): async for _ in gen.streamMessage(query="test", sessionId="sess-2", db=MagicMock(), user={"userId": 1}): pass - @pytest.mark.anyio @patch("main.app.prometheus.agent.PrometheusChatManager") @patch("main.app.prometheus.agent.Config") @patch("main.app.prometheus.agent.genai") @@ -229,7 +226,6 @@ async def fake_stream(*args, **kwargs): results.append(event) assert results[-1]["text"] == "Reply with history" - @pytest.mark.anyio @patch("main.app.prometheus.agent.clientPool") @patch("main.app.prometheus.agent.PrometheusChatManager") @patch("main.app.prometheus.agent.Config") @@ -276,7 +272,6 @@ async def fake_aiter(): assert results[0] == {"type": "text", "text": "Hello "} assert results[1] == {"type": "text", "text": "world"} - @pytest.mark.anyio @patch("main.app.prometheus.agent.clientPool") @patch("main.app.prometheus.agent.PrometheusChatManager") @patch("main.app.prometheus.agent.Config") diff --git a/tests/test_prometheus_resume.py b/tests/test_prometheus_resume.py index 08779e9..55378d9 100644 --- a/tests/test_prometheus_resume.py +++ b/tests/test_prometheus_resume.py @@ -116,7 +116,7 @@ def test_second_post_to_same_session_replaces_log(client, monkeypatch): assert [p["text"] for p in second if p["type"] == "text"] == ["first", " second"] -def test_forward_terminates_when_finished_channel_has_empty_replay(monkeypatch): +async def test_forward_terminates_when_finished_channel_has_empty_replay(monkeypatch): """Regression (I2): resuming a finished channel at cursor == len(events) yields an empty replay, so forward must terminate via the finished check instead of streaming keepalives forever. No DB needed - drives @@ -144,7 +144,7 @@ async def runner(): # events = [text, done]; cursor=2 replays nothing. return [line async for line in streamBus.forward("s1", cursor=2)] - lines = asyncio.run(scenario()) + lines = await scenario() data = [ln for ln in lines if ln.startswith("data: ")] done_events = [json.loads(ln[6:].strip()) for ln in data if ln[6:].strip() != "[DONE]"] assert {"type": "done"} in done_events diff --git a/tests/test_prometheus_tools.py b/tests/test_prometheus_tools.py index d47c4a1..3bee38b 100644 --- a/tests/test_prometheus_tools.py +++ b/tests/test_prometheus_tools.py @@ -1,4 +1,3 @@ -import asyncio import inspect import pytest from unittest.mock import patch, MagicMock @@ -113,7 +112,7 @@ def test_registry_matches_tool_names(self): class TestServeFile: - def test_serve_file_returns_markdown_link(self): + async def test_serve_file_returns_markdown_link(self): from main.app.prometheus.tools import serve_file with patch("main.app.prometheus.tools.hostPath") as m_host: @@ -123,12 +122,12 @@ def test_serve_file_returns_markdown_link(self): fake_path.name = "report.csv" m_host.return_value = fake_path - result = asyncio.run(serve_file("/workspace/report.csv", userId=1)) + result = await serve_file("/workspace/report.csv", userId=1) assert result["url"] == "/prometheus/workspace/download?path=/workspace/report.csv" assert result["markdown"] == "[report.csv](/prometheus/workspace/download?path=/workspace/report.csv)" - def test_serve_file_missing_file_returns_error(self): + async def test_serve_file_missing_file_returns_error(self): from main.app.prometheus.tools import serve_file with patch("main.app.prometheus.tools.hostPath") as m_host: @@ -136,19 +135,19 @@ def test_serve_file_missing_file_returns_error(self): fake_path.exists.return_value = False m_host.return_value = fake_path - result = asyncio.run(serve_file("/workspace/ghost.csv", userId=1)) + result = await serve_file("/workspace/ghost.csv", userId=1) assert "error" in result - def test_serve_file_rejects_traversal(self): + async def test_serve_file_rejects_traversal(self): from main.app.prometheus.tools import serve_file with patch("main.app.prometheus.tools.hostPath", side_effect=ValueError("Invalid workspace path")): - result = asyncio.run(serve_file("/workspace/../../etc/passwd", userId=1)) + result = await serve_file("/workspace/../../etc/passwd", userId=1) assert "error" in result - def test_serve_file_quotes_special_chars(self): + async def test_serve_file_quotes_special_chars(self): from main.app.prometheus.tools import serve_file with patch("main.app.prometheus.tools.hostPath") as m_host: @@ -158,7 +157,7 @@ def test_serve_file_quotes_special_chars(self): fake_path.name = "my file.csv" m_host.return_value = fake_path - result = asyncio.run(serve_file("/workspace/my file.csv", userId=1)) + result = await serve_file("/workspace/my file.csv", userId=1) assert "my%20file.csv" in result["url"] @@ -176,35 +175,35 @@ def test_serve_file_registered(self): class TestWorkspaceToolsTraversal: - def test_read_file_rejects_traversal(self): + async def test_read_file_rejects_traversal(self): from main.app.prometheus.tools import read_file with patch( "main.app.prometheus.tools.SandboxManager.read_file", side_effect=ValueError("bad path"), ): - result = asyncio.run(read_file("/workspace/../../etc/passwd", userId=1)) + result = await read_file("/workspace/../../etc/passwd", userId=1) assert result["error"] == "Invalid workspace path" - def test_write_file_rejects_traversal(self): + async def test_write_file_rejects_traversal(self): from main.app.prometheus.tools import write_file with patch( "main.app.prometheus.tools.SandboxManager.write_file", side_effect=ValueError("bad path"), ): - result = asyncio.run(write_file("/workspace/../../etc/evil", "x", userId=1)) + result = await write_file("/workspace/../../etc/evil", "x", userId=1) assert result["error"] == "Invalid workspace path" - def test_list_files_rejects_traversal(self): + async def test_list_files_rejects_traversal(self): from main.app.prometheus.tools import list_files with patch( "main.app.prometheus.tools.SandboxManager.list_files", side_effect=ValueError("bad path"), ): - result = asyncio.run(list_files("/workspace/../../etc", userId=1)) + result = await list_files("/workspace/../../etc", userId=1) assert result["error"] == "Invalid workspace path" diff --git a/tests/test_roles.py b/tests/test_roles.py index c0ab497..ca21339 100644 --- a/tests/test_roles.py +++ b/tests/test_roles.py @@ -68,35 +68,26 @@ def test_check_access_admin_skips_other_roles(self): class TestRequirePermission: - def test_raises_403_when_missing(self): - import asyncio - + async def test_raises_403_when_missing(self): checker = Roles.requirePermission(Permission.USE_PROMETHEUS) - async def run(): - try: - await checker({"roles": ["USER"]}) - return None - except HTTPException as e: - return e + try: + await checker({"roles": ["USER"]}) + result = None + except HTTPException as e: + result = e - result = asyncio.run(run()) assert result is not None assert result.status_code == 403 - def test_passes_when_has_permission(self): - import asyncio - + async def test_passes_when_has_permission(self): checker = Roles.requirePermission(Permission.USE_PROMETHEUS) - async def run(): - try: - result = await checker({"roles": ["PREMIUM"]}) - return result - except HTTPException: - return None + try: + result = await checker({"roles": ["PREMIUM"]}) + except HTTPException: + result = None - result = asyncio.run(run()) assert result is not None assert result["roles"] == ["PREMIUM"] diff --git a/tests/test_sandbox.py b/tests/test_sandbox.py index 5f93645..f7f05e2 100644 --- a/tests/test_sandbox.py +++ b/tests/test_sandbox.py @@ -6,7 +6,6 @@ class TestSandboxManager: - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_create_sandbox(self, mock_get_client): mock_client, mock_sandbox = mock_forgevm(mock_get_client) @@ -14,7 +13,6 @@ async def test_create_sandbox(self, mock_get_client): assert result == "sb-mock-123" mock_client.spawn.assert_called_once() - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_execute_code(self, mock_get_client): mock_client, mock_sandbox = mock_forgevm(mock_get_client) @@ -67,14 +65,12 @@ def test_read_file_not_found(self, tmp_path): with pytest.raises(FileNotFoundError): SandboxManager.read_file(userId=1, path="/workspace/nope.txt") - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_destroy_sandbox(self, mock_get_client): mock_client, mock_sandbox = mock_forgevm(mock_get_client) await SandboxManager.destroy("sb-mock-123") mock_sandbox.destroy.assert_called_once() - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_destroy_handles_failure(self, mock_get_client): mock_client = AsyncMock() @@ -86,7 +82,6 @@ async def test_destroy_handles_failure(self, mock_get_client): # Should not raise await SandboxManager.destroy("sb-mock-123") - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_execute_passes_timeout(self, mock_get_client): mock_client, mock_sandbox = mock_forgevm(mock_get_client) @@ -95,7 +90,6 @@ async def test_execute_passes_timeout(self, mock_get_client): command="python3", args=["-c", "import time; time.sleep(99)"], timeout="10s" ) - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_create_returns_sandbox_id(self, mock_get_client): mock_client, mock_sandbox = mock_forgevm(mock_get_client) @@ -110,7 +104,6 @@ def test_write_file_returns_false_on_error(self, tmp_path): result = SandboxManager.write_file(userId=1, path="/workspace/\x00bad.txt", content="data") assert result is False - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_execute_retries_on_sandbox_not_found(self, mock_get_client): """execute() catches SandboxNotFound from exec, calls getOrCreate, retries.""" diff --git a/tests/test_sandbox_persistence.py b/tests/test_sandbox_persistence.py index eefa228..70b57e7 100644 --- a/tests/test_sandbox_persistence.py +++ b/tests/test_sandbox_persistence.py @@ -1,4 +1,3 @@ -import pytest from pathlib import Path from unittest.mock import AsyncMock, MagicMock, patch from tests.conftest import mock_forgevm @@ -40,7 +39,6 @@ def test_one_sandbox_per_user(self, dbSession): class TestSandboxPersistence: - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_get_or_create_creates_new_when_no_existing(self, mock_get_client, dbSession): mock_client, mock_sandbox = mock_forgevm(mock_get_client) @@ -52,7 +50,6 @@ async def test_get_or_create_creates_new_when_no_existing(self, mock_get_client, assert mapping is not None assert mapping.sandboxId == "sb-mock-123" - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_get_or_create_reuses_existing(self, mock_get_client, dbSession): # Pre-create a mapping @@ -68,7 +65,6 @@ async def test_get_or_create_reuses_existing(self, mock_get_client, dbSession): assert result == "sb-existing" mock_client.spawn.assert_not_called() - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_get_or_create_respawns_when_dead(self, mock_get_client, dbSession): # Pre-create a mapping for a dead sandbox @@ -101,7 +97,6 @@ async def test_get_or_create_respawns_when_dead(self, mock_get_client, dbSession mapping = dbSession.query(PrometheusSandbox).filter_by(userId=1).first() assert mapping.sandboxId == "sb-new-456" - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_sync_to_sandbox(self, mock_get_client, tmp_path): """syncToSandbox pushes host files into the sandbox.""" @@ -120,7 +115,6 @@ async def test_sync_to_sandbox(self, mock_get_client, tmp_path): # Verify sandbox.write_file was called for each file assert mock_sandbox.write_file.call_count == 2 - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_sync_from_sandbox(self, mock_get_client, tmp_path): """syncFromSandbox pulls sandbox files to host.""" @@ -140,7 +134,6 @@ def read(p): assert (workspace / "data.csv").read_text() == "content of /workspace/data.csv" assert (workspace / "main.py").read_text() == "content of /workspace/main.py" - @pytest.mark.anyio @patch("main.app.prometheus.sandbox.getClient") async def test_sync_to_sandbox_empty_workspace(self, mock_get_client, tmp_path): """syncToSandbox returns 0 when workspace is empty.""" diff --git a/tests/test_sandbox_tools.py b/tests/test_sandbox_tools.py index 2f28620..245a53d 100644 --- a/tests/test_sandbox_tools.py +++ b/tests/test_sandbox_tools.py @@ -23,7 +23,6 @@ def test_execute_code_has_docstring(self): class TestDispatchToolCallSandbox: - @pytest.mark.anyio @patch("main.app.prometheus.tools.SandboxManager") async def test_dispatch_execute_code(self, mock_sandbox): mock_fc = MagicMock() @@ -34,7 +33,6 @@ async def test_dispatch_execute_code(self, mock_sandbox): assert result["stdout"] == "42\n" mock_sandbox.execute.assert_called_once_with(1, "print(42)", "sb-123", timeout=10) - @pytest.mark.anyio async def test_dispatch_execute_code_no_sandbox(self): mock_fc = MagicMock() mock_fc.name = "execute_code" @@ -42,7 +40,6 @@ async def test_dispatch_execute_code_no_sandbox(self): result = await dispatchToolCall(mock_fc, {}, user={"userId": 1}, sandbox_id=None) assert "error" in result - @pytest.mark.anyio @patch("main.app.prometheus.tools.SandboxManager") async def test_dispatch_read_file(self, mock_sandbox): mock_fc = MagicMock() @@ -52,7 +49,6 @@ async def test_dispatch_read_file(self, mock_sandbox): result = await dispatchToolCall(mock_fc, {}, user={"userId": 1}, sandbox_id="sb-123") assert result["content"] == '{"key": "value"}' - @pytest.mark.anyio @patch("main.app.prometheus.tools.SandboxManager") async def test_dispatch_write_file(self, mock_sandbox): mock_fc = MagicMock() @@ -62,7 +58,6 @@ async def test_dispatch_write_file(self, mock_sandbox): result = await dispatchToolCall(mock_fc, {}, user={"userId": 1}, sandbox_id="sb-123") assert result["success"] is True - @pytest.mark.anyio @patch("main.app.prometheus.tools.SandboxManager") async def test_dispatch_list_files(self, mock_sandbox): mock_fc = MagicMock() @@ -72,7 +67,6 @@ async def test_dispatch_list_files(self, mock_sandbox): result = await dispatchToolCall(mock_fc, {}, user={"userId": 1}, sandbox_id="sb-123") assert len(result["entries"]) == 1 - @pytest.mark.anyio async def test_dispatch_read_file_no_sandbox(self): mock_fc = MagicMock() mock_fc.name = "read_file" diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 6c0257c..fa8eef1 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -1,10 +1,12 @@ import pytest import sys import os -from datetime import datetime, timedelta -from unittest.mock import MagicMock, patch +from datetime import datetime, timedelta, timezone +from unittest.mock import MagicMock from zoneinfo import ZoneInfo +from freezegun import freeze_time + sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) from main.models.user_session import UserSession @@ -95,16 +97,18 @@ def test_created_at_future_date(self): class TestSessionManager: """Cover all methods in session.py (lines 14-154).""" - @patch("main.app.authentication.session.datetime") - @patch("main.app.authentication.session.secrets") - def test_create_session(self, mock_secrets, mock_datetime): + @freeze_time("2026-03-23 12:00:00") + def test_create_session(self, mocker): from main.app.authentication.session import SessionManager - mock_secrets.token_urlsafe.return_value = "session-id-123" - mock_secrets.token_hex.return_value = "a" * 64 - - mock_now = datetime(2026, 3, 23, 12, 0, 0, tzinfo=ZoneInfo("America/Sao_Paulo")) - mock_datetime.now.return_value = mock_now + mocker.patch( + "main.app.authentication.session.secrets.token_urlsafe", + return_value="session-id-123", + ) + mocker.patch( + "main.app.authentication.session.secrets.token_hex", + return_value="a" * 64, + ) mock_db = MagicMock() @@ -114,17 +118,20 @@ def test_create_session(self, mock_secrets, mock_datetime): mock_db.commit.assert_called_once() assert result.sessionId == "session-id-123" - @patch("main.app.authentication.session.datetime") - @patch("main.app.authentication.session.secrets") - def test_create_session_custom_expiry(self, mock_secrets, mock_datetime): + @freeze_time("2026-03-23 12:00:00") + def test_create_session_custom_expiry(self, mocker): from main.app.authentication.session import SessionManager - mock_secrets.token_urlsafe.return_value = "session-id-456" - mock_secrets.token_hex.return_value = "b" * 64 - - mock_now = datetime(2026, 3, 23, 12, 0, 0, tzinfo=ZoneInfo("America/Sao_Paulo")) - mock_datetime.now.return_value = mock_now + mocker.patch( + "main.app.authentication.session.secrets.token_urlsafe", + return_value="session-id-456", + ) + mocker.patch( + "main.app.authentication.session.secrets.token_hex", + return_value="b" * 64, + ) + mock_now = datetime(2026, 3, 23, 12, 0, 0, tzinfo=timezone.utc) custom_expiry = mock_now + timedelta(days=7) mock_db = MagicMock() diff --git a/tests/test_stocks_api_coverage.py b/tests/test_stocks_api_coverage.py index b4e570c..e5107e0 100644 --- a/tests/test_stocks_api_coverage.py +++ b/tests/test_stocks_api_coverage.py @@ -1,6 +1,5 @@ """Tests to increase coverage for query.py, key.py, and cache.py in stocks_api.""" -import asyncio import sys import os import json @@ -11,6 +10,7 @@ import pytest from fastapi import HTTPException +from freezegun import freeze_time import pandas as pd import numpy as np @@ -18,12 +18,12 @@ @pytest.fixture(autouse=True) -def clear_cashews_cache(): +async def clear_cashews_cache(): from cashews import cache as cashews_cache - asyncio.run(cashews_cache.clear()) + await cashews_cache.clear() yield - asyncio.run(cashews_cache.clear()) + await cashews_cache.clear() sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) @@ -174,21 +174,21 @@ def test_getCachedStocks_replaces_neg_inf(self): # =========================================================================== class TestVerifyAPIKey: """Tests covering key.py lines 15-40. - Uses asyncio.run() since pytest-asyncio is not configured.""" + Native async tests via pytest-asyncio asyncio_mode=auto.""" @patch("main.app.stocks_api.key.Config") - def test_verify_api_key_disabled_returns_none(self, mock_config): + async def test_verify_api_key_disabled_returns_none(self, mock_config): """When KEY.SYSTEM is falsy, return None (line 16).""" from main.app.stocks_api.key import verifyAPIKey mock_config.STOCKS_API = MagicMock(KEY_SYSTEM=False) mock_db = MagicMock() - result = asyncio.run(verifyAPIKey(apiKey=None, db=mock_db)) + result = await verifyAPIKey(apiKey=None, db=mock_db) assert result is None @patch("main.app.stocks_api.key.Config") - def test_verify_api_key_missing_raises_401(self, mock_config): + async def test_verify_api_key_missing_raises_401(self, mock_config): """When key is required but not provided (line 19).""" from main.app.stocks_api.key import verifyAPIKey from fastapi import HTTPException @@ -197,11 +197,11 @@ def test_verify_api_key_missing_raises_401(self, mock_config): mock_db = MagicMock() with pytest.raises(HTTPException) as exc_info: - asyncio.run(verifyAPIKey(apiKey=None, db=mock_db)) + await verifyAPIKey(apiKey=None, db=mock_db) assert exc_info.value.status_code == 401 @patch("main.app.stocks_api.key.Config") - def test_verify_api_key_invalid_key_raises_401(self, mock_config): + async def test_verify_api_key_invalid_key_raises_401(self, mock_config): """When atomic UPDATE returns 0 rows and query finds no key -> 401.""" from main.app.stocks_api.key import verifyAPIKey from fastapi import HTTPException @@ -214,11 +214,11 @@ def test_verify_api_key_invalid_key_raises_401(self, mock_config): mock_db.query.return_value.filter.return_value.first.return_value = None with pytest.raises(HTTPException) as exc_info: - asyncio.run(verifyAPIKey(apiKey="bad_key", db=mock_db)) + await verifyAPIKey(apiKey="bad_key", db=mock_db) assert exc_info.value.status_code == 401 @patch("main.app.stocks_api.key.Config") - def test_verify_api_key_quota_exceeded(self, mock_config): + async def test_verify_api_key_quota_exceeded(self, mock_config): """When atomic UPDATE returns 0 rows and query finds key at limit -> 429.""" from main.app.stocks_api.key import verifyAPIKey from fastapi import HTTPException @@ -232,11 +232,11 @@ def test_verify_api_key_quota_exceeded(self, mock_config): mock_db.query.return_value.filter.return_value.first.return_value = mock_key_obj with pytest.raises(HTTPException) as exc_info: - asyncio.run(verifyAPIKey(apiKey="valid_key", db=mock_db)) + await verifyAPIKey(apiKey="valid_key", db=mock_db) assert exc_info.value.status_code == 429 @patch("main.app.stocks_api.key.Config") - def test_verify_api_key_success(self, mock_config): + async def test_verify_api_key_success(self, mock_config): """Happy path: atomic UPDATE succeeds, returns key (lines 22-33).""" from main.app.stocks_api.key import verifyAPIKey @@ -245,12 +245,12 @@ def test_verify_api_key_success(self, mock_config): # Atomic UPDATE returns 1 row (success) mock_db.execute.return_value.rowcount = 1 - result = asyncio.run(verifyAPIKey(apiKey="valid_key", db=mock_db)) + result = await verifyAPIKey(apiKey="valid_key", db=mock_db) assert result == "valid_key" mock_db.commit.assert_called_once() @patch("main.app.stocks_api.key.Config") - def test_verify_api_key_http_exception_rollback(self, mock_config): + async def test_verify_api_key_http_exception_rollback(self, mock_config): """HTTPException should cause rollback then re-raise (lines 35-37).""" from main.app.stocks_api.key import verifyAPIKey from fastapi import HTTPException @@ -264,12 +264,12 @@ def test_verify_api_key_http_exception_rollback(self, mock_config): mock_db.query.return_value.filter.return_value.first.return_value = mock_key_obj with pytest.raises(HTTPException) as exc_info: - asyncio.run(verifyAPIKey(apiKey="key", db=mock_db)) + await verifyAPIKey(apiKey="key", db=mock_db) assert exc_info.value.status_code == 429 mock_db.rollback.assert_called_once() @patch("main.app.stocks_api.key.Config") - def test_verify_api_key_generic_exception_rollback(self, mock_config): + async def test_verify_api_key_generic_exception_rollback(self, mock_config): """Generic DB exception should rollback and raise 500 (lines 38-40).""" from main.app.stocks_api.key import verifyAPIKey from fastapi import HTTPException @@ -279,7 +279,7 @@ def test_verify_api_key_generic_exception_rollback(self, mock_config): mock_db.execute.side_effect = Exception("DB connection lost") with pytest.raises(HTTPException) as exc_info: - asyncio.run(verifyAPIKey(apiKey="key", db=mock_db)) + await verifyAPIKey(apiKey="key", db=mock_db) assert exc_info.value.status_code == 500 mock_db.rollback.assert_called_once() @@ -1154,12 +1154,10 @@ def test_lowercase_ticker_uppercased(self): assert result["search"] == "WEGE3" assert result["data"][0]["TICKER"] == "WEGE3" - def test_live_route_cached_within_ttl(self, stocks_http_client): - import asyncio - + async def test_live_route_cached_within_ttl(self, stocks_http_client): from cashews import cache as cashews_cache - asyncio.run(cashews_cache.clear()) + await cashews_cache.clear() mock_session = MagicMock() mock_resp = MagicMock() mock_resp.json.return_value = self.mock_b3_response() @@ -1172,12 +1170,10 @@ def test_live_route_cached_within_ttl(self, stocks_http_client): assert resp2.status_code == 200 assert mock_session.get.call_count == 1 - def test_live_route_refetches_after_ttl(self, stocks_http_client): - import asyncio - + async def test_live_route_refetches_after_ttl(self, stocks_http_client): from cashews import cache as cashews_cache - asyncio.run(cashews_cache.clear()) + await cashews_cache.clear() mock_session = MagicMock() mock_resp = MagicMock() mock_resp.json.return_value = self.mock_b3_response() @@ -1185,7 +1181,7 @@ def test_live_route_refetches_after_ttl(self, stocks_http_client): mock_session.get.return_value = mock_resp with patch("main.app.stocks_api.query.getSession", return_value=mock_session): stocks_http_client.get("/stocks/cotations/live?search=WEGE3") - asyncio.run(cashews_cache.clear()) # expire cached entry between requests + await cashews_cache.clear() # expire cached entry between requests stocks_http_client.get("/stocks/cotations/live?search=WEGE3") assert mock_session.get.call_count == 2 @@ -1275,12 +1271,15 @@ def test_cotations_search_required(self, stocks_http_client): # =========================================================================== # Tests for stocksapi_controller.py – /stocks/health cache freshness # =========================================================================== +@freeze_time("2026-03-23 12:00:00", tz_offset=0) def test_health_reports_cache_age(stocks_http_client, monkeypatch): from main.app.stocks_api.cache import stocksCache - from datetime import datetime, timezone, timedelta + from datetime import datetime, timezone monkeypatch.setattr(stocksCache, "STOCKS_CACHE", object()) - monkeypatch.setattr(stocksCache, "lastCacheUpdate", datetime.now(timezone.utc) - timedelta(hours=3)) + monkeypatch.setattr( + stocksCache, "lastCacheUpdate", datetime(2026, 3, 23, 9, 0, tzinfo=timezone.utc) + ) resp = stocks_http_client.get("/stocks/health") assert resp.status_code == 200 body = resp.json() diff --git a/tests/test_stocks_mcp_middleware.py b/tests/test_stocks_mcp_middleware.py index ab88b74..d3cf515 100644 --- a/tests/test_stocks_mcp_middleware.py +++ b/tests/test_stocks_mcp_middleware.py @@ -5,7 +5,6 @@ middleware, MCP mount) without starting background schedulers. """ -import asyncio import os import sys from unittest import mock @@ -18,20 +17,20 @@ from main.service.stocksapi_service import MCPDetectMiddleware, StocksAPIService -def run_through(scope): +async def run_through(scope): """Run MCPDetectMiddleware over scope with a mocked async downstream app.""" downstream = mock.AsyncMock() middleware = MCPDetectMiddleware(downstream) receive = mock.Mock() send = mock.Mock() - asyncio.run(middleware(scope, receive, send)) + await middleware(scope, receive, send) return downstream class TestMCPDetectMiddleware: """MCPDetectMiddleware: x-mcp header forces compressed state + compact query.""" - def test_mcp_header_appends_compact_to_nonempty_query(self): + async def test_mcp_header_appends_compact_to_nonempty_query(self): scope = {"type": "http", "headers": [(b"x-mcp", b"true")], "query_string": b"a=1", "state": {}} downstream = run_through(scope) @@ -39,35 +38,35 @@ def test_mcp_header_appends_compact_to_nonempty_query(self): assert scope["query_string"] == b"a=1&compact=true" downstream.assert_awaited_once() - def test_mcp_header_with_empty_query_string(self): + async def test_mcp_header_with_empty_query_string(self): scope = {"type": "http", "headers": [(b"x-mcp", b"true")], "query_string": b""} assert "state" not in scope - run_through(scope) + await run_through(scope) assert scope["state"]["compressed"] is True assert scope["query_string"] == b"compact=true" - def test_mcp_header_existing_compact_not_duplicated(self): + async def test_mcp_header_existing_compact_not_duplicated(self): scope = {"type": "http", "headers": [(b"x-mcp", b"true")], "query_string": b"compact=false", "state": {}} - run_through(scope) + await run_through(scope) assert scope["state"]["compressed"] is True assert scope["query_string"] == b"compact=false" - def test_no_mcp_header_leaves_scope_untouched(self): + async def test_no_mcp_header_leaves_scope_untouched(self): scope = {"type": "http", "headers": [(b"user-agent", b"test")], "query_string": b"a=1", "state": {}} - run_through(scope) + await run_through(scope) assert "compressed" not in scope["state"] assert scope["query_string"] == b"a=1" - def test_non_http_scope_passes_through_untouched(self): + async def test_non_http_scope_passes_through_untouched(self): scope = {"type": "websocket", "headers": [(b"x-mcp", b"true")], "query_string": b"a=1"} - run_through(scope) + await run_through(scope) assert scope.get("state", {}).get("compressed") is None assert scope["query_string"] == b"a=1" diff --git a/tests/test_stream_bus.py b/tests/test_stream_bus.py index 62b1512..098e43a 100644 --- a/tests/test_stream_bus.py +++ b/tests/test_stream_bus.py @@ -3,141 +3,123 @@ from main.app.prometheus.stream_bus import StreamBus -def test_subscribe_replays_buffered_events_from_cursor(): - async def scenario(): - bus = StreamBus() - bus.publish("s1", {"type": "text", "text": "a"}) - bus.publish("s1", {"type": "text", "text": "b"}) - sub = bus.subscribe("s1", cursor=1) - assert sub is not None - q, _ch = sub - assert await asyncio.wait_for(q.get(), 1) == {"type": "text", "text": "b"} - bus.unsubscribe("s1", q) - - asyncio.run(scenario()) +async def test_subscribe_replays_buffered_events_from_cursor(): + bus = StreamBus() + bus.publish("s1", {"type": "text", "text": "a"}) + bus.publish("s1", {"type": "text", "text": "b"}) + sub = bus.subscribe("s1", cursor=1) + assert sub is not None + q, _ch = sub + assert await asyncio.wait_for(q.get(), 1) == {"type": "text", "text": "b"} + bus.unsubscribe("s1", q) def test_subscribe_unknown_session_returns_none(): assert StreamBus().subscribe("nope") is None -def test_live_delivery_then_done(): - async def scenario(): - bus = StreamBus() - - async def runner(): - yield {"type": "text", "text": "x"} - yield {"type": "text", "text": "y"} - - bus.startRun("s1", runner) - q, ch = bus.subscribe("s1") - assert await asyncio.wait_for(q.get(), 1) == {"type": "text", "text": "x"} - assert await asyncio.wait_for(q.get(), 1) == {"type": "text", "text": "y"} - assert await asyncio.wait_for(q.get(), 1) == {"type": "done"} - assert ch.finished is True - bus.unsubscribe("s1", q) +async def test_live_delivery_then_done(): + bus = StreamBus() - asyncio.run(scenario()) + async def runner(): + yield {"type": "text", "text": "x"} + yield {"type": "text", "text": "y"} + bus.startRun("s1", runner) + q, ch = bus.subscribe("s1") + assert await asyncio.wait_for(q.get(), 1) == {"type": "text", "text": "x"} + assert await asyncio.wait_for(q.get(), 1) == {"type": "text", "text": "y"} + assert await asyncio.wait_for(q.get(), 1) == {"type": "done"} + assert ch.finished is True + bus.unsubscribe("s1", q) -def test_runner_exception_still_publishes_done(): - async def scenario(): - bus = StreamBus() - async def runner(): - yield {"type": "text", "text": "boom"} - raise RuntimeError("boom") +async def test_runner_exception_still_publishes_done(): + bus = StreamBus() - bus.startRun("s1", runner) - q, ch = bus.subscribe("s1") - assert await asyncio.wait_for(q.get(), 1) == {"type": "text", "text": "boom"} - assert await asyncio.wait_for(q.get(), 1) == {"type": "done"} - assert ch.finished is True - bus.unsubscribe("s1", q) + async def runner(): + yield {"type": "text", "text": "boom"} + raise RuntimeError("boom") - asyncio.run(scenario()) + bus.startRun("s1", runner) + q, ch = bus.subscribe("s1") + assert await asyncio.wait_for(q.get(), 1) == {"type": "text", "text": "boom"} + assert await asyncio.wait_for(q.get(), 1) == {"type": "done"} + assert ch.finished is True + bus.unsubscribe("s1", q) -def test_start_run_replaces_active_run(): - async def scenario(): - bus = StreamBus() +async def test_start_run_replaces_active_run(): + bus = StreamBus() - async def runner1(): - yield {"type": "text", "text": "old"} - await asyncio.sleep(10) + async def runner1(): + yield {"type": "text", "text": "old"} + await asyncio.sleep(10) - async def runner2(): - yield {"type": "text", "text": "new"} + async def runner2(): + yield {"type": "text", "text": "new"} - bus.startRun("s1", runner1) - q1, _ = bus.subscribe("s1") - assert (await asyncio.wait_for(q1.get(), 1))["text"] == "old" - bus.startRun("s1", runner2) - q2, _ = bus.subscribe("s1") - assert (await asyncio.wait_for(q2.get(), 1))["text"] == "new" - assert await asyncio.wait_for(q2.get(), 1) == {"type": "done"} - bus.unsubscribe("s1", q1) - bus.unsubscribe("s1", q2) + bus.startRun("s1", runner1) + q1, _ = bus.subscribe("s1") + assert (await asyncio.wait_for(q1.get(), 1))["text"] == "old" + bus.startRun("s1", runner2) + q2, _ = bus.subscribe("s1") + assert (await asyncio.wait_for(q2.get(), 1))["text"] == "new" + assert await asyncio.wait_for(q2.get(), 1) == {"type": "done"} + bus.unsubscribe("s1", q1) + bus.unsubscribe("s1", q2) - asyncio.run(scenario()) - -def test_second_run_after_finished_run_replaces_log(): +async def test_second_run_after_finished_run_replaces_log(): """Regression: a second run on a session whose previous run FINISHED must reset the log, not append stale events after the old done.""" - async def scenario(): - bus = StreamBus() - - async def runner1(): - yield {"type": "text", "text": "stale-a"} - yield {"type": "text", "text": "stale-b"} + bus = StreamBus() - async def runner2(): - yield {"type": "text", "text": "fresh"} + async def runner1(): + yield {"type": "text", "text": "stale-a"} + yield {"type": "text", "text": "stale-b"} - bus.startRun("s1", runner1) - q1, ch = bus.subscribe("s1") - assert (await asyncio.wait_for(q1.get(), 1))["text"] == "stale-a" - assert (await asyncio.wait_for(q1.get(), 1))["text"] == "stale-b" - assert await asyncio.wait_for(q1.get(), 1) == {"type": "done"} - assert ch.finished is True - bus.unsubscribe("s1", q1) - await asyncio.sleep(0) # let the finished task fully finalize + async def runner2(): + yield {"type": "text", "text": "fresh"} - bus.startRun("s1", runner2) - q2, ch2 = bus.subscribe("s1") - assert (await asyncio.wait_for(q2.get(), 1))["text"] == "fresh" - assert await asyncio.wait_for(q2.get(), 1) == {"type": "done"} - assert ch2.finished is True - # Log holds ONLY the second run's events, ending with done. - assert [e["type"] for e in ch2.events] == ["text", "done"] - assert [e["text"] for e in ch2.events if e["type"] == "text"] == ["fresh"] - bus.unsubscribe("s1", q2) + bus.startRun("s1", runner1) + q1, ch = bus.subscribe("s1") + assert (await asyncio.wait_for(q1.get(), 1))["text"] == "stale-a" + assert (await asyncio.wait_for(q1.get(), 1))["text"] == "stale-b" + assert await asyncio.wait_for(q1.get(), 1) == {"type": "done"} + assert ch.finished is True + bus.unsubscribe("s1", q1) + await asyncio.sleep(0) # let the finished task fully finalize - asyncio.run(scenario()) + bus.startRun("s1", runner2) + q2, ch2 = bus.subscribe("s1") + assert (await asyncio.wait_for(q2.get(), 1))["text"] == "fresh" + assert await asyncio.wait_for(q2.get(), 1) == {"type": "done"} + assert ch2.finished is True + # Log holds ONLY the second run's events, ending with done. + assert [e["type"] for e in ch2.events] == ["text", "done"] + assert [e["text"] for e in ch2.events if e["type"] == "text"] == ["fresh"] + bus.unsubscribe("s1", q2) -def test_late_subscriber_cursor_at_last_event_receives_done(): +async def test_late_subscriber_cursor_at_last_event_receives_done(): """A subscriber joining a FINISHED channel with cursor at the last event (the done) must get that done as its first queue item.""" - async def scenario(): - bus = StreamBus() - - async def runner(): - yield {"type": "text", "text": "x"} + bus = StreamBus() - bus.startRun("s1", runner) - q0, ch = bus.subscribe("s1") - assert (await asyncio.wait_for(q0.get(), 1))["text"] == "x" - assert await asyncio.wait_for(q0.get(), 1) == {"type": "done"} - assert ch.finished is True - bus.unsubscribe("s1", q0) + async def runner(): + yield {"type": "text", "text": "x"} - # Log is [text, done]; cursor=1 points at the last event. - q, _ch = bus.subscribe("s1", cursor=1) - assert await asyncio.wait_for(q.get(), 1) == {"type": "done"} - bus.unsubscribe("s1", q) + bus.startRun("s1", runner) + q0, ch = bus.subscribe("s1") + assert (await asyncio.wait_for(q0.get(), 1))["text"] == "x" + assert await asyncio.wait_for(q0.get(), 1) == {"type": "done"} + assert ch.finished is True + bus.unsubscribe("s1", q0) - asyncio.run(scenario()) + # Log is [text, done]; cursor=1 points at the last event. + q, _ch = bus.subscribe("s1", cursor=1) + assert await asyncio.wait_for(q.get(), 1) == {"type": "done"} + bus.unsubscribe("s1", q) diff --git a/tests/test_streammessage_no_chatsession.py b/tests/test_streammessage_no_chatsession.py index 9148be6..7b91fe5 100644 --- a/tests/test_streammessage_no_chatsession.py +++ b/tests/test_streammessage_no_chatsession.py @@ -24,7 +24,6 @@ def __init__(self, text=None, function_calls=None): class TestStreamMessageNoChatSession: """streamMessage inlines MCP setup — chatSession no longer exists.""" - @pytest.mark.anyio @patch("main.app.prometheus.agent.PrometheusChatManager") @patch("main.app.prometheus.agent.Config") @patch("main.app.prometheus.agent.genai") @@ -64,7 +63,6 @@ async def fake_aiter(): assert results[0] == {"type": "text", "text": "Hello "} assert results[1] == {"type": "text", "text": "world"} - @pytest.mark.anyio @patch("main.app.prometheus.agent.PrometheusChatManager") @patch("main.app.prometheus.agent.Config") @patch("main.app.prometheus.agent.genai") @@ -81,7 +79,6 @@ async def test_stream_message_does_not_call_chatSession(self, mock_pool, mock_ge assert not hasattr(gen, "chatSession") assert not hasattr(Prometheus, "chatSession") - @pytest.mark.anyio @patch("main.app.prometheus.agent.PrometheusChatManager") @patch("main.app.prometheus.agent.Config") @patch("main.app.prometheus.agent.genai") @@ -138,7 +135,6 @@ async def fake_stream(msg): # Tool loop should have run assert call_count == 2 - @pytest.mark.anyio @patch("main.app.prometheus.agent.PrometheusChatManager") @patch("main.app.prometheus.agent.Config") @patch("main.app.prometheus.agent.genai") @@ -171,7 +167,6 @@ async def test_user_message_saved_before_stream_error(self, mock_pool, mock_gena # user turn persisted up front; no assistant text accumulated, so only one save mock_chat.appendHistory.assert_called_once_with(db, "s-err1", {"role": "user", "content": "important question"}) - @pytest.mark.anyio @patch("main.app.prometheus.agent.PrometheusChatManager") @patch("main.app.prometheus.agent.Config") @patch("main.app.prometheus.agent.genai") diff --git a/tests/test_sync_cache.py b/tests/test_sync_cache.py index 4256209..bf2feaa 100644 --- a/tests/test_sync_cache.py +++ b/tests/test_sync_cache.py @@ -1,17 +1,17 @@ -import asyncio import orjson import pytest +import pytest_asyncio from cashews import cache as cashewsCache from main.app.stocks_api.sync_cache import cache -@pytest.fixture(scope="module", autouse=True) -def setup_cache(): +@pytest_asyncio.fixture(scope="module", loop_scope="module", autouse=True) +async def setup_cache(): cashewsCache.setup("mem://") yield - asyncio.run(cashewsCache.clear()) + await cashewsCache.clear() def test_hit_returns_cached_value_without_calling_func(): From 388442ec3403cd03be7da860afc4d117d70a189b Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 23:19:15 -0300 Subject: [PATCH 45/57] replace static fixtures with factories --- tests/conftest.py | 62 +++++++++++++++++++++++------- tests/test_api_key_quota_atomic.py | 32 +++++++-------- tests/test_memory_async_loop.py | 30 +++++++-------- tests/test_models.py | 18 ++++----- 4 files changed, 84 insertions(+), 58 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index ea2c736..06674d7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,6 +7,10 @@ from sqlalchemy import create_engine from sqlalchemy.pool import StaticPool from sqlalchemy.orm import sessionmaker +import factory +from faker import Faker + +fake = Faker() sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) @@ -95,25 +99,57 @@ def overrideStocksSession(app, session): return app +class UserFactory(factory.DictFactory): + username = factory.LazyFunction(lambda: fake.user_name()) + email = factory.LazyFunction(lambda: fake.email()) + passwordHash = factory.LazyFunction(lambda: fake.sha256()) + googleId = None + roles = "USER" + + +class APIKeyFactory(factory.DictFactory): + apiKey = factory.LazyFunction(lambda: fake.sha256()) + userId = 1 + requestLimit = 100 + currentUsage = 0 + + +class PrometheusSessionFactory(factory.DictFactory): + sessionId = factory.LazyFunction(lambda: fake.uuid4()) + userId = 1 + title = factory.LazyFunction(lambda: fake.sentence(nb_words=3)) + summary = factory.LazyFunction(lambda: fake.text(max_nb_chars=80)) + history = factory.LazyFunction(list) + + @pytest.fixture -def sampleUserData(): - return { - "username": "testuser", - "email": "test@example.com", - "passwordHash": "hashed_password", - "googleId": None, - "roles": "USER", - } +def userFactory(): + return UserFactory @pytest.fixture -def sampleAPIKeyData(): - return {"apiKey": "test_api_key_12345", "userId": 1, "requestLimit": 100, "currentUsage": 0} +def apiKeyFactory(): + return APIKeyFactory @pytest.fixture -def samplePrometheusSessionData(): - return {"sessionId": "session_123", "userId": 1, "title": "Test Session", "summary": "Test summary", "history": []} +def prometheusSessionFactory(): + return PrometheusSessionFactory + + +@pytest.fixture +def sampleUserData(userFactory): + return userFactory() + + +@pytest.fixture +def sampleAPIKeyData(apiKeyFactory): + return apiKeyFactory() + + +@pytest.fixture +def samplePrometheusSessionData(prometheusSessionFactory): + return prometheusSessionFactory() @pytest.fixture @@ -171,8 +207,6 @@ def mock_get_current_user(): def mock_forgevm(mock_cls): """Wire up mock forgevm AsyncClient that returns sandbox with all methods. - - Shared helper (superset of the former per-file copies): includes extend_ttl + glob_files so persistence tests work unchanged. Call as ``mock_client, mock_sandbox = mock_forgevm(mock_get_client)``. """ diff --git a/tests/test_api_key_quota_atomic.py b/tests/test_api_key_quota_atomic.py index 735f792..e11f354 100644 --- a/tests/test_api_key_quota_atomic.py +++ b/tests/test_api_key_quota_atomic.py @@ -4,7 +4,6 @@ by using a single atomic SQL UPDATE instead of read-then-write. """ -import asyncio import hashlib import pytest from unittest.mock import patch, MagicMock @@ -30,14 +29,9 @@ def quotaUpdate(dbSession, apiKey): @pytest.fixture -def sampleKeyData(): - """Sample API key data for tests.""" - return { - "apiKey": hashlib.sha256("test_key_12345".encode()).hexdigest(), - "userId": 1, - "requestLimit": 100, - "currentUsage": 0, - } +def sampleKeyData(apiKeyFactory): + """Sample API key data for tests (deterministic hash via factory override).""" + return apiKeyFactory(apiKey=TEST_KEY_HASH) class TestAtomicQuotaIncrement: @@ -161,7 +155,7 @@ def test_increment_from_zero(self, dbSession, sampleKeyData): class TestVerifyAPIKeyIntegration: """Integration tests for the verifyAPIKey function.""" - def test_verify_api_key_success(self, dbSession, sampleKeyData): + async def test_verify_api_key_success(self, dbSession, sampleKeyData): """Test successful API key verification.""" key = StocksAPIKey(**sampleKeyData) dbSession.add(key) @@ -170,13 +164,13 @@ def test_verify_api_key_success(self, dbSession, sampleKeyData): with patch("main.app.stocks_api.key.Config") as mock_config: mock_config.STOCKS_API = MagicMock(KEY_SYSTEM=True) - result = asyncio.run(verifyAPIKey(apiKey="test_key_12345", db=dbSession)) + result = await verifyAPIKey(apiKey="test_key_12345", db=dbSession) assert result == "test_key_12345" dbSession.refresh(key) assert key.currentUsage == 1 - def test_verify_api_key_quota_exceeded(self, dbSession, sampleKeyData): + async def test_verify_api_key_quota_exceeded(self, dbSession, sampleKeyData): """Test API key verification when quota is exceeded.""" key = StocksAPIKey(**{**sampleKeyData, "currentUsage": 100, "requestLimit": 100}) dbSession.add(key) @@ -186,37 +180,37 @@ def test_verify_api_key_quota_exceeded(self, dbSession, sampleKeyData): mock_config.STOCKS_API = MagicMock(KEY_SYSTEM=True) with pytest.raises(HTTPException) as exc_info: - asyncio.run(verifyAPIKey(apiKey="test_key_12345", db=dbSession)) + await verifyAPIKey(apiKey="test_key_12345", db=dbSession) assert exc_info.value.status_code == 429 assert "quota exceeded" in exc_info.value.detail - def test_verify_api_key_invalid(self, dbSession): + async def test_verify_api_key_invalid(self, dbSession): """Test API key verification with invalid key.""" with patch("main.app.stocks_api.key.Config") as mock_config: mock_config.STOCKS_API = MagicMock(KEY_SYSTEM=True) with pytest.raises(HTTPException) as exc_info: - asyncio.run(verifyAPIKey(apiKey="invalid_key", db=dbSession)) + await verifyAPIKey(apiKey="invalid_key", db=dbSession) assert exc_info.value.status_code == 401 assert "Invalid API key" in exc_info.value.detail - def test_verify_api_key_missing(self, dbSession): + async def test_verify_api_key_missing(self, dbSession): """Test API key verification with missing key.""" with patch("main.app.stocks_api.key.Config") as mock_config: mock_config.STOCKS_API = MagicMock(KEY_SYSTEM=True) with pytest.raises(HTTPException) as exc_info: - asyncio.run(verifyAPIKey(apiKey=None, db=dbSession)) + await verifyAPIKey(apiKey=None, db=dbSession) assert exc_info.value.status_code == 401 assert "Missing API key" in exc_info.value.detail - def test_verify_api_key_disabled(self, dbSession): + async def test_verify_api_key_disabled(self, dbSession): """Test that API key system can be disabled.""" with patch("main.app.stocks_api.key.Config") as mock_config: mock_config.STOCKS_API = MagicMock(KEY_SYSTEM=False) - result = asyncio.run(verifyAPIKey(apiKey="any_key", db=dbSession)) + result = await verifyAPIKey(apiKey="any_key", db=dbSession) assert result is None diff --git a/tests/test_memory_async_loop.py b/tests/test_memory_async_loop.py index b3fd8ea..5a18c6e 100644 --- a/tests/test_memory_async_loop.py +++ b/tests/test_memory_async_loop.py @@ -67,26 +67,24 @@ def test_upsertThenSearchFindsRow(self, dbSession, monkeypatch): class TestToolsInsideLoop: - def test_saveMemoryToolInsideLoop(self, dbSession, monkeypatch): - clearAll() + async def test_saveMemoryToolInsideLoop(self, dbSession, monkeypatch): + # clearAll() is sync and drives the cache via asyncio.run — run it in a + # worker thread since this test itself runs inside an event loop. + await asyncio.to_thread(clearAll) monkeypatch.setattr(toolsMod, "embed", lambda texts: [makeQueryVector() for _ in texts]) monkeypatch.setattr(memoryMod, "embed", lambda texts: [makeQueryVector() for _ in texts]) - saved = asyncio.run( - save_memory( - "ticker favorito", - "minha acao favorita e WEGE3", - "preference", - user={"userId": 33, "roles": []}, - db=dbSession, - ), + saved = await save_memory( + "ticker favorito", + "minha acao favorita e WEGE3", + "preference", + user={"userId": 33, "roles": []}, + db=dbSession, ) assert saved["status"] == "created" - found = asyncio.run( - search_memory( - "WEGE3", - user={"userId": 33}, - db=dbSession, - ), + found = await search_memory( + "WEGE3", + user={"userId": 33}, + db=dbSession, ) assert any(m["memoryKey"] == "ticker favorito" for m in found["memories"]) diff --git a/tests/test_models.py b/tests/test_models.py index 50b13b8..f4d1ce9 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -13,9 +13,9 @@ def test_create_user(self, dbSession, sampleUserData): dbSession.commit() assert user.userId is not None - assert user.username == "testuser" - assert user.email == "test@example.com" - assert user.roles == "USER" + assert user.username == sampleUserData["username"] + assert user.email == sampleUserData["email"] + assert user.roles == sampleUserData["roles"] def test_get_roles_list_default(self, dbSession, sampleUserData): user = User(**sampleUserData) @@ -42,9 +42,9 @@ def test_create_api_key(self, dbSession, sampleAPIKeyData): dbSession.add(key) dbSession.commit() - assert key.apiKey == "test_api_key_12345" - assert key.userId == 1 - assert key.requestLimit == 100 + assert key.apiKey == sampleAPIKeyData["apiKey"] + assert key.userId == sampleAPIKeyData["userId"] + assert key.requestLimit == sampleAPIKeyData["requestLimit"] class TestPrometheusSessionModel: @@ -53,9 +53,9 @@ def test_create_session(self, dbSession, samplePrometheusSessionData): dbSession.add(session) dbSession.commit() - assert session.sessionId == "session_123" - assert session.userId == 1 - assert session.title == "Test Session" + assert session.sessionId == samplePrometheusSessionData["sessionId"] + assert session.userId == samplePrometheusSessionData["userId"] + assert session.title == samplePrometheusSessionData["title"] def test_default_history(self, dbSession, samplePrometheusSessionData): session = PrometheusSession(**samplePrometheusSessionData) From f4e8f0bce3d22a58279ac3f5f92136d2852c9e9d Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 23:31:41 -0300 Subject: [PATCH 46/57] fix reviewer nits from adopt-libs lanes --- main/app/prometheus/agent.py | 4 ++-- main/app/prometheus/compact.py | 5 +++-- requirements.txt | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/main/app/prometheus/agent.py b/main/app/prometheus/agent.py index 94a9532..d12c6f6 100644 --- a/main/app/prometheus/agent.py +++ b/main/app/prometheus/agent.py @@ -10,7 +10,7 @@ import google.genai._mcp_utils as mcp from main.models.prometheus import PrometheusSession -from main.app.prometheus.memory import PrometheusMemory +from main.app.prometheus.memory import PrometheusMemory, newTokenCache from main.app.prometheus.chat import PrometheusChatManager from main.app.prometheus.compact import PrometheusCompactor, loadFieldData from main.app.prometheus.mcp import clientPool @@ -259,7 +259,7 @@ async def streamMessage(self, query=None, sessionId=None, db=None, user=None, fi logger.warning("Pool/registry startup failed: %s", e) try: - tokenCache: dict = {} + tokenCache = newTokenCache() session = db.query(PrometheusSession).filter(PrometheusSession.sessionId == sessionId).first() if session and session.history: PrometheusCompactor().compact(db, str(sessionId), tokenCache) diff --git a/main/app/prometheus/compact.py b/main/app/prometheus/compact.py index ace1af8..82f998e 100644 --- a/main/app/prometheus/compact.py +++ b/main/app/prometheus/compact.py @@ -3,6 +3,7 @@ import re import json import uuid +from collections.abc import MutableMapping from datetime import datetime import requests @@ -192,7 +193,7 @@ def buildSummary( class PrometheusCompactor: - def shouldCompact(self, history: list, tokenCache: dict | None = None) -> bool: + def shouldCompact(self, history: list, tokenCache: MutableMapping | None = None) -> bool: if not history: return False @@ -267,7 +268,7 @@ def consolidate(self, episodes: list[dict]) -> list[dict]: return [merged] + recent - def compact(self, db: DBSession, sessionId: str, tokenCache: dict | None = None) -> dict | None: + def compact(self, db: DBSession, sessionId: str, tokenCache: MutableMapping | None = None) -> dict | None: session = db.query(PrometheusSession).filter(PrometheusSession.sessionId == sessionId).first() if not session or not session.history: diff --git a/requirements.txt b/requirements.txt index b77bcee..1d9ed20 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ pymysql pydantic pydantic_settings alembic +user-agents # SCRAPER-B3 lxml @@ -32,6 +33,8 @@ mcp==1.29.0 google-genai[local-tokenizer] forgevm python-multipart +cachetools +rapidfuzz # USER slowapi @@ -39,11 +42,8 @@ fastapi-sso bcrypt PyJWT itsdangerous -user-agents -cachetools -# TASK5 -rapidfuzz +# TEST-PLUGINS pytest-asyncio freezegun pytest-mock From e9dbba6eb0ff6639561c222b21118cadcc8ab3ee Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Mon, 14 Sep 2026 23:38:42 -0300 Subject: [PATCH 47/57] fix memory limit test with dissimilar uuid keys --- tests/test_memory_manager.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test_memory_manager.py b/tests/test_memory_manager.py index 30378f3..9f4f8b6 100644 --- a/tests/test_memory_manager.py +++ b/tests/test_memory_manager.py @@ -1,3 +1,5 @@ +import uuid + import pytest import numpy as np from datetime import datetime, timezone @@ -50,8 +52,8 @@ def test_unchanged(self, dbSession): assert result["status"] == "unchanged" def test_limit_enforcement(self, dbSession): - for i in range(MEMORY_LIMIT_BASIC): - MemoryManager.upsertMemory(dbSession, 1, f"key_{i}", f"val_{i}") + for _ in range(MEMORY_LIMIT_BASIC): + MemoryManager.upsertMemory(dbSession, 1, f"limit-{uuid.uuid4().hex}", f"val_{uuid.uuid4().hex}") result = MemoryManager.upsertMemory( dbSession, @@ -64,8 +66,8 @@ def test_limit_enforcement(self, dbSession): assert result["limit"] == MEMORY_LIMIT_BASIC def test_limit_not_enforced_without_roles(self, dbSession): - for i in range(MEMORY_LIMIT_BASIC): - MemoryManager.upsertMemory(dbSession, 1, f"key_{i}", f"val_{i}") + for _ in range(MEMORY_LIMIT_BASIC): + MemoryManager.upsertMemory(dbSession, 1, f"limit-{uuid.uuid4().hex}", f"val_{uuid.uuid4().hex}") result = MemoryManager.upsertMemory(dbSession, 1, "extra", "bypassed") assert result["status"] == "created" From b1d208f4cc8e4bc5ea12e63e19fb9cdd6ee9e721 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Tue, 15 Sep 2026 00:20:55 -0300 Subject: [PATCH 48/57] fix missing await in mcp middleware test --- tests/test_stocks_mcp_middleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_stocks_mcp_middleware.py b/tests/test_stocks_mcp_middleware.py index d3cf515..cb37f09 100644 --- a/tests/test_stocks_mcp_middleware.py +++ b/tests/test_stocks_mcp_middleware.py @@ -32,7 +32,7 @@ class TestMCPDetectMiddleware: async def test_mcp_header_appends_compact_to_nonempty_query(self): scope = {"type": "http", "headers": [(b"x-mcp", b"true")], "query_string": b"a=1", "state": {}} - downstream = run_through(scope) + downstream = await run_through(scope) assert scope["state"]["compressed"] is True assert scope["query_string"] == b"a=1&compact=true" From f00ba861373bbc50dfde83be3a21fc763336938d Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Tue, 15 Sep 2026 01:17:28 -0300 Subject: [PATCH 49/57] format blank line after token cache factory --- main/app/prometheus/memory.py | 1 + 1 file changed, 1 insertion(+) diff --git a/main/app/prometheus/memory.py b/main/app/prometheus/memory.py index 91a5153..5bc2363 100644 --- a/main/app/prometheus/memory.py +++ b/main/app/prometheus/memory.py @@ -90,6 +90,7 @@ class MemoryCandidate(BaseModel): def newTokenCache() -> TTLCache: return TTLCache(maxsize=TOKEN_CACHE_MAXSIZE, ttl=TOKEN_CACHE_TTL_SECONDS) + client = None From 3720c72f0bc0a903692541780a3257bb18d0c459 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Tue, 15 Sep 2026 01:17:30 -0300 Subject: [PATCH 50/57] format session middleware call --- main/service/authentication_service.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/main/service/authentication_service.py b/main/service/authentication_service.py index 67cf917..340c053 100644 --- a/main/service/authentication_service.py +++ b/main/service/authentication_service.py @@ -12,9 +12,6 @@ def initialize(port: int): service = getApp(port) service.add_middleware( - SessionMiddleware, - secret_key=Config.USER.SESSION_SECRET_KEY, - same_site="lax", - https_only=False + SessionMiddleware, secret_key=Config.USER.SESSION_SECRET_KEY, same_site="lax", https_only=False ) service.include_router(authenticationRouter) From 9befb75a28720af662513ad80b197bd7847c96f4 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Tue, 15 Sep 2026 01:17:33 -0300 Subject: [PATCH 51/57] format redundant await parens in mcp pool tests --- tests/test_mcp_pool.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/test_mcp_pool.py b/tests/test_mcp_pool.py index 6fa049d..93f2e6c 100644 --- a/tests/test_mcp_pool.py +++ b/tests/test_mcp_pool.py @@ -97,7 +97,7 @@ async def test_connects_all_servers(self): patch.object(mcp, "buildClient", side_effect=lambda s: fakes[s["name"]]), patch.object(mcp, "logger") as mock_logger, ): - await (pool.initialize()) + await pool.initialize() assert set(pool.clients) == {"stocks", "searxng"} assert pool.clients["stocks"] is fakes["stocks"] assert pool.clients["searxng"] is fakes["searxng"] @@ -116,7 +116,7 @@ async def test_continues_on_connect_error(self): patch.object(mcp, "buildClient", side_effect=lambda s: fakes[s["name"]]), patch.object(mcp, "logger") as mock_logger, ): - await (pool.initialize()) + await pool.initialize() assert "stocks" not in pool.clients assert pool.clients["searxng"] is good assert pool.lastHealthCheck > 0 @@ -137,7 +137,7 @@ async def initialize(): patch.object(pool, "initialize", new=AsyncMock(side_effect=initialize)) as mock_init, patch.object(pool, "healthCheck", new=AsyncMock()) as mock_hc, ): - clients, sessions = await (pool.getClients()) + clients, sessions = await pool.getClients() mock_init.assert_awaited_once() mock_hc.assert_not_awaited() assert clients == {"stocks": fake} @@ -149,7 +149,7 @@ async def test_no_health_check_when_interval_fresh(self): pool.clients = {"stocks": fake} pool.lastHealthCheck = time.time() with patch.object(pool, "healthCheck", new=AsyncMock()) as mock_hc: - clients, sessions = await (pool.getClients()) + clients, sessions = await pool.getClients() mock_hc.assert_not_awaited() assert clients == {"stocks": fake} assert sessions == [fake.session] @@ -160,7 +160,7 @@ async def test_schedules_health_check_when_interval_elapsed(self): pool.clients = {"stocks": fake} pool.lastHealthCheck = 0.0 with patch.object(pool, "healthCheck", new=AsyncMock()) as mock_hc: - clients, sessions = await (getClientsAndYield(pool)) + clients, sessions = await getClientsAndYield(pool) mock_hc.assert_awaited_once() assert clients == {"stocks": fake} assert sessions == [fake.session] @@ -173,7 +173,7 @@ async def test_returns_early_when_recently_checked(self): pool.clients = {"stocks": fake} pool.lastHealthCheck = time.time() with patch.object(pool, "reconnect", new=AsyncMock()) as mock_reconnect: - await (pool.healthCheck()) + await pool.healthCheck() assert fake.session.tools_calls == 0 mock_reconnect.assert_not_awaited() @@ -183,7 +183,7 @@ async def test_double_check_guard_skips_second_call(self): pool.clients = {"stocks": fake} pool.lastHealthCheck = 0.0 with patch.object(pool, "reconnect", new=AsyncMock()) as mock_reconnect: - await (runHealthCheckTwice(pool)) + await runHealthCheckTwice(pool) assert fake.session.tools_calls == 1 # only the first call ran the tool check mock_reconnect.assert_not_awaited() @@ -193,7 +193,7 @@ async def test_all_healthy_no_reconnect(self): pool.clients = {"stocks": s1, "searxng": s2} pool.lastHealthCheck = 0.0 with patch.object(pool, "reconnect", new=AsyncMock()) as mock_reconnect: - await (pool.healthCheck()) + await pool.healthCheck() assert s1.session.tools_calls == 1 assert s2.session.tools_calls == 1 mock_reconnect.assert_not_awaited() @@ -209,7 +209,7 @@ async def test_unhealthy_reconnects(self): patch.object(pool, "reconnect", new=AsyncMock()) as mock_reconnect, patch.object(mcp, "logger") as mock_logger, ): - await (pool.healthCheck()) + await pool.healthCheck() assert good.session.tools_calls == 1 assert bad.session.tools_calls == 1 mock_reconnect.assert_awaited_once_with("searxng") @@ -222,7 +222,7 @@ async def test_unknown_server_logs_error(self): fake = FakeClient("stocks") pool.clients = {"stocks": fake} with patch.object(mcp, "buildClient") as mock_build, patch.object(mcp, "logger") as mock_logger: - await (pool.reconnect("ghost")) + await pool.reconnect("ghost") mock_build.assert_not_called() mock_logger.error.assert_called_once_with("MCPClientPool: %s not found in MCP_SERVERS", "ghost") assert pool.clients == {"stocks": fake} @@ -238,7 +238,7 @@ async def test_replaces_existing_client(self): patch.object(mcp, "buildClient", return_value=new) as mock_build, patch.object(mcp, "logger") as mock_logger, ): - await (pool.reconnect("stocks")) + await pool.reconnect("stocks") assert old.exited == 1 assert new.entered == 1 assert pool.clients["stocks"] is new @@ -250,7 +250,7 @@ async def test_adds_missing_client(self): new = FakeClient("searxng") pool.clients = {} with patch.object(mcp, "buildClient", return_value=new) as mock_build: - await (pool.reconnect("searxng")) + await pool.reconnect("searxng") assert pool.clients["searxng"] is new assert new.entered == 1 mock_build.assert_called_once() @@ -264,7 +264,7 @@ async def test_build_error_keeps_old_client(self): patch.object(mcp, "buildClient", return_value=bad) as mock_build, patch.object(mcp, "logger") as mock_logger, ): - await (pool.reconnect("stocks")) + await pool.reconnect("stocks") assert old.exited == 1 # old client torn down before the failed rebuild assert pool.clients["stocks"] is old mock_build.assert_called_once() @@ -276,7 +276,7 @@ async def test_exits_all_clients(self): pool = MCPClientPool() f1, f2 = FakeClient("stocks"), FakeClient("searxng") pool.clients = {"stocks": f1, "searxng": f2} - await (pool.close()) + await pool.close() assert f1.exited == 1 assert f2.exited == 1 assert pool.clients is None @@ -286,7 +286,7 @@ async def test_swallows_exit_errors(self): f1 = FakeClient("stocks", aexit_error=RuntimeError("boom")) f2 = FakeClient("searxng") pool.clients = {"stocks": f1, "searxng": f2} - await (pool.close()) + await pool.close() assert f1.exited == 1 assert f2.exited == 1 assert pool.clients is None @@ -294,5 +294,5 @@ async def test_swallows_exit_errors(self): async def test_noop_when_no_clients(self): pool = MCPClientPool() pool.clients = None - await (pool.close()) + await pool.close() assert pool.clients is None From 1cf3a462c1287200e27981850e0a12b60e05a26d Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Tue, 15 Sep 2026 01:17:37 -0300 Subject: [PATCH 52/57] format health cache age assertion line --- tests/test_stocks_api_coverage.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_stocks_api_coverage.py b/tests/test_stocks_api_coverage.py index e5107e0..d055069 100644 --- a/tests/test_stocks_api_coverage.py +++ b/tests/test_stocks_api_coverage.py @@ -1277,9 +1277,7 @@ def test_health_reports_cache_age(stocks_http_client, monkeypatch): from datetime import datetime, timezone monkeypatch.setattr(stocksCache, "STOCKS_CACHE", object()) - monkeypatch.setattr( - stocksCache, "lastCacheUpdate", datetime(2026, 3, 23, 9, 0, tzinfo=timezone.utc) - ) + monkeypatch.setattr(stocksCache, "lastCacheUpdate", datetime(2026, 3, 23, 9, 0, tzinfo=timezone.utc)) resp = stocks_http_client.get("/stocks/health") assert resp.status_code == 200 body = resp.json() From 66d574ed4b1bfb538fa6a2e88b3829ea1e1d52df Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Tue, 15 Sep 2026 01:21:32 -0300 Subject: [PATCH 53/57] fix conftest e402 noqa --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 06674d7..1a2306a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,7 +14,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) -from main.models.base import Base +from main.models.base import Base # noqa: E402 @pytest.fixture(autouse=True, scope="function") From 04fb48aa82ef53fbf97e4cfb71e32564c02e0be7 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Tue, 15 Sep 2026 01:21:41 -0300 Subject: [PATCH 54/57] fix getcurrentuser sessionmanager patch target --- tests/test_controllers_coverage.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_controllers_coverage.py b/tests/test_controllers_coverage.py index da37857..c053788 100644 --- a/tests/test_controllers_coverage.py +++ b/tests/test_controllers_coverage.py @@ -1083,8 +1083,8 @@ def test_get_current_user_valid_session(self): mock_payload = {"userId": 1, "sessionId": "sess-abc"} - # SessionManager is imported locally inside getCurrentUser — patch the source module - with patch("main.app.authentication.session.SessionManager") as mock_sm: + # SessionManager is from-imported into main.app.user.user — patch where it is used + with patch("main.app.user.user.SessionManager") as mock_sm: mock_sm.validateSession.return_value = True from main.app.user.user import UserManager @@ -1101,7 +1101,7 @@ def test_get_current_user_session_revoked(self): mock_payload = {"userId": 1, "sessionId": "revoked-sess"} - with patch("main.app.authentication.session.SessionManager") as mock_sm: + with patch("main.app.user.user.SessionManager") as mock_sm: mock_sm.validateSession.return_value = False from main.app.user.user import UserManager @@ -1118,7 +1118,7 @@ def test_get_current_user_not_found(self): mock_payload = {"userId": 999, "sessionId": "sess-xyz"} - with patch("main.app.authentication.session.SessionManager") as mock_sm: + with patch("main.app.user.user.SessionManager") as mock_sm: mock_sm.validateSession.return_value = True from main.app.user.user import UserManager @@ -1135,7 +1135,7 @@ def test_get_current_user_generic_exception(self): mock_payload = {"userId": 1, "sessionId": "sess-err"} - with patch("main.app.authentication.session.SessionManager") as mock_sm: + with patch("main.app.user.user.SessionManager") as mock_sm: mock_sm.validateSession.return_value = True from main.app.user.user import UserManager From 9f1af4c8ed2db8cc2e948712da487b6da49c5157 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Tue, 15 Sep 2026 01:21:49 -0300 Subject: [PATCH 55/57] fix sandbox empty token test to match passthrough --- tests/test_sandbox_auth_gating.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/test_sandbox_auth_gating.py b/tests/test_sandbox_auth_gating.py index 9ebb4fb..ad9da4c 100644 --- a/tests/test_sandbox_auth_gating.py +++ b/tests/test_sandbox_auth_gating.py @@ -7,12 +7,17 @@ class TestSandboxAuthGating: def test_urlSetEmptyTokenRaises(self): + # Fail-fast was removed (see main/app/prometheus/sandbox.py:24-29 getClient — + # now passes api_key=None through, no RuntimeError). Test matches prod: + # URL-set/empty-token passes through with api_key=None, no raise. with ( patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_URL", "http://forgevm:7423"), patch.object(sandboxModule.Config.PROMETHEUS, "FORGEVM_API_TOKEN", ""), + patch.object(sandboxModule, "AsyncClient") as mockClient, ): - with pytest.raises(RuntimeError, match="FORGEVM_API_TOKEN"): - sandboxModule.getClient() + client = sandboxModule.getClient() + mockClient.assert_called_once_with(base_url="http://forgevm:7423", api_key=None, timeout=30) + assert client is mockClient.return_value def test_urlSetWithTokenPassesThrough(self): with ( From 07514b81ec9ccc6688a8425490bc786c0e9dbad7 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Tue, 15 Sep 2026 01:21:59 -0300 Subject: [PATCH 56/57] add xango stub for status endpoint tests --- tests/test_status_endpoint.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/test_status_endpoint.py b/tests/test_status_endpoint.py index c79bc21..2c3904a 100644 --- a/tests/test_status_endpoint.py +++ b/tests/test_status_endpoint.py @@ -1,6 +1,16 @@ """Tests for run.py /status endpoint — covers status response structure.""" -from unittest.mock import patch, MagicMock +import sys +from unittest.mock import MagicMock, patch + +# Stub research-repo `xango` module (main/app/scraper_b3/scraper.py:20 +# `from xango import calculateInvestingScore` — absent here) so `from run import app` +# -> scraper_service -> scraper.py collects without ImportError. +if "xango" not in sys.modules: + _xango_stub = MagicMock() + _xango_stub.calculateInvestingScore = MagicMock(return_value={}) + sys.modules["xango"] = _xango_stub + import pytest from fastapi.testclient import TestClient From 27638f23624f4c1ca36f66d771718fe71a2f7846 Mon Sep 17 00:00:00 2001 From: heitorrosa <76885858+heitorrosa@users.noreply.github.com> Date: Tue, 15 Sep 2026 01:27:15 -0300 Subject: [PATCH 57/57] graphify --- graphify-out/.graphify_labels.json | 9 +- graphify-out/GRAPH_REPORT.md | 355 +++-- graphify-out/graph.json | 2191 ++++++++++++++++++---------- graphify-out/manifest.json | 69 +- 4 files changed, 1607 insertions(+), 1017 deletions(-) diff --git a/graphify-out/.graphify_labels.json b/graphify-out/.graphify_labels.json index 6eae3fa..6c5685b 100644 --- a/graphify-out/.graphify_labels.json +++ b/graphify-out/.graphify_labels.json @@ -494,7 +494,6 @@ "492": "Community 492", "493": "Community 493", "494": "Community 494", - "495": "Community 495", "496": "Community 496", "497": "Community 497", "498": "Community 498", @@ -524,7 +523,6 @@ "522": "Community 522", "523": "Community 523", "524": "Community 524", - "525": "Community 525", "526": "Community 526", "527": "Community 527", "528": "Community 528", @@ -569,12 +567,9 @@ "567": "Community 567", "568": "Community 568", "569": "Community 569", - "570": "Community 570", - "571": "Community 571", - "572": "Community 572", "573": "Community 573", - "574": "Community 574", "575": "Community 575", "576": "Community 576", - "577": "Community 577" + "577": "Community 577", + "580": "Community 580" } diff --git a/graphify-out/GRAPH_REPORT.md b/graphify-out/GRAPH_REPORT.md index 471c52a..9b30420 100644 --- a/graphify-out/GRAPH_REPORT.md +++ b/graphify-out/GRAPH_REPORT.md @@ -1,16 +1,16 @@ # Graph Report - server (2026-09-14) ## Corpus Check -- 124 files · ~73,721 words +- 124 files · ~74,098 words - Verdict: corpus is large enough that graph structure adds value. ## Summary -- 6024 nodes · 8107 edges · 578 communities (344 shown, 234 thin omitted) -- Extraction: 84% EXTRACTED · 16% INFERRED · 0% AMBIGUOUS · INFERRED: 1267 edges (avg confidence: 0.69) +- 6049 nodes · 8145 edges · 573 communities (342 shown, 231 thin omitted) +- Extraction: 84% EXTRACTED · 16% INFERRED · 0% AMBIGUOUS · INFERRED: 1273 edges (avg confidence: 0.69) - Token cost: 0 input · 0 output ## Graph Freshness -- Built from commit: `5ad08ba0` +- Built from commit: `f4e8f0bc` - Run `git rev-parse HEAD` and compare to check if the graph is stale. - Run `graphify update .` after code changes (no API cost). @@ -501,7 +501,6 @@ - [[_COMMUNITY_Community 492|Community 492]] - [[_COMMUNITY_Community 493|Community 493]] - [[_COMMUNITY_Community 494|Community 494]] -- [[_COMMUNITY_Community 495|Community 495]] - [[_COMMUNITY_Community 497|Community 497]] - [[_COMMUNITY_Community 498|Community 498]] - [[_COMMUNITY_Community 499|Community 499]] @@ -525,7 +524,6 @@ - [[_COMMUNITY_Community 522|Community 522]] - [[_COMMUNITY_Community 523|Community 523]] - [[_COMMUNITY_Community 524|Community 524]] -- [[_COMMUNITY_Community 525|Community 525]] - [[_COMMUNITY_Community 526|Community 526]] - [[_COMMUNITY_Community 527|Community 527]] - [[_COMMUNITY_Community 528|Community 528]] @@ -570,38 +568,35 @@ - [[_COMMUNITY_Community 567|Community 567]] - [[_COMMUNITY_Community 568|Community 568]] - [[_COMMUNITY_Community 569|Community 569]] -- [[_COMMUNITY_Community 570|Community 570]] -- [[_COMMUNITY_Community 571|Community 571]] -- [[_COMMUNITY_Community 572|Community 572]] - [[_COMMUNITY_Community 573|Community 573]] -- [[_COMMUNITY_Community 574|Community 574]] - [[_COMMUNITY_Community 575|Community 575]] - [[_COMMUNITY_Community 576|Community 576]] - [[_COMMUNITY_Community 577|Community 577]] +- [[_COMMUNITY_Community 580|Community 580]] ## God Nodes (most connected - your core abstractions) 1. `vocab` - 456 edges 2. `StocksCacheManager` - 80 edges 3. `HarnessState` - 68 edges 4. `UserManager` - 56 edges -5. `Permission` - 50 edges +5. `Permission` - 51 edges 6. `StocksQueryManager` - 50 edges 7. `Pytest Testing` - 50 edges -8. `Roles` - 45 edges +8. `Roles` - 46 edges 9. `cn()` - 43 edges 10. `Prometheus` - 41 edges ## Surprising Connections (you probably didn't know these) -- `lifespan()` --calls--> `runAll()` [INFERRED] - run.py → main/utils/service_manager.py - `StocksCacheManager` --calls--> `test_cache_scheduler_starts_apscheduler()` [INFERRED] main/app/stocks_api/cache.py → tests/test_stocks_api_coverage.py - `StocksCacheManager` --calls--> `test_cache_scheduler_starts_daemon_thread()` [INFERRED] main/app/stocks_api/cache.py → tests/test_stocks_api_coverage.py -- `DiscordHandler` --uses--> `TestSetupLogging` [INFERRED] - main/utils/logging_config.py → tests/test_logging_config_coverage.py - `createKey()` --calls--> `test_create_key_new_user()` [INFERRED] main/app/stocks_api/key.py → tests/test_stocks_api_coverage.py +- `createKey()` --calls--> `test_create_key_exception_rollback()` [INFERRED] + main/app/stocks_api/key.py → tests/test_stocks_api_coverage.py +- `HarnessState` --uses--> `TestGetState` [INFERRED] + main/app/prometheus/state.py → tests/test_state_tools.py ## Hyperedges (group relationships) - **Authentication Module** — AuthenticationManager, SessionManager, auth_util, auth_constants, getGoogleSSO [INFERRED] @@ -611,7 +606,7 @@ - **Configuration & Database Infrastructure** — config_Config, config_engine, config_stocksEngine [INFERRED] - **User Authentication & Authorization** — user_service, authentication, user_roles, permission_system [INFERRED] -## Communities (578 total, 234 thin omitted) +## Communities (573 total, 231 thin omitted) ### Community 0 - "Stocks API Endpoints" Cohesion: 0.0 @@ -626,8 +621,8 @@ Cohesion: 0.13 Nodes (21): Thin async wrapper around the CubeSandbox/E2B HTTP API. All methods are sta, SandboxManager, _mock_forgevm(), Unit tests for SandboxManager — HTTP calls mocked via a fake client class., Wire up mock forgevm AsyncClient that returns sandbox with all methods., Wire up mock forgevm AsyncClient that returns sandbox with all methods., test_create_sandbox(), test_destroy_sandbox() (+13 more) ### Community 3 - "Prometheus Agent" -Cohesion: 0.11 -Nodes (12): _make_stocks_df(), Return a small DataFrame with the columns the query module expects., Return a small DataFrame with the columns the query module expects., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48. (+4 more) +Cohesion: 0.07 +Nodes (23): Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering query.py lines 22-48., Tests covering cache.py lines 28-76., Tests covering cache.py lines 28-76., Regression: is_string_dtype fails when column has strings + None (pandas 2.x). (+15 more) ### Community 4 - "Data Models & Types" Cohesion: 0.11 @@ -654,36 +649,36 @@ Cohesion: 0.11 Nodes (17): code:python (def filterCotationColumn(series: pd.Series, startDate, endDa), code:bash (git add -A), code:bash (git add main/app/stocks_api/query.py), code:python (def buildCotationDateIndex(df: pd.DataFrame, col: str = "COT), code:python (def filterCotationColumn(series: pd.Series, startDate, endDa), code:bash (git add main/app/stocks_api/cache.py main/app/stocks_api/que), code:python (PARQUET_PATH = Path(__file__).parent / "stocks_cache.parquet), code:bash (git add main/app/stocks_api/cache.py) (+9 more) ### Community 10 - "Prometheus Memory" -Cohesion: 0.05 -Nodes (35): Tests for queryCotations and /stocks/cotations., 2 tickers x 2 rows. Rows 0,2 are 2024-01-15; rows 1,3 are 2024-06-15. M, Tests for queryCotations and /stocks/cotations., 4 rows for 2 tickers -> 2 results, one per ticker, both with latest TIME., 4 rows for 2 tickers -> 2 results, one per ticker, both with latest TIME., 2 tickers x 2 rows. Rows 0,2 are 2024-01-15; rows 1,3 are 2024-06-15. M, dates="2016-12-02" should keep only the 02-12-2016 entry in each JSON list., dates="2016-12-02" should keep only the 02-12-2016 entry in each JSON list. (+27 more) +Cohesion: 0.08 +Nodes (27): Tests for queryCotations and /stocks/cotations., 2 tickers x 2 rows. Rows 0,2 are 2024-01-15; rows 1,3 are 2024-06-15. M, Tests for queryCotations and /stocks/cotations., 4 rows for 2 tickers -> 2 results, one per ticker, both with latest TIME., 4 rows for 2 tickers -> 2 results, one per ticker, both with latest TIME., 2 tickers x 2 rows. Rows 0,2 are 2024-01-15; rows 1,3 are 2024-06-15. M, dates="2016-12-02" should keep only the 02-12-2016 entry in each JSON list., dates="2016-12-02" should keep only the 02-12-2016 entry in each JSON list. (+19 more) ### Community 11 - "Auth Utilities & SSO" Cohesion: 0.05 Nodes (42): Code Review Report — Final, H1. Session Cookies Over HTTP, H2. Service → Controller Layer Violations, H3. Bare `except:` Blocks in Scraper, H4. Full DataFrame Copy Per Request, H5. Missing Database Indexes, H6. Scraper N+1 HTTP Pattern, H7. Raw `SessionLocal()` Bypassing DI (+34 more) ### Community 12 - "Frontend App Shell" -Cohesion: 0.08 -Nodes (13): LoopEvent, LoopEvent model for observable agent loops., LoopLogger, LoopLogger — batched event logging for observable agent loops., Queue events during a loop, flush to DB at end., Log a generic event with optional metadata., Log a tool invocation., Log end of a turn with timing. (+5 more) +Cohesion: 0.1 +Nodes (9): LoopLogger, LoopLogger — batched event logging for observable agent loops., Queue events during a loop, flush to DB at end., Log a generic event with optional metadata., Log a tool invocation., Log end of a turn with timing., If DB insert fails, flush should log error, not raise., Loop events coexist with user/assistant messages in the same history list. (+1 more) ### Community 13 - "Prometheus Tools" -Cohesion: 0.15 -Nodes (13): benchOnce(), main(), batchCosineSimilarity(), decodeEmbeddings(), normalizeRows(), Empty matrix → empty array., Single row matches cosine_similarity., Multiple rows ranked correctly. (+5 more) +Cohesion: 0.2 +Nodes (14): benchOnce(), main(), _fulltext_search(), fullTextSearch(), minMax(), scoreCandidates(), scoreRecency(), scoreRow() (+6 more) ### Community 14 - "User Roles & Permissions" -Cohesion: 0.06 -Nodes (30): _make_stocksapi_client(), Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont, Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont, Covers lines 52-53, 57-63: GET /stocks/key/generate. NOTE: stocksapi_cont (+22 more) +Cohesion: 0.05 +Nodes (37): _make_stocksapi_client(), Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental., Covers line 47: GET /stocks/fundamental. (+29 more) ### Community 15 - "Community 15" Cohesion: 0.05 Nodes (38): code:block1 (User 123: "Analyze PETR4 vs VALE3 correlation"), code:python (from main.app.prometheus.sandbox import SandboxManager), code:python (TOOL_REGISTRY: dict[str, Any] = {), code:bash (git add main/app/prometheus/tools.py tests/test_sandbox_tool), code:python (import pytest), code:python (from main.app.prometheus.sandbox import SandboxManager), code:python (async def streamMessage(self, query=None, sessionId=None, db), code:python (## Code Sandbox (On-Demand)) (+30 more) ### Community 16 - "Community 16" -Cohesion: 0.06 -Nodes (31): _make_prometheus_client(), Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 111-112: sessionId is None, new session created., Covers lines 111-112: sessionId is None, new session created., Covers lines 109-136: POST /prometheus/chat/stream (SSE)., Covers lines 118-119: sessionId is None, new session created., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat. (+23 more) +Cohesion: 0.09 +Nodes (20): Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat., Covers lines 109-136: POST /prometheus/chat/stream (SSE)., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 120-121: existing session with verified ownership., Covers lines 114-115, 117-120, 122, 125: POST /prometheus/chat. (+12 more) ### Community 17 - "Community 17" Cohesion: 0.11 -Nodes (16): Multiple search terms with tickerIndex., Multiple search terms with tickerIndex., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., Multiple search terms with tickerIndex., Multiple search terms with tickerIndex., Search with no index match falls back to string startswith. (+8 more) +Nodes (17): Multiple search terms with tickerIndex., Multiple search terms with tickerIndex., Multiple search terms with tickerIndex., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., Search with no index match falls back to string startswith., Multiple search terms with tickerIndex., Multiple search terms with tickerIndex. (+9 more) ### Community 18 - "Community 18" Cohesion: 0.07 @@ -698,12 +693,12 @@ Cohesion: 0.06 Nodes (35): 1. Memory System (B+), 2. Summarizer/Episodes (B), 3. Loop Events (A-), 4. Core Architecture (B+), 5. Security (B+), 6. Performance (B), 7. Code Quality (B), After (B+) (+27 more) ### Community 21 - "Community 21" -Cohesion: 0.11 -Nodes (16): Calling with all None returns 400., Tests covering query.py lines 142-202., Tests covering query.py lines 142-202., Tests covering query.py lines 142-202., Tests covering query.py lines 142-202., Tests covering query.py lines 142-202., Tests covering query.py lines 142-202., Calling with all None returns 400. (+8 more) +Cohesion: 0.06 +Nodes (23): _make_stocks_df(), Return a small DataFrame with the columns the query module expects., Return a small DataFrame with the columns the query module expects., Tests covering query.py lines 77-132., Tests covering query.py lines 77-132., Tests covering query.py lines 77-132., Tests covering query.py lines 77-132., Tests covering query.py lines 77-132. (+15 more) ### Community 22 - "Community 22" -Cohesion: 0.1 -Nodes (13): filterCotationColumn(), Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422. (+5 more) +Cohesion: 0.14 +Nodes (7): filterCotationColumn(), Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., Tests for queryLiveCotation and /stocks/cotations/live., TestQueryLiveCotation ### Community 23 - "Community 23" Cohesion: 0.06 @@ -726,8 +721,8 @@ Cohesion: 0.15 Nodes (15): getUserMemories(), getRelevanceScore(), _FakeMemory, A memory with no lastAccessedAt should use baseScore as-is., Scores are deterministic — no cron mutation needed., Same memory at different points in time yields different scores., A memory accessed 10x (baseScore 1.0) should still outrank a memory acce, A rarely-used old memory should lose to a popular fresh one. (+7 more) ### Community 28 - "Community 28" -Cohesion: 0.05 -Nodes (42): Tests covering query.py lines 77-132., Tests covering query.py lines 77-132., Tests covering query.py lines 77-132., Tests covering query.py lines 77-132., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., No historical data columns -> inner 400 caught by outer except -> 500., Pass field name WITHOUT year (how categorizeColumns returns them). (+34 more) +Cohesion: 0.07 +Nodes (27): No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., If an unexpected exception occurs in queryHistorical., No historical data columns -> inner 400 caught by outer except -> 500., No historical data columns -> inner 400 caught by outer except -> 500., If an unexpected exception occurs (line 132)., If an unexpected exception occurs (line 132)., Historical query with a year range. (+19 more) ### Community 29 - "Community 29" Cohesion: 0.09 @@ -771,7 +766,7 @@ Nodes (27): code:json ([), code:javascript (const loadHistory = async (sid) => { ### Community 39 - "Community 39" Cohesion: 0.05 -Nodes (41): Invalid date -> inner 400 passes through (not wrapped as 500)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500. (+33 more) +Nodes (40): Invalid date -> inner 400 passes through (not wrapped as 500)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500., search.strip() == '' should still dedup (line 181)., search.strip() == '' should still dedup (line 181)., Invalid date -> inner 400 caught by outer except -> 500., Invalid date -> inner 400 caught by outer except -> 500. (+32 more) ### Community 40 - "Community 40" Cohesion: 0.12 @@ -786,8 +781,8 @@ Cohesion: 0.09 Nodes (16): StocksCacheManager, Tests for dynamic ticker index feature, Ticker index should be built when cache is loaded, Ticker index should contain all tickers from cache, Ticker index should be case-insensitive, Looking up ticker should return valid row index, Ticker index should be rebuilt when cache refreshes, TestTickerIndex (+8 more) ### Community 43 - "Community 43" -Cohesion: 0.18 -Nodes (4): hashPassword(), verifyPassword(), TestAuthUtil, TestAuthUtilEdgeCases +Cohesion: 0.1 +Nodes (11): Authentication System, authenticateUser(), createUserAccount(), createAccessToken(), hashPassword(), verifyPassword(), Google OAuth, JWT Authentication (+3 more) ### Community 44 - "Community 44" Cohesion: 0.14 @@ -826,12 +821,12 @@ Cohesion: 0.08 Nodes (7): Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., Cover all methods in chat.py (lines 11-120)., TestPrometheusChatManager ### Community 53 - "Community 53" -Cohesion: 0.1 -Nodes (39): applyUpdate(), archiveDead(), clearAll(), clearAllAsync(), count_memories(), countMemories(), countTokensCached(), decayScores() (+31 more) +Cohesion: 0.11 +Nodes (31): applyUpdate(), archiveDead(), clearAll(), clearAllAsync(), count_memories(), countMemories(), countTokensCached(), decayScores() (+23 more) ### Community 54 - "Community 54" -Cohesion: 0.11 -Nodes (14): generateKey(), JSONBytesResponse, listFields(), Sends pre-serialized JSON bytes without re-encoding (cache-friendly)., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental. (+6 more) +Cohesion: 0.2 +Nodes (10): listFields(), Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental., Discover available field names before querying /historical or /fundamental. (+2 more) ### Community 55 - "Community 55" Cohesion: 0.11 @@ -846,12 +841,12 @@ Cohesion: 0.09 Nodes (15): Performance benchmark tests for stocks API, Performance benchmark tests for stocks API, Ticker index lookup should be O(1) - very fast, Ticker index lookup should be O(1) - very fast, Prefix scan should be much slower than index lookup, Prefix scan should be much slower than index lookup, Index lookup should be significantly faster than scan, Index lookup should be significantly faster than scan (+7 more) ### Community 58 - "Community 58" -Cohesion: 0.17 -Nodes (15): getGoogleSSO(), createAccessToken(), googleCallback(), googleLogin(), isSecureScheme(), issueSessionCookie(), login(), logout() (+7 more) +Cohesion: 0.25 +Nodes (10): googleCallback(), isSecureScheme(), issueSessionCookie(), login(), logout(), register(), resolveCookieDomain(), Covers line 23: isSecureScheme helper. (+2 more) ### Community 59 - "Community 59" -Cohesion: 0.17 -Nodes (20): Tests for main/utils/connectivity.py — covers all branches., test_both_engines_ok(), test_connection_error(), test_generic_exception(), test_non_200_status(), test_non_stocks_prefix(), test_request_exception(), test_service_not_found() (+12 more) +Cohesion: 0.06 +Nodes (38): lifespan(), status(), initialize(), initialize(), MCPDetectMiddleware, StocksAPIService, Tests for main/utils/connectivity.py — covers all branches., checkServiceConnection — success, not found, errors. (+30 more) ### Community 60 - "Community 60" Cohesion: 0.09 @@ -862,7 +857,7 @@ Cohesion: 0.1 Nodes (20): architectures, attention_probs_dropout_prob, gradient_checkpointing, hidden_act, hidden_dropout_prob, hidden_size, initializer_range, intermediate_size (+12 more) ### Community 63 - "Community 63" -Cohesion: 0.26 +Cohesion: 0.29 Nodes (4): Shared query pipeline for historical and fundamental endpoints., Fetch live prices for B3 tickers via yfinance. B3 tickers must match, sanitizeNanValues(), StocksQueryManager ### Community 64 - "Community 64" @@ -898,8 +893,8 @@ Cohesion: 0.11 Nodes (19): API Key System, B3 Scraper, Fundamental Data, Gemini Model, Historical Data, Ma'at Stock Algorithm, Mansa Server, MySQL Database (+11 more) ### Community 72 - "Community 72" -Cohesion: 0.1 -Nodes (9): B3Scraper, getCurrentSelic(), getInitialData(), calculateInvestingScore(), initialize(), P5: register the scraper cron jobs on the shared scheduler. Kept in this, registerScraperJobs(), runScraper() (+1 more) +Cohesion: 0.14 +Nodes (12): initialize(), P5: register memory maintenance on the shared scheduler. Kept in this ser, registerMemoryMaintenanceJob(), initialize(), P5: register the session-cleanup job on the shared scheduler. Kept in thi, registerSessionCleanupJobs(), UserService, getSharedScheduler() (+4 more) ### Community 73 - "Community 73" Cohesion: 0.16 @@ -930,15 +925,15 @@ Cohesion: 0.05 Nodes (44): cn(), AlertDialogAction(), AlertDialogCancel(), AlertDialogContent(), AlertDialogDescription(), AlertDialogFooter(), AlertDialogHeader(), AlertDialogMedia() (+36 more) ### Community 80 - "Community 80" -Cohesion: 0.16 -Nodes (18): buildSummary(), charCount(), countTokens(), dedup(), extractDecisions(), extractMetrics(), extractSnapshots(), extractTickers() (+10 more) +Cohesion: 0.15 +Nodes (19): buildSummary(), charCount(), countTokens(), dedup(), extractDecisions(), extractMetrics(), extractSnapshots(), extractTickers() (+11 more) ### Community 81 - "Community 81" -Cohesion: 0.15 -Nodes (13): getLiveCotation(), Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th (+5 more) +Cohesion: 0.17 +Nodes (12): getLiveCotation(), Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th, Get real-time price quotation for a single Brazilian B3 stock. Returns th (+4 more) ### Community 82 - "Community 82" -Cohesion: 0.15 +Cohesion: 0.16 Nodes (14): arrowTypeFor(), buildCotationDateIndex(), buildFeatherCache(), buildTickerIndex(), optimizeDtypes(), P1: establish the sorted-cache invariant once at load/refresh. Sorts by (, P1: first-occurrence index over a sortCacheFrame-sorted frame. The cache, Get cached stocks data with optional column filtering. (+6 more) ### Community 83 - "Community 83" @@ -970,8 +965,8 @@ Cohesion: 0.08 Nodes (23): code:python (import asyncio), code:jsx (import { describe, it, expect, vi, beforeEach } from 'vitest), code:javascript (const RESUME_KEY = 'mansa_resume';), code:javascript (let accumulated = '';), code:javascript (const maybeResume = useCallback(async () => {), code:javascript (useEffect(() => {), code:bash (git add frontend/src/App.jsx frontend/src/App.resume.test.js), code:bash (git add TODO.md) (+15 more) ### Community 90 - "Community 90" -Cohesion: 0.18 -Nodes (11): Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback. (+3 more) +Cohesion: 0.13 +Nodes (14): Adopt-Libs Implementation Plan, code:python (from tenacity import retry, retry_if_exception_type, stop_af), code:bash (git add main/app/stocks_api/cache.py main/app/stocks_api/que), code:bash (git commit -m "use native cashews cache decorator"), code:python (from pydantic import BaseModel, TypeAdapter), Global Constraints, Task 1: tenacity replaces bespoke retries, Task 2: cashews native (probe first) (+6 more) ### Community 91 - "Community 91" Cohesion: 0.12 @@ -982,8 +977,8 @@ Cohesion: 0.09 Nodes (21): aliases, components, hooks, lib, ui, utils, iconLibrary, menuAccent (+13 more) ### Community 93 - "Community 93" -Cohesion: 0.12 -Nodes (10): System prompt should instruct LLM about harness state usage., System prompt should instruct LLM about harness state usage., System prompt should instruct LLM about harness state usage., System prompt should instruct LLM about memory vs state., System prompt should instruct LLM about memory vs state., System prompt should instruct LLM about memory vs state., System prompt should instruct LLM about memory vs state., TestSendMessageStateIntegration (+2 more) +Cohesion: 0.11 +Nodes (11): Pytest Testing, System prompt should instruct LLM about harness state usage., System prompt should instruct LLM about harness state usage., System prompt should instruct LLM about harness state usage., System prompt should instruct LLM about memory vs state., System prompt should instruct LLM about memory vs state., System prompt should instruct LLM about memory vs state., System prompt should instruct LLM about memory vs state. (+3 more) ### Community 94 - "Community 94" Cohesion: 0.12 @@ -1006,19 +1001,19 @@ Cohesion: 0.28 Nodes (6): extractTokenPayload(), Tests for extractTokenPayload — the standalone token extraction dependency., Create a mock Starlette Request with given headers., Authorization: Bearer (empty) — no token after Bearer., Authorization: Basic xxx — not Bearer, so no token found., TestExtractTokenPayload ### Community 99 - "Community 99" -Cohesion: 0.1 -Nodes (17): Covers lines 62-63, 65-68: PUT /prometheus/sessions/{sessionId}., Covers lines 62-63, 65-68: PUT /prometheus/sessions/{sessionId}., Covers lines 65-68: title updated successfully., Covers lines 65-68: title updated successfully., Covers lines 62-63, 65-68: PUT /prometheus/sessions/{sessionId}., Covers lines 65-68: title updated successfully., Covers lines 62-63: not the session owner., Covers lines 62-63: not the session owner. (+9 more) +Cohesion: 0.05 +Nodes (33): _make_prometheus_client(), Covers lines 111-112: sessionId is None, new session created., Covers lines 111-112: sessionId is None, new session created., Covers lines 118-119: sessionId is None, new session created., Covers lines 111-112: sessionId is None, new session created., Return (client, app) with prometheus router and mocked deps., Covers lines 33-36: GET /prometheus/sessions., Covers lines 33-36: GET /prometheus/sessions. (+25 more) ### Community 100 - "Community 100" -Cohesion: 0.12 -Nodes (8): _assert_gemini_safe(), Assert a tool function has only Gemini-compatible parameter types., Assert a tool function has only Gemini-compatible parameter types., test_get_state_no_state_returns_error(), test_set_state_no_state_returns_error(), test_tool_has_gemini_safe_signature(), TestStateToolFunctions, TestToolRegistry +Cohesion: 0.16 +Nodes (6): _assert_gemini_safe(), Assert a tool function has only Gemini-compatible parameter types., Assert a tool function has only Gemini-compatible parameter types., test_set_state_no_state_returns_error(), test_tool_has_gemini_safe_signature(), TestStateToolFunctions ### Community 101 - "Community 101" -Cohesion: 0.2 -Nodes (12): execute_code(), Store a value in the harness state for this session. Use this to save inter, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Store a value in the harness state for this session. Use this to save inter (+4 more) +Cohesion: 0.25 +Nodes (4): LoopEvent, LoopEvent model for observable agent loops., Tests for LoopLogger — appends events to history JSON list., TestLoopEventModel ### Community 102 - "Community 102" -Cohesion: 0.13 +Cohesion: 0.12 Nodes (10): BaseSettings, BaseMansaSettings, DiscordSettings, MysqlSettings, PrometheusSettings, ScraperSettings, StocksApiSettings, UserSettings (+2 more) ### Community 103 - "Community 103" @@ -1026,8 +1021,8 @@ Cohesion: 0.13 Nodes (14): 10. Performance, 11. Testing, 12. Risks, 13. Out of Scope (YAGNI), 14. Open Questions, 1. Executive Summary, 2. Context & Motivation, 5. Architecture Decision (+6 more) ### Community 104 - "Community 104" -Cohesion: 0.07 -Nodes (26): Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 120-121: existing session with verified ownership., Covers lines 114-115, 117-120, 122: existing session with verified ownership., Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126, 131, 135-136. (+18 more) +Cohesion: 0.06 +Nodes (34): Covers lines 83-84: session not found., Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126, 131, 135-136., Covers lines 126, 131, 135-136., Covers lines 126-136: DELETE /user/sessions/{sessionId}., Covers lines 126, 131, 135-136., Covers lines 127-129: session not found. (+26 more) ### Community 106 - "Community 106" Cohesion: 0.22 @@ -1046,8 +1041,8 @@ Cohesion: 0.14 Nodes (13): cls_token, do_basic_tokenize, do_lower_case, mask_token, model_max_length, name_or_path, never_split, pad_token (+5 more) ### Community 110 - "Community 110" -Cohesion: 0.15 -Nodes (12): initialize(), P5: register memory maintenance on the shared scheduler. Kept in this ser, registerMemoryMaintenanceJob(), initialize(), P5: register the session-cleanup job on the shared scheduler. Kept in thi, registerSessionCleanupJobs(), UserService, getSharedScheduler() (+4 more) +Cohesion: 0.14 +Nodes (11): Integration tests for the verifyAPIKey function., Test successful API key verification., Integration tests for the verifyAPIKey function., Test API key verification when quota is exceeded., Test API key verification with invalid key., Test API key verification with missing key., Test API key verification with invalid key., Test that API key system can be disabled. (+3 more) ### Community 111 - "Community 111" Cohesion: 0.14 @@ -1071,7 +1066,7 @@ Nodes (11): dateOnly(), EditDividendDialog(), EditLotDialog(), fmtBRL(), fmtMone ### Community 116 - "Community 116" Cohesion: 0.14 -Nodes (16): _build_system_prompt(), buildSystemPrompt(), chatSession(), _execute_memory_tool(), executeMemoryTool(), _get_client(), _get_memory_tools(), getClient() (+8 more) +Nodes (15): _build_system_prompt(), buildSystemPrompt(), chatSession(), _execute_memory_tool(), _get_client(), _get_memory_tools(), getClient(), openMCPClients() (+7 more) ### Community 117 - "Community 117" Cohesion: 0.15 @@ -1086,8 +1081,8 @@ Cohesion: 0.07 Nodes (26): code:python ("""Tests for SandboxManager file mutation helpers (delete_fi), code:python (from main.app.prometheus.sandbox import SandboxManager, host), code:python (@router.post("/workspace/upload")), code:bash (git add main/controller/prometheus_controller.py tests/test_), code:python (from unittest.mock import patch, MagicMock), code:python (from main.app.prometheus.sandbox import SandboxManager, host), code:python (async def serve_file(path: str, **_) -> dict:), code:python ("serve_file": serve_file,) (+18 more) ### Community 120 - "Community 120" -Cohesion: 0.12 -Nodes (26): _make_auth_client(), Tests to cover uncovered lines across controllers, UserManager, and auth util., Return (client, app) with auth + user routers and mocked getSession., Covers lines 107, 109-130, 133: logout token extraction and revocation., Covers lines 111-113: token extracted from Authorization Bearer header., test_callback_existing_user(), test_callback_generic_exception(), test_callback_new_user() (+18 more) +Cohesion: 0.09 +Nodes (35): _make_auth_client(), Tests to cover uncovered lines across controllers, UserManager, and auth util., Covers lines 44-54, 63, 66-71: register success, ValueError, generic Exception., Covers lines 44-54, 63, 66-71: register success, ValueError, generic Exception., Covers lines 87-93, 102: login success and failure paths., Covers lines 87-93, 102: login success and failure paths., Return (client, app) with auth + user routers and mocked getSession., Covers lines 107, 109-130, 133: logout token extraction and revocation. (+27 more) ### Community 121 - "Community 121" Cohesion: 0.21 @@ -1095,7 +1090,7 @@ Nodes (12): code:python (import inspect), code:python (from main.app.prometheus. ### Community 122 - "Community 122" Cohesion: 0.14 -Nodes (11): Config, test_setup_discord_handler_disabled(), test_setup_discord_handler_enabled(), Many concurrent emit() calls must not create more threads than max_workers., Verify that DiscordHandler submits to a bounded executor, not raw threads., The module-level discordExecutor must exist with max_workers <= 5., DiscordHandler.emit() must use discordExecutor.submit, not Thread.start., TestDiscordHandlerThreadPool (+3 more) +Nodes (11): test_setup_discord_handler_disabled(), test_setup_discord_handler_enabled(), TestSetupLogging, Many concurrent emit() calls must not create more threads than max_workers., Verify that DiscordHandler submits to a bounded executor, not raw threads., The module-level discordExecutor must exist with max_workers <= 5., DiscordHandler.emit() must use discordExecutor.submit, not Thread.start., TestDiscordHandlerThreadPool (+3 more) ### Community 123 - "Community 123" Cohesion: 0.17 @@ -1130,12 +1125,12 @@ Cohesion: 0.33 Nodes (5): Performance tests for query operations, Query should respond within 1 second, Performance tests for query operations, Query should respond within 1 second, TestQueryPerformance ### Community 131 - "Community 131" -Cohesion: 0.1 -Nodes (17): Same input → same hash., Different inputs → different hashes., Returns 32-char hex string., pack → unpack preserves values., Empty list roundtrips., 384-dim vector packs to 1536 bytes., TestContentHash, TestPackUnpack (+9 more) +Cohesion: 0.12 +Nodes (16): pack → unpack preserves values., Empty list roundtrips., 384-dim vector packs to 1536 bytes., Empty matrix → empty array., Single row matches cosine_similarity., Multiple rows ranked correctly., Zero query → all zeros., TestBatchCosineSimilarity (+8 more) ### Community 132 - "Community 132" Cohesion: 0.25 -Nodes (7): code:python (from dataclasses import dataclass), code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py ), code:python (from datetime import date), File Structure, Global Constraints, Task 3: Pure derivation math, Wallet Management (Thoth/Iyagba) Implementation Plan +Nodes (7): code:python ("""add wallet_holdings and wallet_lots tables), code:python (import main.models.wallet), code:bash (git add migrations/versions/wallet_tables_20260904_add_walle), File Structure, Global Constraints, Task 2: Alembic migration for wallet tables, Wallet Management (Thoth/Iyagba) Implementation Plan ### Community 133 - "Community 133" Cohesion: 0.18 @@ -1150,12 +1145,12 @@ Cohesion: 0.11 Nodes (4): cache(), Tests for ResultCache., TestColumnValidator, TestResultCache ### Community 136 - "Community 136" -Cohesion: 0.14 -Nodes (11): Integration tests for the verifyAPIKey function., Test successful API key verification., Integration tests for the verifyAPIKey function., Test API key verification when quota is exceeded., Test API key verification with invalid key., Test API key verification with missing key., Test API key verification with invalid key., Test that API key system can be disabled. (+3 more) +Cohesion: 0.29 +Nodes (6): GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422., GET /stocks/realtime-cotation without search returns 422. ### Community 137 - "Community 137" -Cohesion: 0.14 -Nodes (14): _count_memories(), _create_memory(), _get_memory(), Keys with Jaccard > 0.8 should merge., Keys with Jaccard > 0.8 should merge., Keys with low similarity should not merge., Keys with low similarity should not merge., Keys with low similarity should not merge. (+6 more) +Cohesion: 0.18 +Nodes (11): client(), TestClient with all routers mounted — no lifespan (no DB/service init). O, TestClient with all routers mounted — no lifespan (no DB/service init). O, TestClient with all routers mounted — no lifespan (no DB/service init). O, TestClient with all routers mounted — no lifespan (no DB/service init). O, TestClient with all routers mounted — no lifespan (no DB/service init). O, TestClient with stocks router + verifyAPIKey + getCurrentUser overrides., TestClient with all routers mounted — no lifespan (no DB/service init). O (+3 more) ### Community 138 - "Community 138" Cohesion: 0.18 @@ -1166,8 +1161,8 @@ Cohesion: 0.24 Nodes (6): Dataset, produce_data(), Train script for a single file Need to set the TPU address first: export XRT_TP, A class that handles the reddit data files, A class that handles one dataset, RedditDataset ### Community 140 - "Community 140" -Cohesion: 0.08 -Nodes (32): Base, PrometheusMemory, PrometheusMemory, MemoryManager, PrometheusMemory, All memory operations. Stateless class methods., PrometheusService, TestDifferentKeysNoMerge (+24 more) +Cohesion: 0.04 +Nodes (54): Base, PrometheusMemory, PrometheusMemory, MemoryCandidate, MemoryManager, PrometheusMemory, All memory operations. Stateless class methods., Config (+46 more) ### Community 141 - "Community 141" Cohesion: 0.24 @@ -1198,8 +1193,8 @@ Cohesion: 0.23 Nodes (3): categorizeColumns(), TestCategorizeColumns, TestCategorizeColumns ### Community 149 - "Community 149" -Cohesion: 0.2 -Nodes (4): createSession(), getSessionById(), revokeSession(), validateSession() +Cohesion: 0.19 +Nodes (5): createSession(), getSessionById(), parseDeviceFields(), revokeSession(), validateSession() ### Community 151 - "Community 151" Cohesion: 0.2 @@ -1210,8 +1205,8 @@ Cohesion: 0.18 Nodes (12): _getDb(), Search user's saved memories, preferences, and past analysis context. Use t, Search user's saved memories, preferences, and past analysis context. Use t, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use, Search user's saved memories, preferences, and past analysis context. Use (+4 more) ### Community 153 - "Community 153" -Cohesion: 0.12 -Nodes (16): Architecture, Auth/Users — Dual-Layer Session Security, CI Pipeline Order, code:bash (# Run (Docker)), Dev Commands, graphify, Key Quirks, Memory Keys (+8 more) +Cohesion: 0.11 +Nodes (17): Architecture, Auth/Users — Dual-Layer Session Security, CI Pipeline Order, code:bash (# Run (Docker)), Dev Commands, graphify, Key Quirks, Memory Keys (+9 more) ### Community 154 - "Community 154" Cohesion: 0.22 @@ -1246,8 +1241,8 @@ Cohesion: 0.11 Nodes (18): Category 2: Async/Sync Inconsistencies (MEDIUM), Category 4: Caching & Memory (MEDIUM), Category 6: Configuration & Environment (LOW), Category 7: Code Quality (LOW), Executive Summary, Full Code Review Report, Issue 2.1 — All route handlers are synchronous, Issue 2.2 — ServiceManager runs uvicorn in daemon threads (+10 more) ### Community 162 - "Community 162" -Cohesion: 0.2 -Nodes (10): list_files(), List files in the workspace directory. Args: path: Directory pat, Read a file from the sandbox filesystem. Args: path: Absolute pa, List files in the workspace directory. Args: path: Directory pat, List files in the workspace directory. Args: path: Directory pat, List files in the workspace directory. Args: path: Directory pat, List files in the workspace directory. Args: path: Directory pat, List files in the workspace directory. Args: path: Directory pat (+2 more) +Cohesion: 0.25 +Nodes (5): Thread-safe proxy that delegates to per-thread sessions., SessionProxy, get_session(), Return a requests.Session for the current thread. Sessions are created la, Return a requests.Session for the current thread. Sessions are created la ### Community 163 - "Community 163" Cohesion: 0.22 @@ -1322,8 +1317,8 @@ Cohesion: 0.25 Nodes (7): code:block1 (main/), Execution Handoff, Executive Summary: What Mem0 Does That We Don't, File Structure, Mem0 vs Prometheus Memory System — Comparison & Upgrade Plan, Self-Review Checklist, What We Already Do Well (Don't Replace) ### Community 183 - "Community 183" -Cohesion: 0.07 -Nodes (17): Different query parameters should not share cache, Cache should expire after TTL, Tests for connection pool configuration, Stocks engine should have optimized pool settings, Tests for lazy JSON deserialization, Query manager should have deserialize method, Integration tests for all query optimizations, All optimizations should be implemented (+9 more) +Cohesion: 0.17 +Nodes (7): Different query parameters should not share cache, Cache should expire after TTL, Tests for query result caching, CacheManager should track cached queries, Query cache should have configurable TTL, getCachedStocks should support column filtering, TestQueryCaching ### Community 184 - "Community 184" Cohesion: 0.11 @@ -1334,16 +1329,16 @@ Cohesion: 0.38 Nodes (7): code:python (import pytest), code:python (from __future__ import annotations), code:bash (git add main/app/prometheus/context.py tests/test_context.py), Phase 4: ToolContext (Bundled Dispatch Dependencies), Phase 4: ToolContext (Replace God Function), Task 5: ToolContext — Dataclass for Agent Use, Task 5: ToolContext — Single Dispatch Object ### Community 186 - "Community 186" -Cohesion: 0.12 -Nodes (11): Thread-safe proxy that delegates to per-thread sessions., SessionProxy, Verify that getSession() returns per-thread Session instances., Calling getSession() twice in the same thread returns the same object., Two threads must NOT share a Session object., With 20 concurrent threads, every thread must get its own Session., The returned object must be a real requests.Session., TestGetSession (+3 more) +Cohesion: 0.2 +Nodes (6): Verify that getSession() returns per-thread Session instances., Calling getSession() twice in the same thread returns the same object., Two threads must NOT share a Session object., With 20 concurrent threads, every thread must get its own Session., The returned object must be a real requests.Session., TestGetSession ### Community 187 - "Community 187" Cohesion: 0.29 Nodes (6): DEVELOPER:, PREMIUM:, Prometheus, STOCKS_API, USER:, User structure defined by string roles: ### Community 188 - "Community 188" -Cohesion: 0.33 -Nodes (10): Tests for main/utils/logging_config.py — covers DiscordHandler branches., test_discord_disabled(), test_discord_no_webhook(), test_exception_in_submit(), test_level_below_error(), test_message_truncation(), test_submit_called_on_error(), test_with_exception_info() (+2 more) +Cohesion: 0.38 +Nodes (9): Tests for main/utils/logging_config.py — covers DiscordHandler branches., test_discord_disabled(), test_discord_no_webhook(), test_exception_in_submit(), test_level_below_error(), test_message_truncation(), test_submit_called_on_error(), test_with_exception_info() (+1 more) ### Community 189 - "Community 189" Cohesion: 0.36 @@ -1378,8 +1373,8 @@ Cohesion: 0.33 Nodes (5): cls_token, mask_token, pad_token, sep_token, unk_token ### Community 197 - "Community 197" -Cohesion: 0.18 -Nodes (11): getHistorical(), Get year-based historical financial data for Brazilian B3 stocks. Returns, Get year-based historical financial data for Brazilian B3 stocks. Returns, Get year-based historical financial data for Brazilian B3 stocks. Returns, Get year-based historical financial data for Brazilian B3 stocks. Returns, Get year-based historical financial data for Brazilian B3 stocks. Returns, Get year-based historical financial data for Brazilian B3 stocks. Returns, Get year-based historical financial data for Brazilian B3 stocks. Returns (+3 more) +Cohesion: 0.1 +Nodes (15): generateKey(), getHistorical(), JSONBytesResponse, Get year-based historical financial data for Brazilian B3 stocks. Returns, Get year-based historical financial data for Brazilian B3 stocks. Returns, Get year-based historical financial data for Brazilian B3 stocks. Returns, Sends pre-serialized JSON bytes without re-encoding (cache-friendly)., Get year-based historical financial data for Brazilian B3 stocks. Returns (+7 more) ### Community 198 - "Community 198" Cohesion: 0.33 @@ -1422,8 +1417,8 @@ Cohesion: 0.33 Nodes (6): API Design (6), Architecture (8), Frontend (7), P1 — Should Fix, Security (6), Testing (4) ### Community 208 - "Community 208" -Cohesion: 0.13 -Nodes (13): Covers lines 83-84: session not found., Covers lines 77, 83-84, 86: GET /prometheus/history/{sessionId}., Covers lines 77, 83-84, 86: GET /prometheus/history/{sessionId}., Covers lines 77, 86: session found with history., Covers lines 77, 86: session found with history., Covers lines 77, 83-84, 86: GET /prometheus/history/{sessionId}., Covers lines 77, 86: session found with history., Covers lines 77, 83-84, 86: GET /prometheus/history/{sessionId}. (+5 more) +Cohesion: 0.25 +Nodes (8): Same input → same hash., Different inputs → different hashes., Returns 32-char hex string., TestContentHash, content_hash(), contentHash(), MD5 hash for change detection., MD5 hash for change detection. ### Community 209 - "Community 209" Cohesion: 0.33 @@ -1446,8 +1441,8 @@ Cohesion: 0.17 Nodes (11): code:python (def test_search_defersEmbeddingBlob(db):), code:python (from contextlib import contextmanager), code:python (from sqlalchemy.orm import defer), code:bash (git add main/app/prometheus/memory.py tests/test_memory_sear), code:python (def test_search_fusesFulltextOverVectorOnly(db):), code:python (def minMax(values: list[float]) -> list[float]:), code:bash (git add main/app/prometheus/memory.py tests/test_memory_sear), Global Constraints (+3 more) ### Community 215 - "Community 215" -Cohesion: 0.19 -Nodes (8): AuthenticationService, initialize(), initialize(), MCPDetectMiddleware, StocksAPIService, getApp(), runAll(), ServiceManager +Cohesion: 0.33 +Nodes (4): Integration tests for all query optimizations, All optimizations should be implemented, Query filter should use ticker index, TestQueryOptimization ### Community 216 - "Community 216" Cohesion: 0.29 @@ -1519,7 +1514,7 @@ Nodes (5): 8. Build Sequence (4 phases, each independently shippable), Phase 0 ### Community 234 - "Community 234" Cohesion: 0.14 -Nodes (11): memoryMaintenance(), Decay happens first, then archive check with new scores., Decay happens first, then archive check with new scores., Score that decays to >= threshold stays alive. 0.11 * 0.95 = 0.1045 >= 0.1., Score that decays to >= threshold stays alive. 0.12 * 0.90 = 0.108 >= 0.1., 89 days with low score → not archived (need > 90)., 89 days with low score → not archived (need > 90)., TestDecayAndArchiveTogether (+3 more) +Nodes (3): getCurrentSelic(), getInitialData(), calculateInvestingScore() ### Community 236 - "Community 236" Cohesion: 0.5 @@ -1566,8 +1561,8 @@ Cohesion: 0.5 Nodes (4): Category 5: Error Handling Gaps (MEDIUM), Issue 5.1 — Generic exception handler swallows traceback in production, Issue 5.2 — DiscordHandler sends only message, not traceback, Issue 5.3 — `_build_error_response` ignores `status_code` parameter ### Community 251 - "Community 251" -Cohesion: 0.09 -Nodes (17): client(), pytest_configure(), TestClient with all routers mounted — no lifespan (no DB/service init). O, Set required env vars before test collection. config.py eagerly instantia, Reset slowapi in-memory rate limiter between every test., Set required env vars before test collection. config.py eagerly instantia, TestClient with all routers mounted — no lifespan (no DB/service init). O, TestClient with all routers mounted — no lifespan (no DB/service init). O (+9 more) +Cohesion: 0.17 +Nodes (6): pytest_configure(), Set required env vars before test collection. config.py eagerly instantia, Reset slowapi in-memory rate limiter between every test., Set required env vars before test collection. config.py eagerly instantia, Set required env vars before test collection. config.py eagerly instantia, _reset_rate_limiter() ### Community 252 - "Community 252" Cohesion: 0.5 @@ -1610,8 +1605,8 @@ Cohesion: 0.22 Nodes (8): 1. Prime owns the goal, lanes own the work, 2. Dispatch: `delegate()`, one per lane, one turn, 3. Delegate toolsets vary — verify each lane, 4. Trust nothing — verify everything, 5. Windows PowerShell survival, 6. Finish per lane, not per swarm, 7. Standing bans (this repo), SWARMS.md — subagent swarm playbook (OpenCode / Hermes) ### Community 474 - "Community 474" -Cohesion: 0.22 -Nodes (4): authenticateUser(), createUserAccount(), FastAPI, PaginationParams +Cohesion: 0.4 +Nodes (4): getGoogleSSO(), googleLogin(), test_get_google_sso_default_redirect(), test_get_google_sso_with_redirect() ### Community 476 - "Community 476" Cohesion: 0.22 @@ -1637,6 +1632,10 @@ Nodes (4): code:python (def test_extract_temporal_info():), code:python (# main/ Cohesion: 0.5 Nodes (4): code:python (def test_session_scoped_memory(db_session, sample_user):), code:python (# Add to main/models/memory.py), code:bash (git add main/models/memory.py main/app/prometheus/memory.py ), Task 8: Session Scoping +### Community 482 - "Community 482" +Cohesion: 0.11 +Nodes (4): FastAPI, Tests for inline pagination params (used in user + prometheus controllers)., TestPaginationParams, PaginationParams + ### Community 483 - "Community 483" Cohesion: 0.5 Nodes (4): code:python (def test_consolidation_preserves_decisions():), code:python (# Add to main/app/prometheus/summarizer.py), code:bash (git add main/app/prometheus/summarizer.py tests/test_consoli), Task 9: Memory Consolidation @@ -1653,9 +1652,13 @@ Nodes (4): Priority 1: Fix Critical Gaps, Priority 2: Improve Retrieval, Priorit Cohesion: 0.23 Nodes (6): CHART_COLORS, PortfolioBarsCard(), PortfolioPieCard(), tooltipStyle, groupHistoryByMonth(), monthKey() +### Community 487 - "Community 487" +Cohesion: 0.16 +Nodes (14): execute_code(), Store a value in the harness state for this session. Use this to save inter, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Read a file from the workspace. Args: path: Path to the file (e., Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, Execute Python code in an isolated sandbox. Use for quantitative analysis, (+6 more) + ### Community 488 - "Community 488" -Cohesion: 0.12 -Nodes (10): Regression: is_string_dtype fails when column has strings + None (pandas 2.x)., Tests covering query.py lines 50-67., Tests covering query.py lines 50-67., Regression: is_string_dtype fails when column has strings + None (pandas 2.x)., Regression: is_string_dtype fails when column has strings + None (pandas 2.x)., Regression: is_string_dtype fails when column has strings + None (pandas 2.x)., Tests covering query.py lines 50-67., Tests covering query.py lines 50-67. (+2 more) +Cohesion: 0.4 +Nodes (4): COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament, COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament, COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament, COTACAO 10Y PADRAO and COTACAO 10Y AJUSTADA belong to /cotations, not /fundament ### Community 489 - "Community 489" Cohesion: 0.6 @@ -1666,48 +1669,44 @@ Cohesion: 0.33 Nodes (5): Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, TestFilterBySearchTerms ### Community 491 - "Community 491" -Cohesion: 0.24 -Nodes (5): lifespan(), status(), checkDatabaseConnection(), checkSingleDb(), runMigrations() +Cohesion: 0.5 +Nodes (4): code:python (from dataclasses import dataclass), code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py ), code:python (from datetime import date), Task 3: Pure derivation math ### Community 492 - "Community 492" Cohesion: 0.33 Nodes (5): Baseline (lane 4), Export recipe, Move triggers (any one fires the migration), Options, Vector Scale-Up Runbook ### Community 493 - "Community 493" -Cohesion: 0.07 -Nodes (28): Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 36-38, 40-44, 46, 48-49, 51, 58-59, 61: successful user retrieval., Covers lines 36-38, 40-44, 46, 48-49, 51, 58-59, 61: successful user retrieval., Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 36-38, 40-44, 46, 48-49, 51, 58-59, 61: successful user retrieval. (+20 more) - -### Community 495 - "Community 495" -Cohesion: 0.25 -Nodes (4): Authentication System, Google OAuth, JWT Authentication, TestSessionExpiryConfig +Cohesion: 0.05 +Nodes (37): Covers line 27: user already has the role., Covers line 27: user already has the role., Covers line 27: user already has the role., Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 34, 36-38, 40-44, 46, 48-49, 51, 58-59, 61, 63-67: UserManager.getC, Covers lines 36-38, 40-44, 46, 48-49, 51, 58-59, 61: successful user retrieval. (+29 more) ### Community 497 - "Community 497" -Cohesion: 0.5 -Nodes (4): code:python ("""add wallet_holdings and wallet_lots tables), code:python (import main.models.wallet), code:bash (git add migrations/versions/wallet_tables_20260904_add_walle), Task 2: Alembic migration for wallet tables +Cohesion: 0.18 +Nodes (11): Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback., Store a memory about the user's preferences, analysis results, or feedback. (+3 more) ### Community 498 - "Community 498" -Cohesion: 0.06 -Nodes (36): AuthenticationManager, IntFlag, Covers line 28: GET /auth/health., Covers line 28: GET /auth/health., Covers line 13: UserManager.__init__., Covers line 13: UserManager.__init__., Covers line 13: UserManager.__init__., Covers line 13: UserManager.__init__. (+28 more) +Cohesion: 0.05 +Nodes (38): AuthenticationManager, IntFlag, Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 28: GET /auth/health. (+30 more) ### Community 499 - "Community 499" Cohesion: 0.2 Nodes (9): code:python (import numpy as np), code:python (def normalizeRows(matrix: np.ndarray) -> np.ndarray:), code:bash (git add main/app/prometheus/vector.py tests/test_vector_norm), code:python ("""One-shot: renormalize stored embeddings to unit norm. Usa), code:bash (git add scripts/backfill_normalize_embeddings.py), Global Constraints, Lane 1: Normalized Embeddings + Dot-Product Search Implementation Plan, Task 1: Normalize on encode + row-normalize helper (+1 more) ### Community 500 - "Community 500" -Cohesion: 0.25 -Nodes (8): Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Read a file from the sandbox filesystem. Args: path: Absolute pa, Read a file from the sandbox filesystem. Args: path: Absolute pa, Read a file from the workspace. Args: path: Path to the file (e., read_file() +Cohesion: 0.18 +Nodes (6): System prompt should include state context when provided., System prompt should not include state section when empty., State section should appear after memories section., All state entries should appear in the prompt., System prompt should work without state parameter., TestBuildSystemPromptState ### Community 501 - "Community 501" -Cohesion: 0.22 -Nodes (3): getCurrentSession(), getSessions(), sessionToDict() +Cohesion: 0.2 +Nodes (4): verifyAccessToken(), getCurrentSession(), getSessions(), sessionToDict() ### Community 502 - "Community 502" -Cohesion: 0.11 -Nodes (15): Tests for connection pool configuration, Tests for connection pool configuration, Stocks engine should have optimized pool settings, Stocks engine should have optimized pool settings, Tests for lazy JSON deserialization, Tests for lazy JSON deserialization, Query manager should have deserialize method, Query manager should have deserialize method (+7 more) +Cohesion: 0.08 +Nodes (20): Tests for connection pool configuration, Tests for connection pool configuration, Stocks engine should have optimized pool settings, Stocks engine should have optimized pool settings, Tests for lazy JSON deserialization, Tests for lazy JSON deserialization, Query manager should have deserialize method, Query manager should have deserialize method (+12 more) ### Community 503 - "Community 503" -Cohesion: 0.17 -Nodes (7): Tests for dynamic ticker index feature, Ticker index should be built when cache is loaded, Ticker index should contain all tickers from cache, Ticker index should be case-insensitive, Looking up ticker should return valid row index, Ticker index should be rebuilt when cache refreshes, TestTickerIndex +Cohesion: 0.1 +Nodes (13): Tests for connection pool configuration, Stocks engine should have optimized pool settings, Tests for lazy JSON deserialization, Query manager should have deserialize method, Tests for dynamic ticker index feature, Ticker index should be built when cache is loaded, Ticker index should contain all tickers from cache, Ticker index should be case-insensitive (+5 more) ### Community 505 - "Community 505" Cohesion: 0.33 @@ -1734,52 +1733,44 @@ Cohesion: 0.22 Nodes (7): Integration tests for all query optimizations, Integration tests for all query optimizations, All optimizations should be implemented, All optimizations should be implemented, Query filter should use ticker index, Query filter should use ticker index, TestQueryOptimization ### Community 517 - "Community 517" -Cohesion: 0.25 -Nodes (14): baseFrame(), deserializeJsonColumns(), envelope(), filterBySearchTerms(), _filterCotationByDate(), filterCotationData(), finalize(), _parseCotationDate() (+6 more) +Cohesion: 0.2 +Nodes (16): baseFrame(), deserializeJsonColumns(), envelope(), fetchLivePayload(), filterBySearchTerms(), _filterCotationByDate(), filterCotationData(), finalize() (+8 more) ### Community 518 - "Community 518" -Cohesion: 0.08 -Nodes (19): create_memories(), Zero access but score still above threshold → not archived., Even with low score, if accessed → not archived., Even with low score, if accessed → not archived., Already archived memories are skipped., Already archived memories are skipped., Helper to create memories with controlled baseScore, lastAccessedAt, accessCount, Helper to create memories with controlled baseScore, lastAccessedAt, accessCount (+11 more) +Cohesion: 0.06 +Nodes (30): memoryMaintenance(), create_memories(), Zero access but score still above threshold → not archived., Even with low score, if accessed → not archived., Even with low score, if accessed → not archived., Already archived memories are skipped., Already archived memories are skipped., Decay happens first, then archive check with new scores. (+22 more) ### Community 519 - "Community 519" Cohesion: 0.57 Nodes (6): addRole(), addRoleToUser(), getCurrentUser(), getRolesList(), hasRole(), toDict() ### Community 520 - "Community 520" -Cohesion: 0.16 -Nodes (9): pd.NA is not a string, so lambda returns it unchanged., All four SPECIAL_COLS should parse correctly when mixed with None., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., All four SPECIAL_COLS should parse correctly when mixed with None., All four SPECIAL_COLS should parse correctly when mixed with None. (+1 more) +Cohesion: 0.33 +Nodes (5): pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged., pd.NA is not a string, so lambda returns it unchanged. ### Community 521 - "Community 521" Cohesion: 0.2 Nodes (9): Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132)., Invalid date format raises exception (line 132). (+1 more) ### Community 522 - "Community 522" -Cohesion: 0.32 -Nodes (3): TestCleanup, cleanup(), Close the main thread's session at interpreter shutdown. +Cohesion: 0.16 +Nodes (5): Tests for main/utils/http_session.py — covers all branches., TestCleanup, TestGetSession, cleanup(), Close the main thread's session at interpreter shutdown. ### Community 523 - "Community 523" -Cohesion: 0.13 -Nodes (18): check_cache(), Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Read a file from the workspace. Args: path: Path to the file (e., List files in the workspace directory. Args: path: Directory pat (+10 more) +Cohesion: 0.11 +Nodes (21): list_files(), Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, Write a file to the workspace. Use this to save data files (CSV, JSON, scri, List files in the workspace directory. Args: path: Directory pat, List files in the workspace directory. Args: path: Directory pat (+13 more) ### Community 524 - "Community 524" -Cohesion: 0.22 -Nodes (7): verifyAccessToken(), Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError., Covers lines 50-51: jwt.InvalidTokenError. - -### Community 525 - "Community 525" -Cohesion: 0.12 -Nodes (16): Covers line 16: empty password raises ValueError., Covers line 16: empty password raises ValueError., Covers line 16: empty password raises ValueError., Covers lines 45-51: verifyAccessToken with expired and invalid tokens., Covers line 16: empty password raises ValueError., Covers lines 48-49: jwt.ExpiredSignatureError., Covers lines 45-51: verifyAccessToken with expired and invalid tokens., Covers lines 45-51: verifyAccessToken with expired and invalid tokens. (+8 more) +Cohesion: 0.11 +Nodes (17): Covers lines 45-51: verifyAccessToken with expired and invalid tokens., Covers line 16: empty password raises ValueError., Covers lines 48-49: jwt.ExpiredSignatureError., Covers lines 45-51: verifyAccessToken with expired and invalid tokens., Covers lines 45-51: verifyAccessToken with expired and invalid tokens., Covers lines 48-49: jwt.ExpiredSignatureError., Covers lines 45-51: verifyAccessToken with expired and invalid tokens., Covers lines 48-49: jwt.ExpiredSignatureError. (+9 more) ### Community 526 - "Community 526" Cohesion: 0.33 Nodes (7): buildKey(), clearAll(), getMatrix(), invalidateUser(), runAwait(), main(), One-shot: renormalize stored embeddings to unit norm. Usage: python scripts/back ### Community 528 - "Community 528" -Cohesion: 0.07 -Nodes (26): Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added. (+18 more) - -### Community 529 - "Community 529" -Cohesion: 0.18 -Nodes (6): System prompt should include state context when provided., System prompt should not include state section when empty., State section should appear after memories section., All state entries should appear in the prompt., System prompt should work without state parameter., TestBuildSystemPromptState +Cohesion: 0.11 +Nodes (16): Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added., Covers lines 13, 17, 19-20, 22-27: UserManager.addRoleToUser., Covers lines 17, 22-27: user found, role not present, role added. (+8 more) ### Community 530 - "Community 530" Cohesion: 0.39 @@ -1803,28 +1794,24 @@ Nodes (5): replaceNan handles direct float NaN values (line 34)., replaceNan han ### Community 536 - "Community 536" Cohesion: 0.14 -Nodes (19): executeStateTool(), get_state(), Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Execute Python code in an isolated sandbox. Use for quantitative analysis,, test_dispatch_get_state() (+11 more) +Nodes (19): executeStateTool(), get_state(), Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, Retrieve values from the harness state. Use this to recall intermediate results,, test_get_state_no_state_returns_error(), test_dispatch_get_state() (+11 more) ### Community 538 - "Community 538" Cohesion: 0.4 Nodes (5): Category 8: Testing Gaps (MEDIUM), Issue 8.1 — No integration tests for full request lifecycle, Issue 8.2 — No tests for scraper, stocks query, or cache, Issue 8.3 — No tests for Google OAuth callback, Issue 8.4 — No tests for session cleanup -### Community 539 - "Community 539" -Cohesion: 0.29 -Nodes (6): Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., Covers line 18: GET /stocks/health., TestStocksApiHealth - ### Community 540 - "Community 540" Cohesion: 0.29 Nodes (6): code:python (import argparse), code:bash (git add bench/bench_memory_vector.py), Global Constraints, Lane 4: Before/After Bench Implementation Plan, Task 1: Bench script with synthetic scale sweep, Task 2: Record baseline and post-lane numbers -### Community 541 - "Community 541" -Cohesion: 0.2 -Nodes (3): Pytest Testing, Tests for main/utils/http_session.py — covers all branches., TestGetSession - ### Community 542 - "Community 542" Cohesion: 0.5 Nodes (3): at, label, rows +### Community 543 - "Community 543" +Cohesion: 0.22 +Nodes (8): Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false., Hit the actual /stocks/cotations HTTP endpoint with adjusted=false. + ### Community 545 - "Community 545" Cohesion: 0.29 Nodes (7): code:python (def test_split_cliff_no_fake_loss_on_adjusted_series(monkeyp), code:python (def test_snapshot_includes_received_and_cash_gain(dbSession,), code:python (def test_history_merges_dividend_receipts(dbSession, sampleU), code:python (def test_ex_div_methodology_decides_received_stacking(dbSess), code:python (def ex_div_smoothing_verdict(padrao_before: float, padrao_af), code:bash (git add main/app/wallet/manager.py main/controller/wallet_co), Task 12: Split-cliff regression test + snapshot/history dividend extension + final gate @@ -1886,24 +1873,24 @@ Cohesion: 0.5 Nodes (4): code:python (import pytest), code:python (import logging), code:bash (git add main/app/wallet/prices.py tests/test_wallet_prices.p), Task 6: Price client — one batched STOCKS_API fetch per snapshot ### Community 562 - "Community 562" -Cohesion: 0.38 -Nodes (6): create_memory(), createMemory(), _downloadModel(), embed(), getEmbeddingModel(), executeMemoryTool() +Cohesion: 0.32 +Nodes (7): create_memory(), createMemory(), _downloadModel(), embed(), getEmbeddingModel(), executeMemoryTool(), executeMemoryTool() ### Community 563 - "Community 563" Cohesion: 0.29 -Nodes (6): Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., Covers line 35: GET /stocks/historical., TestStocksApiHistorical +Nodes (7): check_cache(), Read a file from the sandbox filesystem. Args: path: Absolute pa, List files in the workspace directory. Args: path: Directory pat, Upload a file to the sandbox filesystem. Use this to push data files (CSV,, Check if a computed result exists in the cache. Use before executing expens, read_sandbox_file(), upload_to_sandbox() ### Community 564 - "Community 564" -Cohesion: 0.67 -Nodes (3): checkServiceConnection — success, not found, errors., checkServiceConnection — success, not found, errors., TestCheckServiceConnection +Cohesion: 0.29 +Nodes (7): Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Read a file from the workspace. Args: path: Path to the file (e., Read a file from the sandbox filesystem. Args: path: Absolute pa, Read a file from the sandbox filesystem. Args: path: Absolute pa, Read a file from the workspace. Args: path: Path to the file (e., read_file() ### Community 565 - "Community 565" Cohesion: 0.33 Nodes (6): Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., Tests covering key.py lines 48-66., TestCreateKey ### Community 566 - "Community 566" -Cohesion: 0.67 -Nodes (3): checkMySqlConnection — success, errors, engine=None paths., checkMySqlConnection — success, errors, engine=None paths., TestCheckMySqlConnection +Cohesion: 0.25 +Nodes (7): Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them)., Pass field name WITHOUT year (how categorizeColumns returns them). ### Community 567 - "Community 567" Cohesion: 0.14 @@ -1913,41 +1900,41 @@ Nodes (18): verifyAPIKey(), Tests to increase coverage for query.py, key.py, and Cohesion: 0.29 Nodes (6): GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422., GET /cotations without search returns 422. -### Community 570 - "Community 570" +### Community 573 - "Community 573" Cohesion: 0.33 -Nodes (5): Tests for optimized search filtering, Tests for optimized search filtering, Filter should use ticker index for O(1) lookup, Filter should use ticker index for O(1) lookup, TestFilterBySearchTerms +Nodes (6): makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., TestMakeChatIncludesMemoryTools + +### Community 575 - "Community 575" +Cohesion: 0.4 +Nodes (5): initialize(), P5: register the scraper cron jobs on the shared scheduler. Kept in this, registerScraperJobs(), runScraper(), ScraperService -### Community 571 - "Community 571" +### Community 576 - "Community 576" Cohesion: 0.33 Nodes (6): dispatchToolCall must route memory tool names via TOOL_REGISTRY., dispatchToolCall must route memory tool names to executeMemoryTool., dispatchToolCall must route memory tool names to executeMemoryTool., dispatchToolCall must route memory tool names to executeMemoryTool., dispatchToolCall must route memory tool names to executeMemoryTool., TestDispatchRoutesMemoryTools -### Community 572 - "Community 572" +### Community 577 - "Community 577" Cohesion: 0.33 Nodes (5): Every function in TOOL_REGISTRY must have Gemini-safe signatures. Custom cl, Every function in TOOL_REGISTRY must have Gemini-safe signatures. Custom cl, Regression: HarnessState must never leak into tool signatures., Regression: HarnessState must never leak into tool signatures., TestGeminiCompatibility -### Community 573 - "Community 573" -Cohesion: 0.33 -Nodes (6): makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., makeChat must include MEMORY_TOOLS alongside MCP sessions., TestMakeChatIncludesMemoryTools - ## Knowledge Gaps -- **3044 isolated node(s):** `$schema`, `style`, `rsc`, `tsx`, `config` (+3039 more) +- **3054 isolated node(s):** `$schema`, `style`, `rsc`, `tsx`, `config` (+3049 more) These have ≤1 connection - possible missing edges or undocumented components. -- **234 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes. +- **231 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes. ## Suggested Questions _Questions this graph is uniquely positioned to answer:_ -- **Why does `Pytest Testing` connect `Community 541` to `Authentication Core`, `Frontend Components`, `Community 129`, `Data Models & Types`, `Community 131`, `Community 518`, `Community 135`, `Community 138`, `Community 140`, `Community 527`, `Community 18`, `Community 147`, `Community 24`, `Community 25`, `Community 536`, `Community 27`, `Community 29`, `Community 32`, `Community 33`, `Community 546`, `Community 40`, `Community 44`, `Community 45`, `Community 172`, `Community 49`, `Community 51`, `Community 567`, `Community 184`, `Community 183`, `Community 59`, `Community 188`, `Community 86`, `Community 474`, `Community 475`, `Community 120`, `Community 93`, `Community 477`, `Community 100`, `Community 234`, `Community 495`, `Community 502`, `Community 504`, `Community 251`, `Community 125`?** - _High betweenness centrality (0.102) - this node is a cross-community bridge._ -- **Why does `UserManager` connect `Community 498` to `Prometheus Agent`, `Community 519`, `Prometheus Memory`, `Community 140`, `Community 525`, `User Roles & Permissions`, `Community 141`, `Community 16`, `Community 528`, `Community 21`, `Community 22`, `Community 539`, `Community 28`, `Community 37`, `Community 47`, `Community 178`, `Community 563`, `Community 565`, `Community 567`, `Community 58`, `Community 61`, `Community 68`, `Community 208`, `Community 86`, `Community 221`, `Community 99`, `Community 231`, `Community 104`, `Community 488`, `Community 107`, `Community 493`, `Community 114`, `Community 120`, `Community 125`?** - _High betweenness centrality (0.042) - this node is a cross-community bridge._ -- **Why does `Prometheus` connect `Community 116` to `Frontend Components`, `Device Detection`, `Community 138`, `Community 140`, `Frontend App Shell`, `Community 529`, `Community 151`, `Community 24`, `Community 543`, `Community 544`, `Community 52`, `Community 569`, `Community 571`, `Community 60`, `Community 573`, `Community 194`, `Community 67`, `Community 68`, `Community 80`, `Community 87`, `Community 88`, `Community 93`, `Community 105`, `Community 122`, `Community 125`?** - _High betweenness centrality (0.037) - this node is a cross-community bridge._ +- **Why does `Pytest Testing` connect `Community 93` to `Authentication Core`, `Frontend Components`, `Community 129`, `Data Models & Types`, `Community 131`, `Community 518`, `Community 135`, `Community 522`, `Community 138`, `Community 140`, `Community 527`, `Community 18`, `Community 147`, `Community 24`, `Community 25`, `Community 536`, `Community 27`, `Community 29`, `Community 32`, `Community 33`, `Community 546`, `Community 40`, `Community 43`, `Community 44`, `Community 45`, `Community 172`, `Community 49`, `Community 51`, `Community 567`, `Community 184`, `Community 59`, `Community 188`, `Community 86`, `Community 475`, `Community 477`, `Community 482`, `Community 100`, `Community 102`, `Community 502`, `Community 503`, `Community 120`, `Community 251`, `Community 125`?** + _High betweenness centrality (0.103) - this node is a cross-community bridge._ +- **Why does `FastAPI` connect `Community 482` to `Community 129`, `Community 517`, `Community 519`, `Community 530`, `Community 18`, `Community 147`, `Community 26`, `Community 33`, `Community 546`, `Community 34`, `Community 40`, `Community 43`, `Community 45`, `Community 567`, `Community 58`, `Community 59`, `Community 197`, `Community 71`, `Community 73`, `Community 84`, `Community 475`, `Community 477`, `Community 498`, `Community 501`, `Community 120`?** + _High betweenness centrality (0.045) - this node is a cross-community bridge._ +- **Why does `Prometheus` connect `Community 116` to `Frontend Components`, `Device Detection`, `Community 138`, `Community 140`, `Frontend App Shell`, `Community 529`, `Community 151`, `Community 24`, `Community 544`, `Community 52`, `Community 569`, `Community 60`, `Community 573`, `Community 576`, `Community 194`, `Community 67`, `Community 68`, `Community 80`, `Community 87`, `Community 88`, `Community 93`, `Community 105`, `Community 500`, `Community 125`?** + _High betweenness centrality (0.033) - this node is a cross-community bridge._ - **Are the 72 inferred relationships involving `StocksCacheManager` (e.g. with `TestStocksCacheManager` and `TestVerifyAPIKey`) actually correct?** _`StocksCacheManager` has 72 INFERRED edges - model-reasoned connections that need verification._ - **Are the 52 inferred relationships involving `HarnessState` (e.g. with `Prometheus` and `.streamMessage()`) actually correct?** _`HarnessState` has 52 INFERRED edges - model-reasoned connections that need verification._ - **Are the 54 inferred relationships involving `UserManager` (e.g. with `AuthenticationManager` and `User`) actually correct?** _`UserManager` has 54 INFERRED edges - model-reasoned connections that need verification._ -- **Are the 48 inferred relationships involving `Permission` (e.g. with `PrometheusMemory` and `UserManager`) actually correct?** - _`Permission` has 48 INFERRED edges - model-reasoned connections that need verification._ \ No newline at end of file +- **Are the 49 inferred relationships involving `Permission` (e.g. with `MemoryCandidate` and `PrometheusMemory`) actually correct?** + _`Permission` has 49 INFERRED edges - model-reasoned connections that need verification._ \ No newline at end of file diff --git a/graphify-out/graph.json b/graphify-out/graph.json index aeacec3..462adde 100644 --- a/graphify-out/graph.json +++ b/graphify-out/graph.json @@ -237,7 +237,7 @@ "source_file": "config.py", "source_location": "L91", "id": "server_config_config", - "community": 122, + "community": 140, "norm_label": "config" }, { @@ -264,43 +264,43 @@ "source_file": "run.py", "source_location": "L1", "id": "run_py", - "community": 491, + "community": 59, "norm_label": "run.py" }, { "label": "lifespan()", "file_type": "code", "source_file": "run.py", - "source_location": "L27", + "source_location": "L28", "id": "server_run_lifespan", - "community": 491, + "community": 59, "norm_label": "lifespan()" }, { "label": "health()", "file_type": "code", "source_file": "run.py", - "source_location": "L72", + "source_location": "L73", "id": "server_run_health", - "community": 491, + "community": 59, "norm_label": "health()" }, { "label": "status()", "file_type": "code", "source_file": "run.py", - "source_location": "L77", + "source_location": "L78", "id": "server_run_status", - "community": 491, + "community": 59, "norm_label": "status()" }, { "label": "triggerScraper()", "file_type": "code", "source_file": "run.py", - "source_location": "L111", + "source_location": "L112", "id": "server_run_triggerscraper", - "community": 491, + "community": 59, "norm_label": "triggerscraper()" }, { @@ -2190,7 +2190,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L1", "id": "main_app_authentication_authentication_py", - "community": 474, + "community": 43, "norm_label": "authentication.py" }, { @@ -2208,7 +2208,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L16", "id": "authentication_authentication_createuseraccount", - "community": 474, + "community": 43, "norm_label": "createuseraccount()" }, { @@ -2217,7 +2217,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L51", "id": "authentication_authentication_authenticategoogleuser", - "community": 474, + "community": 43, "norm_label": "authenticategoogleuser()" }, { @@ -2226,7 +2226,7 @@ "source_file": "main/app/authentication/authentication.py", "source_location": "L65", "id": "authentication_authentication_authenticateuser", - "community": 474, + "community": 43, "norm_label": "authenticateuser()" }, { @@ -2247,11 +2247,20 @@ "community": 149, "norm_label": "session.py" }, + { + "label": "parseDeviceFields()", + "file_type": "code", + "source_file": "main/app/authentication/session.py", + "source_location": "L13", + "id": "authentication_session_parsedevicefields", + "community": 149, + "norm_label": "parsedevicefields()" + }, { "label": "SessionManager", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L12", + "source_location": "L30", "id": "authentication_session_sessionmanager", "community": 68, "norm_label": "sessionmanager" @@ -2260,7 +2269,7 @@ "label": "createSession()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L14", + "source_location": "L32", "id": "authentication_session_createsession", "community": 149, "norm_label": "createsession()" @@ -2269,7 +2278,7 @@ "label": "getUserSessions()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L45", + "source_location": "L68", "id": "authentication_session_getusersessions", "community": 149, "norm_label": "getusersessions()" @@ -2278,7 +2287,7 @@ "label": "getSessionById()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L50", + "source_location": "L73", "id": "authentication_session_getsessionbyid", "community": 149, "norm_label": "getsessionbyid()" @@ -2287,7 +2296,7 @@ "label": "getCurrentSession()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L57", + "source_location": "L80", "id": "authentication_session_getcurrentsession", "community": 149, "norm_label": "getcurrentsession()" @@ -2296,7 +2305,7 @@ "label": "revokeSession()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L69", + "source_location": "L92", "id": "authentication_session_revokesession", "community": 149, "norm_label": "revokesession()" @@ -2305,7 +2314,7 @@ "label": "revokeAllSessions()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L81", + "source_location": "L104", "id": "authentication_session_revokeallsessions", "community": 149, "norm_label": "revokeallsessions()" @@ -2314,7 +2323,7 @@ "label": "updateLastActive()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L94", + "source_location": "L117", "id": "authentication_session_updatelastactive", "community": 149, "norm_label": "updatelastactive()" @@ -2323,7 +2332,7 @@ "label": "validateSession()", "file_type": "code", "source_file": "main/app/authentication/session.py", - "source_location": "L104", + "source_location": "L127", "id": "authentication_session_validatesession", "community": 149, "norm_label": "validatesession()" @@ -2334,7 +2343,7 @@ "source_file": "main/app/authentication/sso.py", "source_location": "L1", "id": "main_app_authentication_sso_py", - "community": 58, + "community": 474, "norm_label": "sso.py" }, { @@ -2343,7 +2352,7 @@ "source_file": "main/app/authentication/sso.py", "source_location": "L6", "id": "authentication_sso_getgooglesso", - "community": 58, + "community": 474, "norm_label": "getgooglesso()" }, { @@ -2352,7 +2361,7 @@ "source_file": "main/app/authentication/util.py", "source_location": "L1", "id": "main_app_authentication_util_py", - "community": 524, + "community": 43, "norm_label": "util.py" }, { @@ -2379,7 +2388,7 @@ "source_file": "main/app/authentication/util.py", "source_location": "L31", "id": "authentication_util_createaccesstoken", - "community": 58, + "community": 43, "norm_label": "createaccesstoken()" }, { @@ -2388,7 +2397,7 @@ "source_file": "main/app/authentication/util.py", "source_location": "L44", "id": "authentication_util_verifyaccesstoken", - "community": 524, + "community": 501, "norm_label": "verifyaccesstoken()" }, { @@ -2575,7 +2584,7 @@ "label": "getTokenizer()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L31", + "source_location": "L35", "id": "prometheus_compact_gettokenizer", "community": 80, "norm_label": "gettokenizer()" @@ -2584,7 +2593,7 @@ "label": "countTokens()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L43", + "source_location": "L47", "id": "prometheus_compact_counttokens", "community": 80, "norm_label": "counttokens()" @@ -2593,16 +2602,34 @@ "label": "getStocksFieldsUrl()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L60", + "source_location": "L64", "id": "prometheus_compact_getstocksfieldsurl", "community": 80, "norm_label": "getstocksfieldsurl()" }, + { + "label": "isTransientFieldsError()", + "file_type": "code", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L68", + "id": "prometheus_compact_istransientfieldserror", + "community": 80, + "norm_label": "istransientfieldserror()" + }, + { + "label": "fetchFieldsPayload()", + "file_type": "code", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L83", + "id": "prometheus_compact_fetchfieldspayload", + "community": 80, + "norm_label": "fetchfieldspayload()" + }, { "label": "loadFieldData()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L64", + "source_location": "L89", "id": "prometheus_compact_loadfielddata", "community": 80, "norm_label": "loadfielddata()" @@ -2611,7 +2638,7 @@ "label": "getMetricRegex()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L82", + "source_location": "L105", "id": "prometheus_compact_getmetricregex", "community": 80, "norm_label": "getmetricregex()" @@ -2620,7 +2647,7 @@ "label": "dedup()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L96", + "source_location": "L119", "id": "prometheus_compact_dedup", "community": 80, "norm_label": "dedup()" @@ -2629,7 +2656,7 @@ "label": "extractTickers()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L100", + "source_location": "L123", "id": "prometheus_compact_extracttickers", "community": 80, "norm_label": "extracttickers()" @@ -2638,7 +2665,7 @@ "label": "extractMetrics()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L104", + "source_location": "L127", "id": "prometheus_compact_extractmetrics", "community": 80, "norm_label": "extractmetrics()" @@ -2647,7 +2674,7 @@ "label": "extractDecisions()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L108", + "source_location": "L131", "id": "prometheus_compact_extractdecisions", "community": 80, "norm_label": "extractdecisions()" @@ -2656,7 +2683,7 @@ "label": "extractSnapshots()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L122", + "source_location": "L145", "id": "prometheus_compact_extractsnapshots", "community": 80, "norm_label": "extractsnapshots()" @@ -2665,7 +2692,7 @@ "label": "extractToolCalls()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L135", + "source_location": "L158", "id": "prometheus_compact_extracttoolcalls", "community": 80, "norm_label": "extracttoolcalls()" @@ -2674,7 +2701,7 @@ "label": "buildSummary()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L151", + "source_location": "L174", "id": "prometheus_compact_buildsummary", "community": 80, "norm_label": "buildsummary()" @@ -2683,7 +2710,7 @@ "label": "PrometheusCompactor", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L172", + "source_location": "L195", "id": "prometheus_compact_prometheuscompactor", "community": 80, "norm_label": "prometheuscompactor" @@ -2692,7 +2719,7 @@ "label": ".shouldCompact()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L173", + "source_location": "L196", "id": "prometheus_compact_prometheuscompactor_shouldcompact", "community": 80, "norm_label": ".shouldcompact()" @@ -2701,7 +2728,7 @@ "label": ".getCompactableChunk()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L190", + "source_location": "L213", "id": "prometheus_compact_prometheuscompactor_getcompactablechunk", "community": 80, "norm_label": ".getcompactablechunk()" @@ -2710,7 +2737,7 @@ "label": ".extractEpisode()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L199", + "source_location": "L222", "id": "prometheus_compact_prometheuscompactor_extractepisode", "community": 80, "norm_label": ".extractepisode()" @@ -2719,7 +2746,7 @@ "label": ".consolidate()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L221", + "source_location": "L244", "id": "prometheus_compact_prometheuscompactor_consolidate", "community": 80, "norm_label": ".consolidate()" @@ -2728,7 +2755,7 @@ "label": ".compact()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L248", + "source_location": "L271", "id": "prometheus_compact_prometheuscompactor_compact", "community": 80, "norm_label": ".compact()" @@ -2737,7 +2764,7 @@ "label": ".getEpisodes()", "file_type": "code", "source_file": "main/app/prometheus/compact.py", - "source_location": "L287", + "source_location": "L310", "id": "prometheus_compact_prometheuscompactor_getepisodes", "community": 80, "norm_label": ".getepisodes()" @@ -2845,7 +2872,7 @@ "label": "getMatrix()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L31", + "source_location": "L35", "id": "prometheus_memory_getmatrix", "community": 53, "norm_label": "getmatrix()" @@ -2854,7 +2881,7 @@ "label": "invalidateUser()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L49", + "source_location": "L53", "id": "prometheus_memory_invalidateuser", "community": 53, "norm_label": "invalidateuser()" @@ -2863,16 +2890,43 @@ "label": "clearAll()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L53", + "source_location": "L57", "id": "prometheus_memory_clearall", "community": 53, "norm_label": "clearall()" }, + { + "label": "MemoryCandidate", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L64", + "id": "prometheus_memory_memorycandidate", + "community": 140, + "norm_label": "memorycandidate" + }, + { + "label": "BaseModel", + "file_type": "code", + "source_file": "", + "source_location": "", + "id": "basemodel", + "community": 33, + "norm_label": "basemodel" + }, + { + "label": "newTokenCache()", + "file_type": "code", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L90", + "id": "prometheus_memory_newtokencache", + "community": 53, + "norm_label": "newtokencache()" + }, { "label": "getClient()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L76", + "source_location": "L97", "id": "prometheus_memory_getclient", "community": 53, "norm_label": "getclient()" @@ -2881,16 +2935,16 @@ "label": "minMax()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L83", + "source_location": "L104", "id": "prometheus_memory_minmax", - "community": 53, + "community": 13, "norm_label": "minmax()" }, { "label": "normalizeKey()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L92", + "source_location": "L113", "id": "prometheus_memory_normalizekey", "community": 53, "norm_label": "normalizekey()" @@ -2899,7 +2953,7 @@ "label": "findSimilarKey()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L99", + "source_location": "L120", "id": "prometheus_memory_findsimilarkey", "community": 53, "norm_label": "findsimilarkey()" @@ -2908,34 +2962,34 @@ "label": "scoreRow()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L122", + "source_location": "L140", "id": "prometheus_memory_scorerow", - "community": 53, + "community": 13, "norm_label": "scorerow()" }, { "label": "scoreRecency()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L134", + "source_location": "L152", "id": "prometheus_memory_scorerecency", - "community": 53, + "community": 13, "norm_label": "scorerecency()" }, { "label": "scoreCandidates()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L144", + "source_location": "L162", "id": "prometheus_memory_scorecandidates", - "community": 53, + "community": 13, "norm_label": "scorecandidates()" }, { "label": "sumTokens()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L161", + "source_location": "L179", "id": "prometheus_memory_sumtokens", "community": 53, "norm_label": "sumtokens()" @@ -2944,7 +2998,7 @@ "label": "PrometheusMemory", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L176", + "source_location": "L194", "id": "prometheus_memory_prometheusmemory", "community": 140, "norm_label": "prometheusmemory" @@ -2953,7 +3007,7 @@ "label": "getMemoryLimit()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L178", + "source_location": "L196", "id": "prometheus_memory_getmemorylimit", "community": 53, "norm_label": "getmemorylimit()" @@ -2962,7 +3016,7 @@ "label": "countMemories()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L184", + "source_location": "L202", "id": "prometheus_memory_countmemories", "community": 53, "norm_label": "countmemories()" @@ -2971,7 +3025,7 @@ "label": "touch()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L193", + "source_location": "L211", "id": "prometheus_memory_touch", "community": 53, "norm_label": "touch()" @@ -2980,7 +3034,7 @@ "label": "upsertMemory()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L204", + "source_location": "L222", "id": "prometheus_memory_upsertmemory", "community": 53, "norm_label": "upsertmemory()" @@ -2989,25 +3043,25 @@ "label": "search()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L268", + "source_location": "L286", "id": "prometheus_memory_search", - "community": 53, + "community": 13, "norm_label": "search()" }, { "label": "fullTextSearch()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L331", + "source_location": "L349", "id": "prometheus_memory_fulltextsearch", - "community": 53, + "community": 13, "norm_label": "fulltextsearch()" }, { "label": "getUserMemories()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L389", + "source_location": "L407", "id": "prometheus_memory_getusermemories", "community": 27, "norm_label": "getusermemories()" @@ -3016,7 +3070,7 @@ "label": "deleteMemory()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L414", + "source_location": "L432", "id": "prometheus_memory_deletememory", "community": 53, "norm_label": "deletememory()" @@ -3025,7 +3079,7 @@ "label": "extract()", "file_type": "code", "source_file": "main/app/prometheus/memory.py", - "source_location": "L432", + "source_location": "L450", "id": "prometheus_memory_extract", "community": 53, "norm_label": "extract()" @@ -3187,7 +3241,7 @@ "label": "StreamChannel", "file_type": "code", "source_file": "main/app/prometheus/stream_bus.py", - "source_location": "L11", + "source_location": "L14", "id": "prometheus_stream_bus_streamchannel", "community": 210, "norm_label": "streamchannel" @@ -3196,7 +3250,7 @@ "label": ".__init__()", "file_type": "code", "source_file": "main/app/prometheus/stream_bus.py", - "source_location": "L12", + "source_location": "L15", "id": "prometheus_stream_bus_streamchannel_init", "community": 210, "norm_label": ".__init__()" @@ -3205,7 +3259,7 @@ "label": ".publish()", "file_type": "code", "source_file": "main/app/prometheus/stream_bus.py", - "source_location": "L18", + "source_location": "L21", "id": "prometheus_stream_bus_streamchannel_publish", "community": 210, "norm_label": ".publish()" @@ -3214,7 +3268,7 @@ "label": "StreamBus", "file_type": "code", "source_file": "main/app/prometheus/stream_bus.py", - "source_location": "L29", + "source_location": "L32", "id": "prometheus_stream_bus_streambus", "community": 210, "norm_label": "streambus" @@ -3223,7 +3277,7 @@ "label": ".__init__()", "file_type": "code", "source_file": "main/app/prometheus/stream_bus.py", - "source_location": "L30", + "source_location": "L33", "id": "prometheus_stream_bus_streambus_init", "community": 210, "norm_label": ".__init__()" @@ -3232,7 +3286,7 @@ "label": ".getOrCreate()", "file_type": "code", "source_file": "main/app/prometheus/stream_bus.py", - "source_location": "L33", + "source_location": "L36", "id": "prometheus_stream_bus_streambus_getorcreate", "community": 210, "norm_label": ".getorcreate()" @@ -3241,7 +3295,7 @@ "label": ".publish()", "file_type": "code", "source_file": "main/app/prometheus/stream_bus.py", - "source_location": "L40", + "source_location": "L43", "id": "prometheus_stream_bus_streambus_publish", "community": 210, "norm_label": ".publish()" @@ -3250,7 +3304,7 @@ "label": ".subscribe()", "file_type": "code", "source_file": "main/app/prometheus/stream_bus.py", - "source_location": "L43", + "source_location": "L46", "id": "prometheus_stream_bus_streambus_subscribe", "community": 210, "norm_label": ".subscribe()" @@ -3259,7 +3313,7 @@ "label": ".unsubscribe()", "file_type": "code", "source_file": "main/app/prometheus/stream_bus.py", - "source_location": "L56", + "source_location": "L59", "id": "prometheus_stream_bus_streambus_unsubscribe", "community": 210, "norm_label": ".unsubscribe()" @@ -3268,16 +3322,34 @@ "label": ".startRun()", "file_type": "code", "source_file": "main/app/prometheus/stream_bus.py", - "source_location": "L61", + "source_location": "L64", "id": "prometheus_stream_bus_streambus_startrun", "community": 210, "norm_label": ".startrun()" }, + { + "label": ".eventGenerator()", + "file_type": "code", + "source_file": "main/app/prometheus/stream_bus.py", + "source_location": "L86", + "id": "prometheus_stream_bus_streambus_eventgenerator", + "community": 210, + "norm_label": ".eventgenerator()" + }, + { + "label": ".streamResponse()", + "file_type": "code", + "source_file": "main/app/prometheus/stream_bus.py", + "source_location": "L109", + "id": "prometheus_stream_bus_streambus_streamresponse", + "community": 210, + "norm_label": ".streamresponse()" + }, { "label": ".forward()", "file_type": "code", "source_file": "main/app/prometheus/stream_bus.py", - "source_location": "L83", + "source_location": "L112", "id": "prometheus_stream_bus_streambus_forward", "community": 210, "norm_label": ".forward()" @@ -3288,7 +3360,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L1", "id": "main_app_prometheus_tools_py", - "community": 523, + "community": 563, "norm_label": "tools.py" }, { @@ -3306,7 +3378,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L51", "id": "prometheus_tools_save_memory", - "community": 90, + "community": 497, "norm_label": "save_memory()" }, { @@ -3315,7 +3387,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L93", "id": "prometheus_tools_execute_code", - "community": 101, + "community": 487, "norm_label": "execute_code()" }, { @@ -3324,7 +3396,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L114", "id": "prometheus_tools_read_file", - "community": 500, + "community": 564, "norm_label": "read_file()" }, { @@ -3342,7 +3414,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L144", "id": "prometheus_tools_list_files", - "community": 162, + "community": 523, "norm_label": "list_files()" }, { @@ -3378,7 +3450,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L52", "id": "prometheus_tools_rationale_52", - "community": 90, + "community": 497, "norm_label": "store a memory about the user's preferences, analysis results, or feedback." }, { @@ -3387,7 +3459,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L94", "id": "prometheus_tools_rationale_94", - "community": 101, + "community": 487, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis," }, { @@ -3396,7 +3468,7 @@ "source_file": "main/app/prometheus/tools.py", "source_location": "L115", "id": "prometheus_tools_rationale_115", - "community": 500, + "community": 564, "norm_label": "read a file from the workspace. args: path: path to the file (e." }, { @@ -3450,7 +3522,7 @@ "source_file": "main/app/prometheus/vector.py", "source_location": "L15", "id": "prometheus_vector_embed", - "community": 53, + "community": 13, "norm_label": "embed()" }, { @@ -3513,7 +3585,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L1", "id": "main_app_scraper_b3_scraper_py", - "community": 72, + "community": 234, "norm_label": "scraper.py" }, { @@ -3522,7 +3594,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L32", "id": "scraper_b3_scraper_getcurrentselic", - "community": 72, + "community": 234, "norm_label": "getcurrentselic()" }, { @@ -3531,7 +3603,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L42", "id": "scraper_b3_scraper_b3scraper", - "community": 72, + "community": 539, "norm_label": "b3scraper" }, { @@ -3540,7 +3612,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L43", "id": "scraper_b3_scraper_b3scraper_init", - "community": 72, + "community": 234, "norm_label": ".__init__()" }, { @@ -3549,7 +3621,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L57", "id": "scraper_b3_scraper_getinitialdata", - "community": 72, + "community": 234, "norm_label": "getinitialdata()" }, { @@ -3558,7 +3630,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L112", "id": "scraper_b3_scraper_historicalrentability", - "community": 72, + "community": 234, "norm_label": "historicalrentability()" }, { @@ -3567,7 +3639,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L135", "id": "scraper_b3_scraper_historicaldividends", - "community": 72, + "community": 234, "norm_label": "historicaldividends()" }, { @@ -3576,7 +3648,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L166", "id": "scraper_b3_scraper_historicaldividendyields", - "community": 72, + "community": 234, "norm_label": "historicaldividendyields()" }, { @@ -3585,7 +3657,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L194", "id": "scraper_b3_scraper_historicalrevenue", - "community": 72, + "community": 234, "norm_label": "historicalrevenue()" }, { @@ -3594,7 +3666,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L215", "id": "scraper_b3_scraper_historicalcotationprofits", - "community": 72, + "community": 234, "norm_label": "historicalcotationprofits()" }, { @@ -3603,7 +3675,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L228", "id": "scraper_b3_scraper_b3scraper_historicalcotationprofits_oceans14", - "community": 72, + "community": 539, "norm_label": ".historicalcotationprofits_oceans14()" }, { @@ -3612,7 +3684,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L241", "id": "scraper_b3_scraper_historicalcotations", - "community": 72, + "community": 234, "norm_label": "historicalcotations()" }, { @@ -3621,7 +3693,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L258", "id": "scraper_b3_scraper_tagalong", - "community": 72, + "community": 234, "norm_label": "tagalong()" }, { @@ -3630,7 +3702,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L283", "id": "scraper_b3_scraper_stocknews", - "community": 72, + "community": 234, "norm_label": "stocknews()" }, { @@ -3639,7 +3711,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L296", "id": "scraper_b3_scraper_b3scraper_fundamentalindicators", - "community": 72, + "community": 539, "norm_label": ".fundamentalindicators()" }, { @@ -3648,7 +3720,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L419", "id": "scraper_b3_scraper_b3scraper_processticker", - "community": 72, + "community": 539, "norm_label": ".processticker()" }, { @@ -3657,7 +3729,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L450", "id": "scraper_b3_scraper_b3scraper_scrapestocks", - "community": 72, + "community": 539, "norm_label": ".scrapestocks()" }, { @@ -3666,7 +3738,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L497", "id": "scraper_b3_scraper_b3scraper_reordercolumns", - "community": 72, + "community": 539, "norm_label": ".reordercolumns()" }, { @@ -3675,7 +3747,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L506", "id": "scraper_b3_scraper_b3scraper_serializecomplextypes", - "community": 72, + "community": 539, "norm_label": ".serializecomplextypes()" }, { @@ -3684,7 +3756,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L525", "id": "scraper_b3_scraper_b3scraper_exportjson", - "community": 72, + "community": 539, "norm_label": ".exportjson()" }, { @@ -3693,7 +3765,7 @@ "source_file": "main/app/scraper_b3/scraper.py", "source_location": "L533", "id": "scraper_b3_scraper_b3scraper_exportmysql", - "community": 72, + "community": 539, "norm_label": ".exportmysql()" }, { @@ -3702,7 +3774,7 @@ "source_file": "main/app/scraper_b3/xango.py", "source_location": "L1", "id": "main_app_scraper_b3_xango_py", - "community": 72, + "community": 234, "norm_label": "xango.py" }, { @@ -3711,7 +3783,7 @@ "source_file": "main/app/scraper_b3/xango.py", "source_location": "L15", "id": "scraper_b3_xango_calculateinvestingscore", - "community": 72, + "community": 234, "norm_label": "calculateinvestingscore()" }, { @@ -3727,7 +3799,7 @@ "label": "optimizeDtypes()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L39", + "source_location": "L40", "id": "stocks_api_cache_optimizedtypes", "community": 82, "norm_label": "optimizedtypes()" @@ -3736,7 +3808,7 @@ "label": "arrowTypeFor()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L59", + "source_location": "L60", "id": "stocks_api_cache_arrowtypefor", "community": 82, "norm_label": "arrowtypefor()" @@ -3745,7 +3817,7 @@ "label": "buildFeatherCache()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L70", + "source_location": "L77", "id": "stocks_api_cache_buildfeathercache", "community": 82, "norm_label": "buildfeathercache()" @@ -3754,7 +3826,7 @@ "label": "tryBuildLock()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L165", + "source_location": "L168", "id": "stocks_api_cache_trybuildlock", "community": 82, "norm_label": "trybuildlock()" @@ -3763,7 +3835,7 @@ "label": "sortCacheFrame()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L182", + "source_location": "L185", "id": "stocks_api_cache_sortcacheframe", "community": 82, "norm_label": "sortcacheframe()" @@ -3772,7 +3844,7 @@ "label": "buildTickerIndex()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L192", + "source_location": "L195", "id": "stocks_api_cache_buildtickerindex", "community": 82, "norm_label": "buildtickerindex()" @@ -3781,7 +3853,7 @@ "label": "StocksCacheManager", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L201", + "source_location": "L204", "id": "stocks_api_cache_stockscachemanager", "community": 42, "norm_label": "stockscachemanager" @@ -3790,7 +3862,7 @@ "label": ".__init__()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L202", + "source_location": "L205", "id": "stocks_api_cache_stockscachemanager_init", "community": 42, "norm_label": ".__init__()" @@ -3799,7 +3871,7 @@ "label": ".snapshot()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L210", + "source_location": "L213", "id": "stocks_api_cache_stockscachemanager_snapshot", "community": 42, "norm_label": ".snapshot()" @@ -3808,16 +3880,16 @@ "label": ".cacheScheduler()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L214", + "source_location": "L217", "id": "stocks_api_cache_stockscachemanager_cachescheduler", - "community": 82, + "community": 72, "norm_label": ".cachescheduler()" }, { "label": ".loadFromFeather()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L225", + "source_location": "L228", "id": "stocks_api_cache_stockscachemanager_loadfromfeather", "community": 82, "norm_label": ".loadfromfeather()" @@ -3826,7 +3898,7 @@ "label": ".getCachedStocks()", "file_type": "code", "source_file": "main/app/stocks_api/cache.py", - "source_location": "L244", + "source_location": "L247", "id": "stocks_api_cache_stockscachemanager_getcachedstocks", "community": 82, "norm_label": ".getcachedstocks()" @@ -3934,7 +4006,7 @@ "label": "sanitizeNanValues()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L17", + "source_location": "L19", "id": "stocks_api_query_sanitizenanvalues", "community": 63, "norm_label": "sanitizenanvalues()" @@ -3943,7 +4015,7 @@ "label": "filterCotationColumn()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L33", + "source_location": "L35", "id": "stocks_api_query_filtercotationcolumn", "community": 22, "norm_label": "filtercotationcolumn()" @@ -3952,7 +4024,7 @@ "label": "baseFrame()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L53", + "source_location": "L55", "id": "stocks_api_query_baseframe", "community": 517, "norm_label": "baseframe()" @@ -3961,7 +4033,7 @@ "label": "validateFields()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L66", + "source_location": "L68", "id": "stocks_api_query_validatefields", "community": 517, "norm_label": "validatefields()" @@ -3970,7 +4042,7 @@ "label": "envelope()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L79", + "source_location": "L81", "id": "stocks_api_query_envelope", "community": 517, "norm_label": "envelope()" @@ -3979,7 +4051,7 @@ "label": "finalize()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L90", + "source_location": "L92", "id": "stocks_api_query_finalize", "community": 517, "norm_label": "finalize()" @@ -3988,7 +4060,7 @@ "label": "deserializeJsonColumns()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L123", + "source_location": "L125", "id": "stocks_api_query_deserializejsoncolumns", "community": 517, "norm_label": "deserializejsoncolumns()" @@ -3997,7 +4069,7 @@ "label": "filterBySearchTerms()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L151", + "source_location": "L153", "id": "stocks_api_query_filterbysearchterms", "community": 517, "norm_label": "filterbysearchterms()" @@ -4006,7 +4078,7 @@ "label": "queryHistorical()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L169", + "source_location": "L171", "id": "stocks_api_query_queryhistorical", "community": 517, "norm_label": "queryhistorical()" @@ -4015,7 +4087,7 @@ "label": "queryFundamental()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L226", + "source_location": "L228", "id": "stocks_api_query_queryfundamental", "community": 517, "norm_label": "queryfundamental()" @@ -4024,18 +4096,36 @@ "label": "queryCotations()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L289", + "source_location": "L291", "id": "stocks_api_query_querycotations", "community": 517, "norm_label": "querycotations()" }, + { + "label": "isTransientLiveError()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L332", + "id": "stocks_api_query_istransientliveerror", + "community": 517, + "norm_label": "istransientliveerror()" + }, + { + "label": "fetchLivePayload()", + "file_type": "code", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L347", + "id": "stocks_api_query_fetchlivepayload", + "community": 517, + "norm_label": "fetchlivepayload()" + }, { "label": "queryLiveCotation()", "file_type": "code", "source_file": "main/app/stocks_api/query.py", - "source_location": "L330", + "source_location": "L356", "id": "stocks_api_query_querylivecotation", - "community": 81, + "community": 517, "norm_label": "querylivecotation()" }, { @@ -4141,7 +4231,7 @@ "label": "UserManager", "file_type": "code", "source_file": "main/app/user/user.py", - "source_location": "L14", + "source_location": "L15", "id": "user_user_usermanager", "community": 498, "norm_label": "usermanager" @@ -4150,7 +4240,7 @@ "label": "getRolesList()", "file_type": "code", "source_file": "main/app/user/user.py", - "source_location": "L16", + "source_location": "L17", "id": "user_user_getroleslist", "community": 519, "norm_label": "getroleslist()" @@ -4159,7 +4249,7 @@ "label": "getCurrentUser()", "file_type": "code", "source_file": "main/app/user/user.py", - "source_location": "L22", + "source_location": "L23", "id": "user_user_getcurrentuser", "community": 519, "norm_label": "getcurrentuser()" @@ -4242,7 +4332,7 @@ "source_file": "main/controller/authentication_controller.py", "source_location": "L155", "id": "controller_authentication_controller_googlelogin", - "community": 58, + "community": 474, "norm_label": "googlelogin()" }, { @@ -4368,7 +4458,7 @@ "source_file": "main/controller/stocksapi_controller.py", "source_location": "L1", "id": "main_controller_stocksapi_controller_py", - "community": 54, + "community": 197, "norm_label": "stocksapi_controller.py" }, { @@ -4377,7 +4467,7 @@ "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", "id": "controller_stocksapi_controller_health", - "community": 54, + "community": 197, "norm_label": "health()" }, { @@ -4737,7 +4827,7 @@ "source_file": "main/service/authentication_service.py", "source_location": "L1", "id": "main_service_authentication_service_py", - "community": 215, + "community": 59, "norm_label": "authentication_service.py" }, { @@ -4746,7 +4836,7 @@ "source_file": "main/service/authentication_service.py", "source_location": "L9", "id": "service_authentication_service_authenticationservice", - "community": 215, + "community": 140, "norm_label": "authenticationservice" }, { @@ -4755,7 +4845,7 @@ "source_file": "main/service/authentication_service.py", "source_location": "L11", "id": "service_authentication_service_initialize", - "community": 215, + "community": 59, "norm_label": "initialize()" }, { @@ -4764,7 +4854,7 @@ "source_file": "main/service/prometheus_service.py", "source_location": "L1", "id": "main_service_prometheus_service_py", - "community": 110, + "community": 72, "norm_label": "prometheus_service.py" }, { @@ -4773,7 +4863,7 @@ "source_file": "main/service/prometheus_service.py", "source_location": "L23", "id": "service_prometheus_service_memorymaintenance", - "community": 234, + "community": 518, "norm_label": "memorymaintenance()" }, { @@ -4791,7 +4881,7 @@ "source_file": "main/service/prometheus_service.py", "source_location": "L67", "id": "service_prometheus_service_initialize", - "community": 110, + "community": 72, "norm_label": "initialize()" }, { @@ -4800,7 +4890,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L1", "id": "main_service_scraper_service_py", - "community": 72, + "community": 575, "norm_label": "scraper_service.py" }, { @@ -4809,7 +4899,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L13", "id": "service_scraper_service_runscraper", - "community": 72, + "community": 575, "norm_label": "runscraper()" }, { @@ -4818,7 +4908,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L23", "id": "service_scraper_service_registerscraperjobs", - "community": 72, + "community": 575, "norm_label": "registerscraperjobs()" }, { @@ -4827,7 +4917,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L49", "id": "service_scraper_service_scraperservice", - "community": 72, + "community": 575, "norm_label": "scraperservice" }, { @@ -4836,7 +4926,7 @@ "source_file": "main/service/scraper_service.py", "source_location": "L51", "id": "service_scraper_service_initialize", - "community": 72, + "community": 575, "norm_label": "initialize()" }, { @@ -4845,7 +4935,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L1", "id": "main_service_stocksapi_service_py", - "community": 215, + "community": 59, "norm_label": "stocksapi_service.py" }, { @@ -4854,7 +4944,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L10", "id": "service_stocksapi_service_mcpdetectmiddleware", - "community": 215, + "community": 59, "norm_label": "mcpdetectmiddleware" }, { @@ -4863,7 +4953,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L11", "id": "service_stocksapi_service_mcpdetectmiddleware_init", - "community": 215, + "community": 59, "norm_label": ".__init__()" }, { @@ -4872,7 +4962,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L14", "id": "service_stocksapi_service_mcpdetectmiddleware_call", - "community": 215, + "community": 59, "norm_label": ".__call__()" }, { @@ -4881,7 +4971,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L25", "id": "service_stocksapi_service_stocksapiservice", - "community": 215, + "community": 59, "norm_label": "stocksapiservice" }, { @@ -4890,7 +4980,7 @@ "source_file": "main/service/stocksapi_service.py", "source_location": "L27", "id": "service_stocksapi_service_initialize", - "community": 215, + "community": 59, "norm_label": "initialize()" }, { @@ -4899,7 +4989,7 @@ "source_file": "main/service/user_service.py", "source_location": "L1", "id": "main_service_user_service_py", - "community": 110, + "community": 72, "norm_label": "user_service.py" }, { @@ -4908,7 +4998,7 @@ "source_file": "main/service/user_service.py", "source_location": "L17", "id": "service_user_service_removeinactivesessions", - "community": 110, + "community": 72, "norm_label": "removeinactivesessions()" }, { @@ -4917,7 +5007,7 @@ "source_file": "main/service/user_service.py", "source_location": "L42", "id": "service_user_service_userservice", - "community": 110, + "community": 72, "norm_label": "userservice" }, { @@ -4926,7 +5016,7 @@ "source_file": "main/service/user_service.py", "source_location": "L44", "id": "service_user_service_initialize", - "community": 110, + "community": 72, "norm_label": "initialize()" }, { @@ -4935,7 +5025,7 @@ "source_file": "main/utils/connectivity.py", "source_location": "L1", "id": "main_utils_connectivity_py", - "community": 491, + "community": 59, "norm_label": "connectivity.py" }, { @@ -4944,7 +5034,7 @@ "source_file": "main/utils/connectivity.py", "source_location": "L11", "id": "utils_connectivity_checkdatabaseconnection", - "community": 491, + "community": 59, "norm_label": "checkdatabaseconnection()" }, { @@ -4974,15 +5064,6 @@ "community": 33, "norm_label": "errorresponse" }, - { - "label": "BaseModel", - "file_type": "code", - "source_file": "", - "source_location": "", - "id": "basemodel", - "community": 33, - "norm_label": "basemodel" - }, { "label": "RequestContextFilter", "file_type": "code", @@ -5124,7 +5205,7 @@ "source_file": "main/utils/migrator.py", "source_location": "L1", "id": "main_utils_migrator_py", - "community": 491, + "community": 59, "norm_label": "migrator.py" }, { @@ -5133,7 +5214,7 @@ "source_file": "main/utils/migrator.py", "source_location": "L8", "id": "utils_migrator_runmigrations", - "community": 491, + "community": 59, "norm_label": "runmigrations()" }, { @@ -5178,7 +5259,7 @@ "source_file": "main/utils/roles.py", "source_location": "L1", "id": "main_utils_roles_py", - "community": 131, + "community": 498, "norm_label": "roles.py" }, { @@ -5205,7 +5286,7 @@ "source_file": "main/utils/roles.py", "source_location": "L13", "id": "utils_roles_all", - "community": 131, + "community": 59, "norm_label": "all()" }, { @@ -5223,7 +5304,7 @@ "source_file": "main/utils/roles.py", "source_location": "L29", "id": "utils_roles_checkaccess", - "community": 131, + "community": 498, "norm_label": "checkaccess()" }, { @@ -5232,7 +5313,7 @@ "source_file": "main/utils/roles.py", "source_location": "L42", "id": "utils_roles_requirepermission", - "community": 131, + "community": 498, "norm_label": "requirepermission()" }, { @@ -5241,7 +5322,7 @@ "source_file": "main/utils/scheduler.py", "source_location": "L1", "id": "main_utils_scheduler_py", - "community": 110, + "community": 72, "norm_label": "scheduler.py" }, { @@ -5250,7 +5331,7 @@ "source_file": "main/utils/scheduler.py", "source_location": "L10", "id": "utils_scheduler_getsharedscheduler", - "community": 110, + "community": 72, "norm_label": "getsharedscheduler()" }, { @@ -5259,7 +5340,7 @@ "source_file": "main/utils/scheduler.py", "source_location": "L19", "id": "utils_scheduler_registerjob", - "community": 110, + "community": 72, "norm_label": "registerjob()" }, { @@ -5268,7 +5349,7 @@ "source_file": "main/utils/service_manager.py", "source_location": "L1", "id": "main_utils_service_manager_py", - "community": 215, + "community": 59, "norm_label": "service_manager.py" }, { @@ -5277,7 +5358,7 @@ "source_file": "main/utils/service_manager.py", "source_location": "L19", "id": "utils_service_manager_getapp", - "community": 215, + "community": 59, "norm_label": "getapp()" }, { @@ -5286,7 +5367,7 @@ "source_file": "main/utils/service_manager.py", "source_location": "L43", "id": "utils_service_manager_runall", - "community": 215, + "community": 59, "norm_label": "runall()" }, { @@ -5857,58 +5938,13 @@ "norm_label": "graphify" }, { - "label": "PONYTAIL.md", - "file_type": "document", - "source_file": "PONYTAIL.md", - "source_location": "L1", - "id": "ponytail_md", - "community": 509, - "norm_label": "ponytail.md" - }, - { - "label": "PONYTAIL.md \u2014 proposed cuts, NOT applied. Approve before any edit.", - "file_type": "document", - "source_file": "PONYTAIL.md", - "source_location": "L1", - "id": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", - "community": 509, - "norm_label": "ponytail.md \u2014 proposed cuts, not applied. approve before any edit." - }, - { - "label": "Proposed (awaiting approval)", - "file_type": "document", - "source_file": "PONYTAIL.md", - "source_location": "L6", - "id": "server_ponytail_proposed_awaiting_approval", - "community": 509, - "norm_label": "proposed (awaiting approval)" - }, - { - "label": "Disputed (already litigated \u2014 needs your ruling to proceed)", - "file_type": "document", - "source_file": "PONYTAIL.md", - "source_location": "L64", - "id": "server_ponytail_disputed_already_litigated_needs_your_ruling_to_proceed", - "community": 509, - "norm_label": "disputed (already litigated \u2014 needs your ruling to proceed)" - }, - { - "label": "Held out (your ignore rules \u2014 not proposed)", - "file_type": "document", - "source_file": "PONYTAIL.md", - "source_location": "L72", - "id": "server_ponytail_held_out_your_ignore_rules_not_proposed", - "community": 509, - "norm_label": "held out (your ignore rules \u2014 not proposed)" - }, - { - "label": "Refused", + "label": "Swarm Delegation (default)", "file_type": "document", - "source_file": "PONYTAIL.md", - "source_location": "L78", - "id": "server_ponytail_refused", - "community": 509, - "norm_label": "refused" + "source_file": "AGENTS.md", + "source_location": "L60", + "id": "server_agents_swarm_delegation_default", + "community": 153, + "norm_label": "swarm delegation (default)" }, { "label": "README.md", @@ -8778,7 +8814,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L166", "id": "plans_2026_09_04_wallet_management_task_2_alembic_migration_for_wallet_tables", - "community": 497, + "community": 132, "norm_label": "task 2: alembic migration for wallet tables" }, { @@ -8787,7 +8823,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L189", "id": "plans_2026_09_04_wallet_management_codeblock_6", - "community": 497, + "community": 132, "norm_label": "code:python (\"\"\"add wallet_holdings and wallet_lots tables)" }, { @@ -8796,7 +8832,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L248", "id": "plans_2026_09_04_wallet_management_codeblock_7", - "community": 497, + "community": 132, "norm_label": "code:python (import main.models.wallet)" }, { @@ -8805,7 +8841,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L262", "id": "plans_2026_09_04_wallet_management_codeblock_8", - "community": 497, + "community": 132, "norm_label": "code:bash (git add migrations/versions/wallet_tables_20260904_add_walle)" }, { @@ -8814,7 +8850,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L269", "id": "plans_2026_09_04_wallet_management_task_3_pure_derivation_math", - "community": 132, + "community": 491, "norm_label": "task 3: pure derivation math" }, { @@ -8823,7 +8859,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L281", "id": "plans_2026_09_04_wallet_management_codeblock_9", - "community": 132, + "community": 491, "norm_label": "code:python (from datetime import date)" }, { @@ -8832,7 +8868,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L325", "id": "plans_2026_09_04_wallet_management_codeblock_10", - "community": 132, + "community": 491, "norm_label": "code:python (from dataclasses import dataclass)" }, { @@ -8841,7 +8877,7 @@ "source_file": "docs/superpowers/plans/2026-09-04-wallet-management.md", "source_location": "L384", "id": "plans_2026_09_04_wallet_management_codeblock_11", - "community": 132, + "community": 491, "norm_label": "code:bash (git add main/app/wallet/__init__.py main/app/wallet/math.py )" }, { @@ -9510,6 +9546,141 @@ "community": 181, "norm_label": "code:bash (git rm scripts/backfill_embedding_vector.py)" }, + { + "label": "2026-09-15-adopt-libs.md", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L1", + "id": "docs_superpowers_plans_2026_09_15_adopt_libs_md", + "community": 90, + "norm_label": "2026-09-15-adopt-libs.md" + }, + { + "label": "Adopt-Libs Implementation Plan", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L1", + "id": "plans_2026_09_15_adopt_libs_adopt_libs_implementation_plan", + "community": 90, + "norm_label": "adopt-libs implementation plan" + }, + { + "label": "Global Constraints", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L13", + "id": "plans_2026_09_15_adopt_libs_global_constraints", + "community": 90, + "norm_label": "global constraints" + }, + { + "label": "Task 1: tenacity replaces bespoke retries", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L24", + "id": "plans_2026_09_15_adopt_libs_task_1_tenacity_replaces_bespoke_retries", + "community": 90, + "norm_label": "task 1: tenacity replaces bespoke retries" + }, + { + "label": "code:python (from tenacity import retry, retry_if_exception_type, stop_af)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L38", + "id": "plans_2026_09_15_adopt_libs_codeblock_1", + "community": 90, + "norm_label": "code:python (from tenacity import retry, retry_if_exception_type, stop_af)" + }, + { + "label": "code:bash (git add main/app/stocks_api/cache.py main/app/stocks_api/que)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L51", + "id": "plans_2026_09_15_adopt_libs_codeblock_2", + "community": 90, + "norm_label": "code:bash (git add main/app/stocks_api/cache.py main/app/stocks_api/que)" + }, + { + "label": "Task 2: cashews native (probe first)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L56", + "id": "plans_2026_09_15_adopt_libs_task_2_cashews_native_probe_first", + "community": 90, + "norm_label": "task 2: cashews native (probe first)" + }, + { + "label": "code:bash (git commit -m \"use native cashews cache decorator\")", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L72", + "id": "plans_2026_09_15_adopt_libs_codeblock_3", + "community": 90, + "norm_label": "code:bash (git commit -m \"use native cashews cache decorator\")" + }, + { + "label": "Task 3: pydantic validates LLM extraction JSON", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L76", + "id": "plans_2026_09_15_adopt_libs_task_3_pydantic_validates_llm_extraction_json", + "community": 90, + "norm_label": "task 3: pydantic validates llm extraction json" + }, + { + "label": "code:python (from pydantic import BaseModel, TypeAdapter)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L88", + "id": "plans_2026_09_15_adopt_libs_codeblock_4", + "community": 90, + "norm_label": "code:python (from pydantic import basemodel, typeadapter)" + }, + { + "label": "Task 4: sse-starlette replaces hand SSE bus", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L102", + "id": "plans_2026_09_15_adopt_libs_task_4_sse_starlette_replaces_hand_sse_bus", + "community": 90, + "norm_label": "task 4: sse-starlette replaces hand sse bus" + }, + { + "label": "Task 5: rapidfuzz memory key dedup", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L117", + "id": "plans_2026_09_15_adopt_libs_task_5_rapidfuzz_memory_key_dedup", + "community": 90, + "norm_label": "task 5: rapidfuzz memory key dedup" + }, + { + "label": "Task 6: cachetools bounds token cache", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L132", + "id": "plans_2026_09_15_adopt_libs_task_6_cachetools_bounds_token_cache", + "community": 90, + "norm_label": "task 6: cachetools bounds token cache" + }, + { + "label": "Task 7: user-agents fills device fields (OPTIONAL)", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L143", + "id": "plans_2026_09_15_adopt_libs_task_7_user_agents_fills_device_fields_optional", + "community": 90, + "norm_label": "task 7: user-agents fills device fields (optional)" + }, + { + "label": "Task 8: pytest plugin set", + "file_type": "document", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L154", + "id": "plans_2026_09_15_adopt_libs_task_8_pytest_plugin_set", + "community": 90, + "norm_label": "task 8: pytest plugin set" + }, { "label": "2026-09-04-wallet-design.md", "file_type": "document", @@ -9663,6 +9834,60 @@ "community": 94, "norm_label": "spec self-review" }, + { + "label": "PONYTAIL.md", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L1", + "community": 509, + "norm_label": "ponytail.md", + "id": "ponytail_md" + }, + { + "label": "PONYTAIL.md \u2014 proposed cuts, NOT applied. Approve before any edit.", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L1", + "community": 509, + "norm_label": "ponytail.md \u2014 proposed cuts, not applied. approve before any edit.", + "id": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit" + }, + { + "label": "Proposed (awaiting approval)", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L6", + "community": 509, + "norm_label": "proposed (awaiting approval)", + "id": "server_ponytail_proposed_awaiting_approval" + }, + { + "label": "Disputed (already litigated \u2014 needs your ruling to proceed)", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L64", + "community": 509, + "norm_label": "disputed (already litigated \u2014 needs your ruling to proceed)", + "id": "server_ponytail_disputed_already_litigated_needs_your_ruling_to_proceed" + }, + { + "label": "Held out (your ignore rules \u2014 not proposed)", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L72", + "community": 509, + "norm_label": "held out (your ignore rules \u2014 not proposed)", + "id": "server_ponytail_held_out_your_ignore_rules_not_proposed" + }, + { + "label": "Refused", + "file_type": "document", + "source_file": "PONYTAIL.md", + "source_location": "L78", + "community": 509, + "norm_label": "refused", + "id": "server_ponytail_refused" + }, { "label": "getDeviceName()", "file_type": "code", @@ -9911,7 +10136,7 @@ "file_type": "code", "source_file": "main/app/prometheus/memory.py", "source_location": "L333", - "community": 53, + "community": 13, "norm_label": "searchasync()", "id": "prometheus_memory_searchasync" }, @@ -9938,7 +10163,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L50", - "community": 90, + "community": 497, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_50" }, @@ -9947,7 +10172,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L91", - "community": 101, + "community": 487, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", "id": "prometheus_tools_rationale_91" }, @@ -9956,7 +10181,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L112", - "community": 500, + "community": 564, "norm_label": "read a file from the workspace. args: path: path to the file (e.", "id": "prometheus_tools_rationale_112" }, @@ -9974,7 +10199,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L142", - "community": 162, + "community": 563, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_142" }, @@ -10028,7 +10253,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L49", - "community": 90, + "community": 497, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_49" }, @@ -10037,7 +10262,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L90", - "community": 536, + "community": 487, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", "id": "prometheus_tools_rationale_90" }, @@ -10046,7 +10271,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L111", - "community": 500, + "community": 487, "norm_label": "read a file from the workspace. args: path: path to the file (e.", "id": "prometheus_tools_rationale_111" }, @@ -10064,7 +10289,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L141", - "community": 162, + "community": 523, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_141" }, @@ -10091,7 +10316,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", - "community": 54, + "community": 197, "norm_label": "jsonbytesresponse", "id": "controller_stocksapi_controller_jsonbytesresponse" }, @@ -10100,7 +10325,7 @@ "file_type": "code", "source_file": "", "source_location": "", - "community": 54, + "community": 197, "norm_label": "fastapiresponse", "id": "fastapiresponse" }, @@ -10109,7 +10334,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L26", - "community": 54, + "community": 197, "norm_label": ".render()", "id": "controller_stocksapi_controller_jsonbytesresponse_render" }, @@ -10946,7 +11171,7 @@ "file_type": "rationale", "source_file": "main/service/scraper_service.py", "source_location": "L23", - "community": 72, + "community": 575, "norm_label": "p5: register the scraper cron jobs on the shared scheduler. kept in this", "id": "service_scraper_service_rationale_23" }, @@ -10955,7 +11180,7 @@ "file_type": "code", "source_file": "main/service/user_service.py", "source_location": "L46", - "community": 110, + "community": 72, "norm_label": "registersessioncleanupjobs()", "id": "service_user_service_registersessioncleanupjobs" }, @@ -10964,7 +11189,7 @@ "file_type": "rationale", "source_file": "main/service/user_service.py", "source_location": "L47", - "community": 110, + "community": 72, "norm_label": "p5: register the session-cleanup job on the shared scheduler. kept in thi", "id": "service_user_service_rationale_47" }, @@ -12098,7 +12323,7 @@ "file_type": "code", "source_file": "main/service/prometheus_service.py", "source_location": "L60", - "community": 110, + "community": 72, "norm_label": "registermemorymaintenancejob()", "id": "service_prometheus_service_registermemorymaintenancejob" }, @@ -12107,7 +12332,7 @@ "file_type": "rationale", "source_file": "main/service/prometheus_service.py", "source_location": "L61", - "community": 110, + "community": 72, "norm_label": "p5: register memory maintenance on the shared scheduler. kept in this ser", "id": "service_prometheus_service_rationale_61" }, @@ -12116,7 +12341,7 @@ "file_type": "rationale", "source_file": "main/utils/scheduler.py", "source_location": "L1", - "community": 110, + "community": 72, "norm_label": "p5: single shared backgroundscheduler for all services. replaces the 4 per-serv", "id": "utils_scheduler_rationale_1" }, @@ -12125,7 +12350,7 @@ "file_type": "rationale", "source_file": "main/utils/scheduler.py", "source_location": "L33", - "community": 110, + "community": 72, "norm_label": "return the process-wide scheduler, starting it on first use.", "id": "utils_scheduler_rationale_33" }, @@ -12134,7 +12359,7 @@ "file_type": "rationale", "source_file": "main/utils/scheduler.py", "source_location": "L43", - "community": 110, + "community": 72, "norm_label": "register func on the shared scheduler (replaces any same-id job). trigger i", "id": "utils_scheduler_rationale_43" }, @@ -12350,7 +12575,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L54", - "community": 90, + "community": 497, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_54" }, @@ -12359,7 +12584,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L92", - "community": 101, + "community": 487, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", "id": "prometheus_tools_rationale_92" }, @@ -12368,7 +12593,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L113", - "community": 500, + "community": 564, "norm_label": "read a file from the workspace. args: path: path to the file (e.", "id": "prometheus_tools_rationale_113" }, @@ -12386,7 +12611,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L143", - "community": 162, + "community": 523, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_143" }, @@ -12467,7 +12692,7 @@ "file_type": "code", "source_file": "main/utils/service_manager.py", "source_location": "L15", - "community": 215, + "community": 140, "norm_label": "servicemanager", "id": "utils_service_manager_servicemanager" }, @@ -12629,7 +12854,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L135", - "community": 162, + "community": 523, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_135" }, @@ -12926,7 +13151,7 @@ "file_type": "rationale", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L24", - "community": 54, + "community": 197, "norm_label": "sends pre-serialized json bytes without re-encoding (cache-friendly).", "id": "controller_stocksapi_controller_rationale_24" }, @@ -13070,7 +13295,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L323", - "community": 54, + "community": 197, "norm_label": "generatekey()", "id": "controller_stocksapi_controller_generatekey" }, @@ -14906,7 +15131,7 @@ "file_type": "code", "source_file": "main/app/prometheus/tools.py", "source_location": "L104", - "community": 101, + "community": 487, "norm_label": "set_state()", "id": "prometheus_tools_set_state" }, @@ -14915,7 +15140,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L105", - "community": 101, + "community": 487, "norm_label": "store a value in the harness state for this session. use this to save inter", "id": "prometheus_tools_rationale_105" }, @@ -14924,7 +15149,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L123", - "community": 101, + "community": 487, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", "id": "prometheus_tools_rationale_123" }, @@ -14942,7 +15167,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L168", - "community": 162, + "community": 523, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_168" }, @@ -15122,7 +15347,7 @@ "file_type": "code", "source_file": "main/utils/connectivity.py", "source_location": "L13", - "community": 491, + "community": 59, "norm_label": "checksingledb()", "id": "utils_connectivity_checksingledb" }, @@ -16310,7 +16535,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L44", - "community": 90, + "community": 497, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_44" }, @@ -16328,7 +16553,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L96", - "community": 101, + "community": 487, "norm_label": "store a value in the harness state for this session. use this to save inter", "id": "prometheus_tools_rationale_96" }, @@ -16337,7 +16562,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L114", - "community": 101, + "community": 487, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", "id": "prometheus_tools_rationale_114" }, @@ -16355,7 +16580,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L159", - "community": 162, + "community": 523, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_159" }, @@ -22592,7 +22817,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L81", - "community": 251, + "community": 137, "norm_label": "stocks_http_client()", "id": "tests_conftest_stocks_http_client" }, @@ -22601,7 +22826,7 @@ "file_type": "code", "source_file": "tests/conftest.py", "source_location": "L106", - "community": 251, + "community": 137, "norm_label": "client()", "id": "tests_conftest_client" }, @@ -22628,7 +22853,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L82", - "community": 251, + "community": 137, "norm_label": "testclient with stocks router + verifyapikey + getcurrentuser overrides.", "id": "tests_conftest_rationale_82" }, @@ -22637,7 +22862,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L107", - "community": 251, + "community": 137, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_107" }, @@ -22745,7 +22970,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L7", - "community": 529, + "community": 500, "norm_label": "testbuildsystempromptstate", "id": "tests_test_agent_state_integration_testbuildsystempromptstate" }, @@ -22754,7 +22979,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L8", - "community": 529, + "community": 500, "norm_label": ".test_build_system_prompt_no_state()", "id": "tests_test_agent_state_integration_testbuildsystempromptstate_test_build_system_prompt_no_state" }, @@ -22763,7 +22988,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L13", - "community": 529, + "community": 500, "norm_label": ".test_build_system_prompt_with_state()", "id": "tests_test_agent_state_integration_testbuildsystempromptstate_test_build_system_prompt_with_state" }, @@ -22772,7 +22997,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L21", - "community": 529, + "community": 500, "norm_label": ".test_build_system_prompt_empty_state()", "id": "tests_test_agent_state_integration_testbuildsystempromptstate_test_build_system_prompt_empty_state" }, @@ -22781,7 +23006,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L27", - "community": 529, + "community": 500, "norm_label": ".test_build_system_prompt_state_after_memories()", "id": "tests_test_agent_state_integration_testbuildsystempromptstate_test_build_system_prompt_state_after_memories" }, @@ -22790,7 +23015,7 @@ "file_type": "code", "source_file": "tests/test_agent_state_integration.py", "source_location": "L37", - "community": 529, + "community": 500, "norm_label": ".test_build_system_prompt_multiple_state_entries()", "id": "tests_test_agent_state_integration_testbuildsystempromptstate_test_build_system_prompt_multiple_state_entries" }, @@ -22871,7 +23096,7 @@ "file_type": "rationale", "source_file": "tests/test_agent_state_integration.py", "source_location": "L9", - "community": 529, + "community": 500, "norm_label": "system prompt should work without state parameter.", "id": "tests_test_agent_state_integration_rationale_9" }, @@ -22880,7 +23105,7 @@ "file_type": "rationale", "source_file": "tests/test_agent_state_integration.py", "source_location": "L14", - "community": 529, + "community": 500, "norm_label": "system prompt should include state context when provided.", "id": "tests_test_agent_state_integration_rationale_14" }, @@ -22889,7 +23114,7 @@ "file_type": "rationale", "source_file": "tests/test_agent_state_integration.py", "source_location": "L22", - "community": 529, + "community": 500, "norm_label": "system prompt should not include state section when empty.", "id": "tests_test_agent_state_integration_rationale_22" }, @@ -22898,7 +23123,7 @@ "file_type": "rationale", "source_file": "tests/test_agent_state_integration.py", "source_location": "L28", - "community": 529, + "community": 500, "norm_label": "state section should appear after memories section.", "id": "tests_test_agent_state_integration_rationale_28" }, @@ -22907,7 +23132,7 @@ "file_type": "rationale", "source_file": "tests/test_agent_state_integration.py", "source_location": "L38", - "community": 529, + "community": 500, "norm_label": "all state entries should appear in the prompt.", "id": "tests_test_agent_state_integration_rationale_38" }, @@ -23051,7 +23276,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L220", - "community": 136, + "community": 110, "norm_label": "testverifyapikeyintegration", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration" }, @@ -23060,7 +23285,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L223", - "community": 136, + "community": 110, "norm_label": ".test_verify_api_key_success()", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration_test_verify_api_key_success" }, @@ -23069,7 +23294,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L238", - "community": 136, + "community": 110, "norm_label": ".test_verify_api_key_quota_exceeded()", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration_test_verify_api_key_quota_exceeded" }, @@ -23078,7 +23303,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L253", - "community": 136, + "community": 110, "norm_label": ".test_verify_api_key_invalid()", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration_test_verify_api_key_invalid" }, @@ -23087,7 +23312,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L264", - "community": 136, + "community": 110, "norm_label": ".test_verify_api_key_missing()", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration_test_verify_api_key_missing" }, @@ -23096,7 +23321,7 @@ "file_type": "code", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L275", - "community": 136, + "community": 110, "norm_label": ".test_verify_api_key_disabled()", "id": "tests_test_api_key_quota_atomic_testverifyapikeyintegration_test_verify_api_key_disabled" }, @@ -23195,7 +23420,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L221", - "community": 136, + "community": 110, "norm_label": "integration tests for the verifyapikey function.", "id": "tests_test_api_key_quota_atomic_rationale_221" }, @@ -23204,7 +23429,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L224", - "community": 136, + "community": 110, "norm_label": "test successful api key verification.", "id": "tests_test_api_key_quota_atomic_rationale_224" }, @@ -23213,7 +23438,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L239", - "community": 136, + "community": 110, "norm_label": "test api key verification when quota is exceeded.", "id": "tests_test_api_key_quota_atomic_rationale_239" }, @@ -23222,7 +23447,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L254", - "community": 136, + "community": 110, "norm_label": "test api key verification with invalid key.", "id": "tests_test_api_key_quota_atomic_rationale_254" }, @@ -23231,7 +23456,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L265", - "community": 136, + "community": 110, "norm_label": "test api key verification with missing key.", "id": "tests_test_api_key_quota_atomic_rationale_265" }, @@ -23240,7 +23465,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L276", - "community": 136, + "community": 110, "norm_label": "test that api key system can be disabled.", "id": "tests_test_api_key_quota_atomic_rationale_276" }, @@ -23249,7 +23474,7 @@ "file_type": "code", "source_file": "tests/test_auth_util.py", "source_location": "L1", - "community": 495, + "community": 43, "norm_label": "test_auth_util.py", "id": "tests_test_auth_util_py" }, @@ -23348,7 +23573,7 @@ "file_type": "code", "source_file": "tests/test_auth_util.py", "source_location": "L69", - "community": 495, + "community": 43, "norm_label": "testsessionexpiryconfig", "id": "tests_test_auth_util_testsessionexpiryconfig" }, @@ -23357,7 +23582,7 @@ "file_type": "code", "source_file": "tests/test_auth_util.py", "source_location": "L70", - "community": 495, + "community": 43, "norm_label": ".test_session_expiry_days_is_30()", "id": "tests_test_auth_util_testsessionexpiryconfig_test_session_expiry_days_is_30" }, @@ -23366,7 +23591,7 @@ "file_type": "code", "source_file": "tests/test_auth_util.py", "source_location": "L73", - "community": 495, + "community": 43, "norm_label": ".test_session_expiry_hours_calculation()", "id": "tests_test_auth_util_testsessionexpiryconfig_test_session_expiry_hours_calculation" }, @@ -23375,7 +23600,7 @@ "file_type": "code", "source_file": "tests/test_auth_util.py", "source_location": "L78", - "community": 495, + "community": 43, "norm_label": ".test_default_token_expiry_equals_30_days()", "id": "tests_test_auth_util_testsessionexpiryconfig_test_default_token_expiry_equals_30_days" }, @@ -23438,7 +23663,7 @@ "file_type": "code", "source_file": "tests/test_config.py", "source_location": "L1", - "community": 541, + "community": 102, "norm_label": "test_config.py", "id": "tests_test_config_py" }, @@ -23501,7 +23726,7 @@ "file_type": "code", "source_file": "tests/test_connectivity_coverage.py", "source_location": "L8", - "community": 566, + "community": 59, "norm_label": "testcheckmysqlconnection", "id": "tests_test_connectivity_coverage_testcheckmysqlconnection" }, @@ -23591,7 +23816,7 @@ "file_type": "code", "source_file": "tests/test_connectivity_coverage.py", "source_location": "L114", - "community": 564, + "community": 59, "norm_label": "testcheckserviceconnection", "id": "tests_test_connectivity_coverage_testcheckserviceconnection" }, @@ -23681,7 +23906,7 @@ "file_type": "rationale", "source_file": "tests/test_connectivity_coverage.py", "source_location": "L9", - "community": 566, + "community": 59, "norm_label": "checkmysqlconnection \u2014 success, errors, engine=none paths.", "id": "tests_test_connectivity_coverage_rationale_9" }, @@ -23690,7 +23915,7 @@ "file_type": "rationale", "source_file": "tests/test_connectivity_coverage.py", "source_location": "L115", - "community": 564, + "community": 59, "norm_label": "checkserviceconnection \u2014 success, not found, errors.", "id": "tests_test_connectivity_coverage_rationale_115" }, @@ -23726,7 +23951,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L57", - "community": 16, + "community": 99, "norm_label": "_make_prometheus_client()", "id": "tests_test_controllers_coverage_make_prometheus_client" }, @@ -23798,7 +24023,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L146", - "community": 498, + "community": 120, "norm_label": "testregisterendpoint", "id": "tests_test_controllers_coverage_testregisterendpoint" }, @@ -23843,7 +24068,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L215", - "community": 498, + "community": 120, "norm_label": "testloginendpoint", "id": "tests_test_controllers_coverage_testloginendpoint" }, @@ -23960,7 +24185,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L390", - "community": 498, + "community": 120, "norm_label": "testgooglecallback", "id": "tests_test_controllers_coverage_testgooglecallback" }, @@ -24239,7 +24464,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L849", - "community": 16, + "community": 99, "norm_label": "testprometheusgetsessions", "id": "tests_test_controllers_coverage_testprometheusgetsessions" }, @@ -24248,7 +24473,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L852", - "community": 16, + "community": 99, "norm_label": ".test_get_sessions()", "id": "tests_test_controllers_coverage_testprometheusgetsessions_test_get_sessions" }, @@ -24257,7 +24482,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L867", - "community": 16, + "community": 99, "norm_label": "testprometheuscreatesession", "id": "tests_test_controllers_coverage_testprometheuscreatesession" }, @@ -24266,7 +24491,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L870", - "community": 16, + "community": 99, "norm_label": ".test_create_session()", "id": "tests_test_controllers_coverage_testprometheuscreatesession_test_create_session" }, @@ -24311,7 +24536,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L915", - "community": 208, + "community": 104, "norm_label": "testprometheusgethistory", "id": "tests_test_controllers_coverage_testprometheusgethistory" }, @@ -24320,7 +24545,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L918", - "community": 208, + "community": 104, "norm_label": ".test_get_history_found()", "id": "tests_test_controllers_coverage_testprometheusgethistory_test_get_history_found" }, @@ -24329,7 +24554,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L962", - "community": 208, + "community": 104, "norm_label": ".test_get_history_not_found()", "id": "tests_test_controllers_coverage_testprometheusgethistory_test_get_history_not_found" }, @@ -24374,7 +24599,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1023", - "community": 16, + "community": 99, "norm_label": ".test_chat_new_session()", "id": "tests_test_controllers_coverage_testprometheuschat_test_chat_new_session" }, @@ -24383,7 +24608,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1042", - "community": 104, + "community": 16, "norm_label": ".test_chat_existing_session_verified()", "id": "tests_test_controllers_coverage_testprometheuschat_test_chat_existing_session_verified" }, @@ -24410,7 +24635,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1144", - "community": 539, + "community": 498, "norm_label": "teststocksapihealth", "id": "tests_test_controllers_coverage_teststocksapihealth" }, @@ -24419,7 +24644,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1147", - "community": 539, + "community": 498, "norm_label": ".test_health()", "id": "tests_test_controllers_coverage_teststocksapihealth_test_health" }, @@ -24428,7 +24653,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1158", - "community": 563, + "community": 14, "norm_label": "teststocksapihistorical", "id": "tests_test_controllers_coverage_teststocksapihistorical" }, @@ -24437,7 +24662,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1161", - "community": 563, + "community": 14, "norm_label": ".test_get_historical()", "id": "tests_test_controllers_coverage_teststocksapihistorical_test_get_historical" }, @@ -24518,7 +24743,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1249", - "community": 528, + "community": 493, "norm_label": ".test_add_role_already_has_role()", "id": "tests_test_controllers_coverage_testaddroletouser_test_add_role_already_has_role" }, @@ -24563,7 +24788,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1307", - "community": 528, + "community": 493, "norm_label": ".test_get_current_user_session_revoked()", "id": "tests_test_controllers_coverage_testgetcurrentuser_test_get_current_user_session_revoked" }, @@ -24599,7 +24824,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1381", - "community": 525, + "community": 498, "norm_label": "testhashpasswordempty", "id": "tests_test_controllers_coverage_testhashpasswordempty" }, @@ -24608,7 +24833,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1384", - "community": 525, + "community": 498, "norm_label": ".test_empty_password_raises()", "id": "tests_test_controllers_coverage_testhashpasswordempty_test_empty_password_raises" }, @@ -24617,7 +24842,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1391", - "community": 525, + "community": 524, "norm_label": "testverifyaccesstoken", "id": "tests_test_controllers_coverage_testverifyaccesstoken" }, @@ -24626,7 +24851,7 @@ "file_type": "code", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1394", - "community": 525, + "community": 524, "norm_label": ".test_expired_token()", "id": "tests_test_controllers_coverage_testverifyaccesstoken_test_expired_token" }, @@ -24707,7 +24932,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L58", - "community": 16, + "community": 99, "norm_label": "return (client, app) with prometheus router and mocked deps.", "id": "tests_test_controllers_coverage_rationale_58" }, @@ -24743,7 +24968,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L147", - "community": 498, + "community": 120, "norm_label": "covers lines 44-54, 63, 66-71: register success, valueerror, generic exception.", "id": "tests_test_controllers_coverage_rationale_147" }, @@ -24788,7 +25013,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L216", - "community": 498, + "community": 120, "norm_label": "covers lines 87-93, 102: login success and failure paths.", "id": "tests_test_controllers_coverage_rationale_216" }, @@ -24905,7 +25130,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L391", - "community": 498, + "community": 120, "norm_label": "covers lines 155-156, 158, 160-168, 170-177, 179-184, 186, 190-204: googlecallba", "id": "tests_test_controllers_coverage_rationale_391" }, @@ -25103,7 +25328,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L850", - "community": 16, + "community": 99, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_850" }, @@ -25112,7 +25337,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L868", - "community": 16, + "community": 99, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_868" }, @@ -25157,7 +25382,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L916", - "community": 208, + "community": 104, "norm_label": "covers lines 77, 83-84, 86: get /prometheus/history/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_916" }, @@ -25166,7 +25391,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L919", - "community": 208, + "community": 104, "norm_label": "covers lines 77, 86: session found with history.", "id": "tests_test_controllers_coverage_rationale_919" }, @@ -25175,7 +25400,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L963", - "community": 208, + "community": 104, "norm_label": "covers lines 83-84: session not found.", "id": "tests_test_controllers_coverage_rationale_963" }, @@ -25220,7 +25445,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1024", - "community": 16, + "community": 99, "norm_label": "covers lines 118-119: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1024" }, @@ -25229,7 +25454,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1043", - "community": 104, + "community": 16, "norm_label": "covers lines 120-121: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1043" }, @@ -25256,7 +25481,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1145", - "community": 539, + "community": 498, "norm_label": "covers line 18: get /stocks/health.", "id": "tests_test_controllers_coverage_rationale_1145" }, @@ -25265,7 +25490,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1159", - "community": 563, + "community": 14, "norm_label": "covers line 35: get /stocks/historical.", "id": "tests_test_controllers_coverage_rationale_1159" }, @@ -25337,7 +25562,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1250", - "community": 528, + "community": 14, "norm_label": "covers line 27: user already has the role.", "id": "tests_test_controllers_coverage_rationale_1250" }, @@ -25373,7 +25598,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1308", - "community": 528, + "community": 493, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1308" }, @@ -25409,7 +25634,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1382", - "community": 525, + "community": 524, "norm_label": "covers line 16: empty password raises valueerror.", "id": "tests_test_controllers_coverage_rationale_1382" }, @@ -25418,7 +25643,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1392", - "community": 525, + "community": 524, "norm_label": "covers lines 45-51: verifyaccesstoken with expired and invalid tokens.", "id": "tests_test_controllers_coverage_rationale_1392" }, @@ -25427,7 +25652,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1395", - "community": 525, + "community": 524, "norm_label": "covers lines 48-49: jwt.expiredsignatureerror.", "id": "tests_test_controllers_coverage_rationale_1395" }, @@ -26219,7 +26444,7 @@ "file_type": "code", "source_file": "tests/test_events.py", "source_location": "L1", - "community": 12, + "community": 101, "norm_label": "test_events.py", "id": "tests_test_events_py" }, @@ -26309,7 +26534,7 @@ "file_type": "rationale", "source_file": "tests/test_events.py", "source_location": "L1", - "community": 12, + "community": 101, "norm_label": "tests for looplogger \u2014 appends events to history json list.", "id": "tests_test_events_rationale_1" }, @@ -26327,7 +26552,7 @@ "file_type": "code", "source_file": "tests/test_harness_state.py", "source_location": "L1", - "community": 541, + "community": 93, "norm_label": "test_harness_state.py", "id": "tests_test_harness_state_py" }, @@ -26435,7 +26660,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L1", - "community": 541, + "community": 522, "norm_label": "test_http_session_coverage.py", "id": "tests_test_http_session_coverage_py" }, @@ -26444,7 +26669,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L8", - "community": 541, + "community": 522, "norm_label": "testgetsession", "id": "tests_test_http_session_coverage_testgetsession" }, @@ -26453,7 +26678,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L9", - "community": 541, + "community": 522, "norm_label": ".test_returns_same_session()", "id": "tests_test_http_session_coverage_testgetsession_test_returns_same_session" }, @@ -26462,7 +26687,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L16", - "community": 541, + "community": 522, "norm_label": ".test_returns_requests_session()", "id": "tests_test_http_session_coverage_testgetsession_test_returns_requests_session" }, @@ -26471,7 +26696,7 @@ "file_type": "rationale", "source_file": "tests/test_http_session_coverage.py", "source_location": "L1", - "community": 541, + "community": 522, "norm_label": "tests for main/utils/http_session.py \u2014 covers all branches.", "id": "tests_test_http_session_coverage_rationale_1" }, @@ -26876,7 +27101,7 @@ "file_type": "code", "source_file": "tests/test_logging_config_coverage.py", "source_location": "L103", - "community": 188, + "community": 122, "norm_label": "testsetuplogging", "id": "tests_test_logging_config_coverage_testsetuplogging" }, @@ -26912,7 +27137,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L1", - "community": 137, + "community": 140, "norm_label": "test_memory_dedup.py", "id": "tests_test_memory_dedup_py" }, @@ -26921,7 +27146,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L8", - "community": 137, + "community": 140, "norm_label": "_create_memory()", "id": "tests_test_memory_dedup_create_memory" }, @@ -26930,7 +27155,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L12", - "community": 137, + "community": 140, "norm_label": "_count_memories()", "id": "tests_test_memory_dedup_count_memories" }, @@ -26939,7 +27164,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L20", - "community": 137, + "community": 140, "norm_label": "_get_memory()", "id": "tests_test_memory_dedup_get_memory" }, @@ -26948,7 +27173,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L28", - "community": 137, + "community": 140, "norm_label": "testexactsamekeyupdates", "id": "tests_test_memory_dedup_testexactsamekeyupdates" }, @@ -26957,7 +27182,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L29", - "community": 137, + "community": 140, "norm_label": ".test_exact_same_key_updates()", "id": "tests_test_memory_dedup_testexactsamekeyupdates_test_exact_same_key_updates" }, @@ -26975,7 +27200,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L37", - "community": 137, + "community": 140, "norm_label": ".test_similar_key_merges()", "id": "tests_test_memory_dedup_testsimilarkeymerges_test_similar_key_merges" }, @@ -26993,7 +27218,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L47", - "community": 137, + "community": 140, "norm_label": ".test_different_keys_no_merge()", "id": "tests_test_memory_dedup_testdifferentkeysnomerge_test_different_keys_no_merge" }, @@ -27002,7 +27227,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L55", - "community": 137, + "community": 140, "norm_label": "testmergeboostsscore", "id": "tests_test_memory_dedup_testmergeboostsscore" }, @@ -27011,7 +27236,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L56", - "community": 137, + "community": 140, "norm_label": ".test_merge_boosts_score()", "id": "tests_test_memory_dedup_testmergeboostsscore_test_merge_boosts_score" }, @@ -27020,7 +27245,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L64", - "community": 137, + "community": 140, "norm_label": "testmergeincrementsaccess", "id": "tests_test_memory_dedup_testmergeincrementsaccess" }, @@ -27029,7 +27254,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L65", - "community": 137, + "community": 140, "norm_label": ".test_merge_increments_access()", "id": "tests_test_memory_dedup_testmergeincrementsaccess_test_merge_increments_access" }, @@ -27047,7 +27272,7 @@ "file_type": "code", "source_file": "tests/test_memory_dedup.py", "source_location": "L74", - "community": 137, + "community": 140, "norm_label": ".test_threshold_boundary()", "id": "tests_test_memory_dedup_testthresholdboundary_test_threshold_boundary" }, @@ -27056,7 +27281,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L38", - "community": 137, + "community": 140, "norm_label": "keys with jaccard > 0.8 should merge.", "id": "tests_test_memory_dedup_rationale_38" }, @@ -27065,7 +27290,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L48", - "community": 137, + "community": 140, "norm_label": "keys with low similarity should not merge.", "id": "tests_test_memory_dedup_rationale_48" }, @@ -27074,7 +27299,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L75", - "community": 137, + "community": 140, "norm_label": "keys with jaccard <= 0.8 should not merge.", "id": "tests_test_memory_dedup_rationale_75" }, @@ -27227,7 +27452,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L133", - "community": 234, + "community": 518, "norm_label": "testdecayandarchivetogether", "id": "tests_test_memory_maintenance_testdecayandarchivetogether" }, @@ -27236,7 +27461,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L134", - "community": 234, + "community": 518, "norm_label": ".test_decay_then_archive_check()", "id": "tests_test_memory_maintenance_testdecayandarchivetogether_test_decay_then_archive_check" }, @@ -27245,7 +27470,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L143", - "community": 234, + "community": 518, "norm_label": ".test_score_above_threshold_after_decay_not_archived()", "id": "tests_test_memory_maintenance_testdecayandarchivetogether_test_score_above_threshold_after_decay_not_archived" }, @@ -27254,7 +27479,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L150", - "community": 234, + "community": 518, "norm_label": ".test_score_just_below_threshold_archived()", "id": "tests_test_memory_maintenance_testdecayandarchivetogether_test_score_just_below_threshold_archived" }, @@ -27263,7 +27488,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L156", - "community": 234, + "community": 518, "norm_label": ".test_days_just_below_threshold_not_archived()", "id": "tests_test_memory_maintenance_testdecayandarchivetogether_test_days_just_below_threshold_not_archived" }, @@ -27272,7 +27497,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L163", - "community": 234, + "community": 518, "norm_label": ".test_days_just_above_threshold_archived()", "id": "tests_test_memory_maintenance_testdecayandarchivetogether_test_days_just_above_threshold_archived" }, @@ -27290,7 +27515,7 @@ "file_type": "code", "source_file": "tests/test_memory_maintenance.py", "source_location": "L171", - "community": 234, + "community": 518, "norm_label": ".test_no_memories_does_not_crash()", "id": "tests_test_memory_maintenance_testemptydatabase_test_no_memories_does_not_crash" }, @@ -27371,7 +27596,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L135", - "community": 234, + "community": 518, "norm_label": "decay happens first, then archive check with new scores.", "id": "tests_test_memory_maintenance_rationale_135" }, @@ -27380,7 +27605,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L144", - "community": 234, + "community": 518, "norm_label": "score that decays to >= threshold stays alive. 0.12 * 0.90 = 0.108 >= 0.1.", "id": "tests_test_memory_maintenance_rationale_144" }, @@ -27389,7 +27614,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L157", - "community": 234, + "community": 518, "norm_label": "89 days with low score \u2192 not archived (need > 90).", "id": "tests_test_memory_maintenance_rationale_157" }, @@ -27434,7 +27659,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L15", - "community": 574, + "community": 140, "norm_label": ".test_admin_user()", "id": "tests_test_memory_manager_testgetmemorylimit_test_admin_user" }, @@ -27452,7 +27677,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L20", - "community": 575, + "community": 140, "norm_label": ".test_create()", "id": "tests_test_memory_manager_testupsertmemory_test_create" }, @@ -27479,7 +27704,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L45", - "community": 577, + "community": 140, "norm_label": ".test_limit_enforcement()", "id": "tests_test_memory_manager_testupsertmemory_test_limit_enforcement" }, @@ -27524,7 +27749,7 @@ "file_type": "code", "source_file": "tests/test_memory_manager.py", "source_location": "L86", - "community": 576, + "community": 140, "norm_label": ".test_excludes_archived()", "id": "tests_test_memory_manager_testcountmemories_test_excludes_archived" }, @@ -27776,7 +28001,7 @@ "file_type": "code", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L112", - "community": 571, + "community": 576, "norm_label": "testdispatchroutesmemorytools", "id": "tests_test_memory_tools_wiring_testdispatchroutesmemorytools" }, @@ -27848,7 +28073,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L113", - "community": 571, + "community": 576, "norm_label": "dispatchtoolcall must route memory tool names via tool_registry.", "id": "tests_test_memory_tools_wiring_rationale_113" }, @@ -28406,7 +28631,7 @@ "file_type": "code", "source_file": "tests/test_pagination.py", "source_location": "L1", - "community": 504, + "community": 482, "norm_label": "test_pagination.py", "id": "tests_test_pagination_py" }, @@ -28415,7 +28640,7 @@ "file_type": "code", "source_file": "tests/test_pagination.py", "source_location": "L14", - "community": 504, + "community": 482, "norm_label": "app()", "id": "tests_test_pagination_app" }, @@ -28424,7 +28649,7 @@ "file_type": "code", "source_file": "tests/test_pagination.py", "source_location": "L35", - "community": 504, + "community": 482, "norm_label": "client()", "id": "tests_test_pagination_client" }, @@ -28523,7 +28748,7 @@ "file_type": "rationale", "source_file": "tests/test_pagination.py", "source_location": "L1", - "community": 504, + "community": 482, "norm_label": "tests for inline pagination params (used in user + prometheus controllers).", "id": "tests_test_pagination_rationale_1" }, @@ -29126,7 +29351,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_auth_coverage.py", "source_location": "L919", - "community": 58, + "community": 474, "norm_label": "test_get_google_sso_with_redirect()", "id": "tests_test_prometheus_auth_coverage_test_get_google_sso_with_redirect" }, @@ -29135,7 +29360,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_auth_coverage.py", "source_location": "L938", - "community": 58, + "community": 474, "norm_label": "test_get_google_sso_default_redirect()", "id": "tests_test_prometheus_auth_coverage_test_get_google_sso_default_redirect" }, @@ -29252,7 +29477,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L44", - "community": 487, + "community": 541, "norm_label": "testmemorytoolfunctions", "id": "tests_test_prometheus_tools_testmemorytoolfunctions" }, @@ -29261,7 +29486,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L45", - "community": 487, + "community": 541, "norm_label": ".test_search_memory_has_docstring()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_search_memory_has_docstring" }, @@ -29270,7 +29495,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L49", - "community": 487, + "community": 541, "norm_label": ".test_save_memory_has_docstring()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_save_memory_has_docstring" }, @@ -29279,7 +29504,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L53", - "community": 487, + "community": 541, "norm_label": ".test_search_memory_signature()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_search_memory_signature" }, @@ -29288,7 +29513,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L59", - "community": 487, + "community": 541, "norm_label": ".test_save_memory_signature()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_save_memory_signature" }, @@ -29297,7 +29522,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L66", - "community": 487, + "community": 541, "norm_label": ".test_search_memory_has_type_hints()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_search_memory_has_type_hints" }, @@ -29306,7 +29531,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L71", - "community": 487, + "community": 541, "norm_label": ".test_save_memory_has_type_hints()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_save_memory_has_type_hints" }, @@ -29315,7 +29540,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L77", - "community": 487, + "community": 541, "norm_label": ".test_memory_tools_is_list_of_callables()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_memory_tools_is_list_of_callables" }, @@ -29324,7 +29549,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L83", - "community": 487, + "community": 541, "norm_label": ".test_memory_tool_names_unchanged()", "id": "tests_test_prometheus_tools_testmemorytoolfunctions_test_memory_tool_names_unchanged" }, @@ -29414,7 +29639,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L126", - "community": 572, + "community": 577, "norm_label": "testgeminicompatibility", "id": "tests_test_prometheus_tools_testgeminicompatibility" }, @@ -29432,7 +29657,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L135", - "community": 572, + "community": 577, "norm_label": ".test_no_harnessstate_in_any_signature()", "id": "tests_test_prometheus_tools_testgeminicompatibility_test_no_harnessstate_in_any_signature" }, @@ -29441,7 +29666,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L151", - "community": 100, + "community": 580, "norm_label": "testtoolregistry", "id": "tests_test_prometheus_tools_testtoolregistry" }, @@ -29450,7 +29675,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L152", - "community": 100, + "community": 580, "norm_label": ".test_registry_contains_memory_tools()", "id": "tests_test_prometheus_tools_testtoolregistry_test_registry_contains_memory_tools" }, @@ -29459,7 +29684,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L156", - "community": 100, + "community": 580, "norm_label": ".test_registry_values_are_callable()", "id": "tests_test_prometheus_tools_testtoolregistry_test_registry_values_are_callable" }, @@ -29468,7 +29693,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L160", - "community": 100, + "community": 580, "norm_label": ".test_registry_matches_tool_names()", "id": "tests_test_prometheus_tools_testtoolregistry_test_registry_matches_tool_names" }, @@ -29486,7 +29711,7 @@ "file_type": "rationale", "source_file": "tests/test_prometheus_tools.py", "source_location": "L127", - "community": 572, + "community": 577, "norm_label": "every function in tool_registry must have gemini-safe signatures. custom cl", "id": "tests_test_prometheus_tools_rationale_127" }, @@ -29495,7 +29720,7 @@ "file_type": "rationale", "source_file": "tests/test_prometheus_tools.py", "source_location": "L136", - "community": 572, + "community": 577, "norm_label": "regression: harnessstate must never leak into tool signatures.", "id": "tests_test_prometheus_tools_rationale_136" }, @@ -31277,7 +31502,7 @@ "file_type": "code", "source_file": "tests/test_state_tools.py", "source_location": "L97", - "community": 101, + "community": 487, "norm_label": "test_set_state_no_state()", "id": "tests_test_state_tools_test_set_state_no_state" }, @@ -31475,7 +31700,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L23", - "community": 3, + "community": 21, "norm_label": "_make_stocks_df()", "id": "tests_test_stocks_api_coverage_make_stocks_df" }, @@ -31853,7 +32078,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L451", - "community": 488, + "community": 3, "norm_label": ".test_deserialize_mixed_string_none_parses_json()", "id": "tests_test_stocks_api_coverage_testdeserializejsoncolumns_test_deserialize_mixed_string_none_parses_json" }, @@ -31862,7 +32087,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L473", - "community": 520, + "community": 3, "norm_label": ".test_deserialize_multiple_special_cols_with_none()", "id": "tests_test_stocks_api_coverage_testdeserializejsoncolumns_test_deserialize_multiple_special_cols_with_none" }, @@ -31871,7 +32096,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L498", - "community": 488, + "community": 3, "norm_label": "testfilterbysearchterms", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms" }, @@ -31880,7 +32105,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L501", - "community": 488, + "community": 3, "norm_label": "._make_manager()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_make_manager" }, @@ -31889,7 +32114,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L509", - "community": 488, + "community": 3, "norm_label": ".test_filter_empty_search_returns_all()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_empty_search_returns_all" }, @@ -31898,7 +32123,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L515", - "community": 488, + "community": 3, "norm_label": ".test_filter_ticker_index_hit()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_ticker_index_hit" }, @@ -31907,7 +32132,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L523", - "community": 488, + "community": 3, "norm_label": ".test_filter_multiple_terms_index()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_multiple_terms_index" }, @@ -31916,7 +32141,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L530", - "community": 488, + "community": 3, "norm_label": ".test_filter_no_index_match_fallback_to_str()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_no_index_match_fallback_to_str" }, @@ -31925,7 +32150,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L538", - "community": 488, + "community": 3, "norm_label": ".test_filter_fallback_multiple_terms()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_fallback_multiple_terms" }, @@ -31934,7 +32159,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L545", - "community": 488, + "community": 3, "norm_label": ".test_filter_case_insensitive()", "id": "tests_test_stocks_api_coverage_testfilterbysearchterms_test_filter_case_insensitive" }, @@ -31943,7 +32168,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L553", - "community": 28, + "community": 21, "norm_label": "testqueryhistorical", "id": "tests_test_stocks_api_coverage_testqueryhistorical" }, @@ -31952,7 +32177,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L556", - "community": 63, + "community": 21, "norm_label": "._make_manager()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_make_manager" }, @@ -31961,7 +32186,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L566", - "community": 28, + "community": 21, "norm_label": ".test_cache_not_initialized_raises_503()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_cache_not_initialized_raises_503" }, @@ -31970,7 +32195,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L574", - "community": 3, + "community": 21, "norm_label": ".test_basic_historical_query()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_basic_historical_query" }, @@ -31979,7 +32204,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L583", - "community": 3, + "community": 21, "norm_label": ".test_historical_with_search()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_with_search" }, @@ -31988,7 +32213,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L591", - "community": 28, + "community": 566, "norm_label": ".test_historical_with_fields()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_with_fields" }, @@ -31997,7 +32222,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L599", - "community": 3, + "community": 21, "norm_label": ".test_historical_with_dates()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_with_dates" }, @@ -32006,7 +32231,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L605", - "community": 3, + "community": 21, "norm_label": ".test_historical_with_order_by()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_with_order_by" }, @@ -32015,7 +32240,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L611", - "community": 3, + "community": 21, "norm_label": ".test_historical_with_limit()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_with_limit" }, @@ -32033,7 +32258,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L628", - "community": 3, + "community": 21, "norm_label": ".test_historical_sorts_by_time()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_sorts_by_time" }, @@ -32042,7 +32267,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L634", - "community": 3, + "community": 21, "norm_label": ".test_historical_deduplicates_by_ticker()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_deduplicates_by_ticker" }, @@ -32069,7 +32294,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L669", - "community": 3, + "community": 21, "norm_label": ".test_historical_search_with_no_results()", "id": "tests_test_stocks_api_coverage_testqueryhistorical_test_historical_search_with_no_results" }, @@ -32141,7 +32366,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L733", - "community": 3, + "community": 21, "norm_label": ".test_basic_fundamental_query()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_basic_fundamental_query" }, @@ -32150,7 +32375,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L741", - "community": 3, + "community": 21, "norm_label": ".test_fundamental_with_search()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_search" }, @@ -32159,7 +32384,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L748", - "community": 3, + "community": 21, "norm_label": ".test_fundamental_with_fields()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_fields" }, @@ -32168,7 +32393,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L754", - "community": 3, + "community": 21, "norm_label": ".test_fundamental_with_date_range()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_date_range" }, @@ -32177,7 +32402,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L760", - "community": 3, + "community": 21, "norm_label": ".test_fundamental_with_single_date()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_single_date" }, @@ -32195,7 +32420,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L776", - "community": 3, + "community": 21, "norm_label": ".test_fundamental_with_order_by()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_order_by" }, @@ -32204,7 +32429,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L782", - "community": 3, + "community": 21, "norm_label": ".test_fundamental_with_limit()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_limit" }, @@ -32213,7 +32438,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L788", - "community": 3, + "community": 21, "norm_label": ".test_fundamental_deduplicates_without_search()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_deduplicates_without_search" }, @@ -32222,7 +32447,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L796", - "community": 3, + "community": 21, "norm_label": ".test_fundamental_with_search_no_dedup()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_with_search_no_dedup" }, @@ -32312,7 +32537,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L913", - "community": 21, + "community": 488, "norm_label": ".test_fundamental_excludes_cotacao_10y()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_excludes_cotacao_10y" }, @@ -32330,7 +32555,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L963", - "community": 3, + "community": 21, "norm_label": ".test_fundamental_requires_search_fields_or_dates()", "id": "tests_test_stocks_api_coverage_testqueryfundamental_test_fundamental_requires_search_fields_or_dates" }, @@ -32348,7 +32573,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L986", - "community": 3, + "community": 10, "norm_label": "._make_manager()", "id": "tests_test_stocks_api_coverage_testquerycotations_make_manager" }, @@ -32492,7 +32717,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1139", - "community": 10, + "community": 543, "norm_label": ".test_cotations_http_route()", "id": "tests_test_stocks_api_coverage_testquerycotations_test_cotations_http_route" }, @@ -32582,7 +32807,7 @@ "file_type": "code", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1265", - "community": 22, + "community": 136, "norm_label": ".test_http_route_search_required()", "id": "tests_test_stocks_api_coverage_testquerylivecotation_test_http_route_search_required" }, @@ -32636,7 +32861,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L24", - "community": 3, + "community": 21, "norm_label": "return a small dataframe with the columns the query module expects.", "id": "tests_test_stocks_api_coverage_rationale_24" }, @@ -32807,7 +33032,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L452", - "community": 488, + "community": 3, "norm_label": "regression: is_string_dtype fails when column has strings + none (pandas 2.x).", "id": "tests_test_stocks_api_coverage_rationale_452" }, @@ -32816,7 +33041,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L474", - "community": 520, + "community": 3, "norm_label": "all four special_cols should parse correctly when mixed with none.", "id": "tests_test_stocks_api_coverage_rationale_474" }, @@ -32825,7 +33050,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L499", - "community": 488, + "community": 3, "norm_label": "tests covering query.py lines 50-67.", "id": "tests_test_stocks_api_coverage_rationale_499" }, @@ -32834,7 +33059,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L554", - "community": 28, + "community": 21, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_554" }, @@ -32843,7 +33068,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L592", - "community": 28, + "community": 566, "norm_label": "pass field name without year (how categorizecolumns returns them).", "id": "tests_test_stocks_api_coverage_rationale_592" }, @@ -32978,7 +33203,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L883", - "community": 39, + "community": 17, "norm_label": "multiple search terms with tickerindex.", "id": "tests_test_stocks_api_coverage_rationale_883" }, @@ -33005,7 +33230,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L914", - "community": 21, + "community": 488, "norm_label": "cotacao 10y padrao and cotacao 10y ajustada belong to /cotations, not /fundament", "id": "tests_test_stocks_api_coverage_rationale_914" }, @@ -33059,7 +33284,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1140", - "community": 10, + "community": 543, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1140" }, @@ -33077,7 +33302,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1266", - "community": 22, + "community": 136, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1266" }, @@ -34328,7 +34553,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L1", - "community": 234, + "community": 518, "norm_label": "test_type_aware_decay.py", "id": "tests_test_type_aware_decay_py" }, @@ -34337,7 +34562,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L11", - "community": 234, + "community": 518, "norm_label": "_create()", "id": "tests_test_type_aware_decay_create" }, @@ -34346,7 +34571,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L29", - "community": 234, + "community": 518, "norm_label": "testtypeawaredecay", "id": "tests_test_type_aware_decay_testtypeawaredecay" }, @@ -34355,7 +34580,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L30", - "community": 234, + "community": 518, "norm_label": ".test_preference_decays_slowly()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_preference_decays_slowly" }, @@ -34364,7 +34589,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L36", - "community": 234, + "community": 518, "norm_label": ".test_context_decays_fast()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_context_decays_fast" }, @@ -34373,7 +34598,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L42", - "community": 234, + "community": 518, "norm_label": ".test_analysis_decays_normally()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_analysis_decays_normally" }, @@ -34382,7 +34607,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L48", - "community": 234, + "community": 518, "norm_label": ".test_feedback_decays_medium()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_feedback_decays_medium" }, @@ -34391,7 +34616,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L54", - "community": 234, + "community": 518, "norm_label": ".test_unknown_type_uses_default()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_unknown_type_uses_default" }, @@ -34400,7 +34625,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L60", - "community": 234, + "community": 518, "norm_label": ".test_mixed_types_all_correct()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_mixed_types_all_correct" }, @@ -34409,7 +34634,7 @@ "file_type": "code", "source_file": "tests/test_type_aware_decay.py", "source_location": "L76", - "community": 234, + "community": 518, "norm_label": ".test_preference_survives_longer()", "id": "tests_test_type_aware_decay_testtypeawaredecay_test_preference_survives_longer" }, @@ -34418,7 +34643,7 @@ "file_type": "rationale", "source_file": "tests/test_type_aware_decay.py", "source_location": "L77", - "community": 234, + "community": 518, "norm_label": "after 10 cycles, preference (0.99^10) > context (0.90^10).", "id": "tests_test_type_aware_decay_rationale_77" }, @@ -34427,7 +34652,7 @@ "file_type": "code", "source_file": "tests/test_user_deps.py", "source_location": "L1", - "community": 474, + "community": 482, "norm_label": "test_user_deps.py", "id": "tests_test_user_deps_py" }, @@ -34571,7 +34796,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L6", - "community": 13, + "community": 131, "norm_label": "testbatchcosinesimilarity", "id": "tests_test_vector_utils_testbatchcosinesimilarity" }, @@ -34580,7 +34805,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L7", - "community": 13, + "community": 131, "norm_label": ".test_empty_matrix()", "id": "tests_test_vector_utils_testbatchcosinesimilarity_test_empty_matrix" }, @@ -34589,7 +34814,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L11", - "community": 13, + "community": 131, "norm_label": ".test_single_row()", "id": "tests_test_vector_utils_testbatchcosinesimilarity_test_single_row" }, @@ -34598,7 +34823,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L17", - "community": 13, + "community": 131, "norm_label": ".test_multiple_rows()", "id": "tests_test_vector_utils_testbatchcosinesimilarity_test_multiple_rows" }, @@ -34607,7 +34832,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L32", - "community": 13, + "community": 131, "norm_label": ".test_zero_query()", "id": "tests_test_vector_utils_testbatchcosinesimilarity_test_zero_query" }, @@ -34616,7 +34841,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L38", - "community": 131, + "community": 208, "norm_label": "testcontenthash", "id": "tests_test_vector_utils_testcontenthash" }, @@ -34625,7 +34850,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L39", - "community": 131, + "community": 208, "norm_label": ".test_deterministic()", "id": "tests_test_vector_utils_testcontenthash_test_deterministic" }, @@ -34634,7 +34859,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L42", - "community": 131, + "community": 208, "norm_label": ".test_different_inputs()", "id": "tests_test_vector_utils_testcontenthash_test_different_inputs" }, @@ -34643,7 +34868,7 @@ "file_type": "code", "source_file": "tests/test_vector_utils.py", "source_location": "L45", - "community": 131, + "community": 208, "norm_label": ".test_hex_format()", "id": "tests_test_vector_utils_testcontenthash_test_hex_format" }, @@ -35975,7 +36200,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1042", - "community": 104, + "community": 16, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1042" }, @@ -36002,7 +36227,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1138", - "community": 539, + "community": 498, "norm_label": "covers line 18: get /stocks/health.", "id": "tests_test_controllers_coverage_rationale_1138" }, @@ -36011,7 +36236,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1152", - "community": 563, + "community": 14, "norm_label": "covers line 35: get /stocks/historical.", "id": "tests_test_controllers_coverage_rationale_1152" }, @@ -36083,7 +36308,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1243", - "community": 528, + "community": 493, "norm_label": "covers line 27: user already has the role.", "id": "tests_test_controllers_coverage_rationale_1243" }, @@ -36110,7 +36335,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1301", - "community": 528, + "community": 493, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1301" }, @@ -36146,7 +36371,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1375", - "community": 525, + "community": 498, "norm_label": "covers line 16: empty password raises valueerror.", "id": "tests_test_controllers_coverage_rationale_1375" }, @@ -36155,7 +36380,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1385", - "community": 525, + "community": 524, "norm_label": "covers lines 45-51: verifyaccesstoken with expired and invalid tokens.", "id": "tests_test_controllers_coverage_rationale_1385" }, @@ -36164,7 +36389,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1388", - "community": 525, + "community": 524, "norm_label": "covers lines 48-49: jwt.expiredsignatureerror.", "id": "tests_test_controllers_coverage_rationale_1388" }, @@ -36308,7 +36533,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L42", - "community": 90, + "community": 497, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_42" }, @@ -36326,7 +36551,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L147", - "community": 500, + "community": 564, "norm_label": "read a file from the workspace. args: path: path to the file (e.", "id": "prometheus_tools_rationale_147" }, @@ -36335,7 +36560,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L171", - "community": 162, + "community": 523, "norm_label": "list files in the workspace directory. args: path: directory pat", "id": "prometheus_tools_rationale_171" }, @@ -36344,7 +36569,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L30", - "community": 137, + "community": 140, "norm_label": "keys with jaccard > 0.8 should merge.", "id": "tests_test_memory_dedup_rationale_30" }, @@ -36353,7 +36578,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L40", - "community": 137, + "community": 140, "norm_label": "keys with low similarity should not merge.", "id": "tests_test_memory_dedup_rationale_40" }, @@ -36362,7 +36587,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L67", - "community": 137, + "community": 140, "norm_label": "keys with jaccard <= 0.8 should not merge.", "id": "tests_test_memory_dedup_rationale_67" }, @@ -36632,7 +36857,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L131", - "community": 500, + "community": 564, "norm_label": "read a file from the sandbox filesystem. args: path: absolute pa", "id": "prometheus_tools_rationale_131" }, @@ -36830,7 +37055,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L130", - "community": 500, + "community": 564, "norm_label": "read a file from the sandbox filesystem. args: path: absolute pa", "id": "prometheus_tools_rationale_130" }, @@ -36839,7 +37064,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L7", - "community": 543, + "community": 529, "norm_label": "testagentsandboxintegration", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration" }, @@ -36848,7 +37073,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L8", - "community": 543, + "community": 529, "norm_label": ".test_build_system_prompt_includes_sandbox_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_includes_sandbox_instructions" }, @@ -36857,7 +37082,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L14", - "community": 543, + "community": 529, "norm_label": ".test_build_system_prompt_includes_state_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_includes_state_instructions" }, @@ -36866,7 +37091,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L19", - "community": 543, + "community": 529, "norm_label": ".test_build_system_prompt_with_state()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_with_state" }, @@ -36965,7 +37190,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L41", - "community": 90, + "community": 497, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_41" }, @@ -36983,7 +37208,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L93", - "community": 101, + "community": 487, "norm_label": "store a value in the harness state for this session. use this to save inter", "id": "prometheus_tools_rationale_93" }, @@ -39170,7 +39395,7 @@ "file_type": "code", "source_file": "tests/test_prometheus_tools.py", "source_location": "L114", - "community": 100, + "community": 536, "norm_label": "test_get_state_no_state_returns_error()", "id": "tests_test_prometheus_tools_test_get_state_no_state_returns_error" }, @@ -39197,7 +39422,7 @@ "file_type": "rationale", "source_file": "tests/test_prometheus_tools.py", "source_location": "L128", - "community": 572, + "community": 577, "norm_label": "every function in tool_registry must have gemini-safe signatures. custom cl", "id": "tests_test_prometheus_tools_rationale_128" }, @@ -39206,7 +39431,7 @@ "file_type": "rationale", "source_file": "tests/test_prometheus_tools.py", "source_location": "L137", - "community": 572, + "community": 577, "norm_label": "regression: harnessstate must never leak into tool signatures.", "id": "tests_test_prometheus_tools_rationale_137" }, @@ -39323,7 +39548,7 @@ "file_type": "code", "source_file": "main/app/prometheus/tools.py", "source_location": "L139", - "community": 162, + "community": 563, "norm_label": "read_sandbox_file()", "id": "prometheus_tools_read_sandbox_file" }, @@ -39332,7 +39557,7 @@ "file_type": "code", "source_file": "main/app/prometheus/tools.py", "source_location": "L151", - "community": 523, + "community": 563, "norm_label": "upload_to_sandbox()", "id": "prometheus_tools_upload_to_sandbox" }, @@ -39341,7 +39566,7 @@ "file_type": "code", "source_file": "main/app/prometheus/tools.py", "source_location": "L165", - "community": 523, + "community": 563, "norm_label": "check_cache()", "id": "prometheus_tools_check_cache" }, @@ -39359,7 +39584,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L109", - "community": 101, + "community": 487, "norm_label": "execute python code in an isolated sandbox. use for quantitative analysis,", "id": "prometheus_tools_rationale_109" }, @@ -39368,7 +39593,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L140", - "community": 162, + "community": 563, "norm_label": "read a file from the sandbox filesystem. args: path: absolute pa", "id": "prometheus_tools_rationale_140" }, @@ -39377,7 +39602,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L152", - "community": 523, + "community": 563, "norm_label": "upload a file to the sandbox filesystem. use this to push data files (csv,", "id": "prometheus_tools_rationale_152" }, @@ -39386,7 +39611,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L166", - "community": 523, + "community": 563, "norm_label": "check if a computed result exists in the cache. use before executing expens", "id": "prometheus_tools_rationale_166" }, @@ -39395,7 +39620,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L9", - "community": 543, + "community": 529, "norm_label": ".test_build_system_prompt_no_state()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_no_state" }, @@ -39404,7 +39629,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L20", - "community": 543, + "community": 529, "norm_label": ".test_build_system_prompt_empty_state()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_build_system_prompt_empty_state" }, @@ -39413,7 +39638,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L25", - "community": 543, + "community": 529, "norm_label": ".test_system_prompt_includes_state_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_system_prompt_includes_state_instructions" }, @@ -39422,7 +39647,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L30", - "community": 543, + "community": 529, "norm_label": ".test_system_prompt_includes_sandbox_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_system_prompt_includes_sandbox_instructions" }, @@ -39431,7 +39656,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L34", - "community": 543, + "community": 529, "norm_label": ".test_system_prompt_includes_cache_instructions()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_system_prompt_includes_cache_instructions" }, @@ -39440,7 +39665,7 @@ "file_type": "code", "source_file": "tests/test_agent_sandbox_integration.py", "source_location": "L38", - "community": 543, + "community": 529, "norm_label": ".test_makechat_uses_tool_registry()", "id": "tests_test_agent_sandbox_integration_testagentsandboxintegration_test_makechat_uses_tool_registry" }, @@ -39611,7 +39836,7 @@ "file_type": "code", "source_file": "tests/test_config_sandbox.py", "source_location": "L1", - "community": 541, + "community": 102, "norm_label": "test_config_sandbox.py", "id": "tests_test_config_sandbox_py" }, @@ -40493,7 +40718,7 @@ "file_type": "code", "source_file": "main/models/harness.py", "source_location": "L1", - "community": 12, + "community": 101, "norm_label": "harness.py", "id": "main_models_harness_py" }, @@ -40502,7 +40727,7 @@ "file_type": "code", "source_file": "main/models/harness.py", "source_location": "L7", - "community": 12, + "community": 101, "norm_label": "loopevent", "id": "models_harness_loopevent" }, @@ -40511,7 +40736,7 @@ "file_type": "rationale", "source_file": "main/models/harness.py", "source_location": "L1", - "community": 12, + "community": 101, "norm_label": "loopevent model for observable agent loops.", "id": "models_harness_rationale_1" }, @@ -40520,7 +40745,7 @@ "file_type": "code", "source_file": "tests/test_events.py", "source_location": "L7", - "community": 12, + "community": 101, "norm_label": "testloopeventmodel", "id": "tests_test_events_testloopeventmodel" }, @@ -40529,7 +40754,7 @@ "file_type": "code", "source_file": "tests/test_events.py", "source_location": "L8", - "community": 12, + "community": 101, "norm_label": ".test_create_event()", "id": "tests_test_events_testloopeventmodel_test_create_event" }, @@ -40538,7 +40763,7 @@ "file_type": "code", "source_file": "tests/test_events.py", "source_location": "L14", - "community": 12, + "community": 101, "norm_label": ".test_event_fields()", "id": "tests_test_events_testloopeventmodel_test_event_fields" }, @@ -40547,7 +40772,7 @@ "file_type": "code", "source_file": "tests/test_events.py", "source_location": "L33", - "community": 12, + "community": 101, "norm_label": ".test_nullable_fields()", "id": "tests_test_events_testloopeventmodel_test_nullable_fields" }, @@ -40556,7 +40781,7 @@ "file_type": "code", "source_file": "tests/test_events.py", "source_location": "L43", - "community": 12, + "community": 101, "norm_label": ".test_created_at_auto()", "id": "tests_test_events_testloopeventmodel_test_created_at_auto" }, @@ -40565,7 +40790,7 @@ "file_type": "code", "source_file": "tests/test_events.py", "source_location": "L50", - "community": 12, + "community": 101, "norm_label": ".test_session_id_indexed()", "id": "tests_test_events_testloopeventmodel_test_session_id_indexed" }, @@ -40745,7 +40970,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L39", - "community": 90, + "community": 497, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_39" }, @@ -40871,7 +41096,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L38", - "community": 90, + "community": 497, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_38" }, @@ -40934,7 +41159,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/tools.py", "source_location": "L29", - "community": 90, + "community": 497, "norm_label": "store a memory about the user's preferences, analysis results, or feedback.", "id": "prometheus_tools_rationale_29" }, @@ -40943,7 +41168,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L52", - "community": 137, + "community": 140, "norm_label": "keys with low similarity should not merge.", "id": "tests_test_memory_dedup_rationale_52" }, @@ -40952,7 +41177,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_dedup.py", "source_location": "L85", - "community": 137, + "community": 140, "norm_label": "keys with jaccard <= 0.8 should not merge.", "id": "tests_test_memory_dedup_rationale_85" }, @@ -41078,7 +41303,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L89", - "community": 571, + "community": 576, "norm_label": "dispatchtoolcall must route memory tool names to executememorytool.", "id": "tests_test_memory_tools_wiring_rationale_89" }, @@ -41114,7 +41339,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L92", - "community": 571, + "community": 576, "norm_label": "dispatchtoolcall must route memory tool names to executememorytool.", "id": "tests_test_memory_tools_wiring_rationale_92" }, @@ -41204,7 +41429,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L134", - "community": 234, + "community": 518, "norm_label": "decay happens first, then archive check with new scores.", "id": "tests_test_memory_maintenance_rationale_134" }, @@ -41213,7 +41438,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L143", - "community": 234, + "community": 518, "norm_label": "score that decays to >= threshold stays alive. 0.11 * 0.95 = 0.1045 >= 0.1.", "id": "tests_test_memory_maintenance_rationale_143" }, @@ -41222,7 +41447,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_maintenance.py", "source_location": "L156", - "community": 234, + "community": 518, "norm_label": "89 days with low score \u2192 not archived (need > 90).", "id": "tests_test_memory_maintenance_rationale_156" }, @@ -41555,7 +41780,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1302", - "community": 528, + "community": 493, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1302" }, @@ -41591,7 +41816,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1376", - "community": 525, + "community": 498, "norm_label": "covers line 16: empty password raises valueerror.", "id": "tests_test_controllers_coverage_rationale_1376" }, @@ -41600,7 +41825,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1386", - "community": 525, + "community": 524, "norm_label": "covers lines 45-51: verifyaccesstoken with expired and invalid tokens.", "id": "tests_test_controllers_coverage_rationale_1386" }, @@ -41879,7 +42104,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L91", - "community": 571, + "community": 576, "norm_label": "dispatchtoolcall must route memory tool names to executememorytool.", "id": "tests_test_memory_tools_wiring_rationale_91" }, @@ -41897,7 +42122,7 @@ "file_type": "code", "source_file": "main/utils/vector.py", "source_location": "L8", - "community": 13, + "community": 131, "norm_label": "batchcosinesimilarity()", "id": "utils_vector_batchcosinesimilarity" }, @@ -41906,7 +42131,7 @@ "file_type": "code", "source_file": "main/utils/vector.py", "source_location": "L20", - "community": 131, + "community": 208, "norm_label": "contenthash()", "id": "utils_vector_contenthash" }, @@ -42212,7 +42437,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_tools_wiring.py", "source_location": "L76", - "community": 571, + "community": 576, "norm_label": "dispatchtoolcall must route memory tool names to executememorytool.", "id": "tests_test_memory_tools_wiring_rationale_76" }, @@ -42266,7 +42491,7 @@ "file_type": "code", "source_file": "main/app/prometheus/agent.py", "source_location": "L91", - "community": 116, + "community": 562, "norm_label": "executememorytool()", "id": "prometheus_agent_executememorytool" }, @@ -42473,7 +42698,7 @@ "file_type": "rationale", "source_file": "main/utils/vector.py", "source_location": "L19", - "community": 131, + "community": 208, "norm_label": "md5 hash for change detection.", "id": "utils_vector_rationale_19" }, @@ -42986,7 +43211,7 @@ "file_type": "code", "source_file": "main/app/prometheus/memory.py", "source_location": "L138", - "community": 53, + "community": 13, "norm_label": "_fulltext_search()", "id": "prometheus_memory_fulltext_search" }, @@ -43157,7 +43382,7 @@ "file_type": "code", "source_file": "main/utils/vector.py", "source_location": "L28", - "community": 13, + "community": 131, "norm_label": "batch_cosine_similarity()", "id": "utils_vector_batch_cosine_similarity" }, @@ -43166,7 +43391,7 @@ "file_type": "code", "source_file": "main/utils/vector.py", "source_location": "L41", - "community": 131, + "community": 208, "norm_label": "content_hash()", "id": "utils_vector_content_hash" }, @@ -43193,7 +43418,7 @@ "file_type": "rationale", "source_file": "main/utils/vector.py", "source_location": "L29", - "community": 13, + "community": 131, "norm_label": "vectorized cosine similarity: one query against n embeddings.", "id": "utils_vector_rationale_29" }, @@ -43202,7 +43427,7 @@ "file_type": "rationale", "source_file": "main/utils/vector.py", "source_location": "L42", - "community": 131, + "community": 208, "norm_label": "md5 hash for change detection.", "id": "utils_vector_rationale_42" }, @@ -43355,7 +43580,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L19", - "community": 574, + "community": 140, "norm_label": "admin gets extended limit (has all permissions).", "id": "tests_test_memory_manager_rationale_19" }, @@ -43364,7 +43589,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L25", - "community": 575, + "community": 140, "norm_label": "creates a new memory.", "id": "tests_test_memory_manager_rationale_25" }, @@ -43391,7 +43616,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L49", - "community": 577, + "community": 140, "norm_label": "rejects new memory when limit reached.", "id": "tests_test_memory_manager_rationale_49" }, @@ -43427,7 +43652,7 @@ "file_type": "rationale", "source_file": "tests/test_memory_manager.py", "source_location": "L88", - "community": 576, + "community": 140, "norm_label": "archived memories not counted.", "id": "tests_test_memory_manager_rationale_88" }, @@ -43661,7 +43886,7 @@ "file_type": "rationale", "source_file": "tests/test_vector_utils.py", "source_location": "L68", - "community": 13, + "community": 131, "norm_label": "empty matrix \u2192 empty array.", "id": "tests_test_vector_utils_rationale_68" }, @@ -43670,7 +43895,7 @@ "file_type": "rationale", "source_file": "tests/test_vector_utils.py", "source_location": "L73", - "community": 13, + "community": 131, "norm_label": "single row matches cosine_similarity.", "id": "tests_test_vector_utils_rationale_73" }, @@ -43679,7 +43904,7 @@ "file_type": "rationale", "source_file": "tests/test_vector_utils.py", "source_location": "L80", - "community": 13, + "community": 131, "norm_label": "multiple rows ranked correctly.", "id": "tests_test_vector_utils_rationale_80" }, @@ -43688,7 +43913,7 @@ "file_type": "rationale", "source_file": "tests/test_vector_utils.py", "source_location": "L93", - "community": 13, + "community": 131, "norm_label": "zero query \u2192 all zeros.", "id": "tests_test_vector_utils_rationale_93" }, @@ -43697,7 +43922,7 @@ "file_type": "rationale", "source_file": "tests/test_vector_utils.py", "source_location": "L101", - "community": 131, + "community": 208, "norm_label": "same input \u2192 same hash.", "id": "tests_test_vector_utils_rationale_101" }, @@ -43706,7 +43931,7 @@ "file_type": "rationale", "source_file": "tests/test_vector_utils.py", "source_location": "L105", - "community": 131, + "community": 208, "norm_label": "different inputs \u2192 different hashes.", "id": "tests_test_vector_utils_rationale_105" }, @@ -43715,7 +43940,7 @@ "file_type": "rationale", "source_file": "tests/test_vector_utils.py", "source_location": "L109", - "community": 131, + "community": 208, "norm_label": "returns 32-char hex string.", "id": "tests_test_vector_utils_rationale_109" }, @@ -44588,7 +44813,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L1", - "community": 186, + "community": 162, "norm_label": "generation.py", "id": "main_app_prometheus_generation_py" }, @@ -44624,7 +44849,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L36", - "community": 186, + "community": 162, "norm_label": ".executeworkflow()", "id": "prometheus_generation_prometheusgenerator_executeworkflow" }, @@ -44705,7 +44930,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L74", - "community": 251, + "community": 137, "norm_label": "testclient with stocks router + verifyapikey + getcurrentuser overrides.", "id": "tests_conftest_rationale_74" }, @@ -44714,7 +44939,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L99", - "community": 251, + "community": 137, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_99" }, @@ -44876,7 +45101,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L846", - "community": 16, + "community": 99, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_846" }, @@ -44885,7 +45110,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L864", - "community": 16, + "community": 99, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_864" }, @@ -44930,7 +45155,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L912", - "community": 208, + "community": 104, "norm_label": "covers lines 77, 83-84, 86: get /prometheus/history/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_912" }, @@ -44939,7 +45164,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L915", - "community": 208, + "community": 104, "norm_label": "covers lines 77, 86: session found with history.", "id": "tests_test_controllers_coverage_rationale_915" }, @@ -44948,7 +45173,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L959", - "community": 208, + "community": 104, "norm_label": "covers lines 83-84: session not found.", "id": "tests_test_controllers_coverage_rationale_959" }, @@ -44993,7 +45218,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1020", - "community": 16, + "community": 99, "norm_label": "covers lines 111-112: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1020" }, @@ -45002,7 +45227,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1038", - "community": 104, + "community": 16, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1038" }, @@ -45029,7 +45254,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1134", - "community": 539, + "community": 498, "norm_label": "covers line 18: get /stocks/health.", "id": "tests_test_controllers_coverage_rationale_1134" }, @@ -45038,7 +45263,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1148", - "community": 563, + "community": 14, "norm_label": "covers line 35: get /stocks/historical.", "id": "tests_test_controllers_coverage_rationale_1148" }, @@ -45110,7 +45335,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1239", - "community": 528, + "community": 493, "norm_label": "covers line 27: user already has the role.", "id": "tests_test_controllers_coverage_rationale_1239" }, @@ -45146,7 +45371,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1298", - "community": 528, + "community": 493, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1298" }, @@ -45488,7 +45713,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L844", - "community": 16, + "community": 99, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_844" }, @@ -45497,7 +45722,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L862", - "community": 16, + "community": 99, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_862" }, @@ -45542,7 +45767,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L910", - "community": 208, + "community": 104, "norm_label": "covers lines 77, 83-84, 86: get /prometheus/history/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_910" }, @@ -45551,7 +45776,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L913", - "community": 208, + "community": 104, "norm_label": "covers lines 77, 86: session found with history.", "id": "tests_test_controllers_coverage_rationale_913" }, @@ -45560,7 +45785,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L957", - "community": 208, + "community": 104, "norm_label": "covers lines 83-84: session not found.", "id": "tests_test_controllers_coverage_rationale_957" }, @@ -45605,7 +45830,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1018", - "community": 16, + "community": 99, "norm_label": "covers lines 111-112: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1018" }, @@ -45614,7 +45839,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1036", - "community": 104, + "community": 16, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1036" }, @@ -45641,7 +45866,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1133", - "community": 539, + "community": 498, "norm_label": "covers line 18: get /stocks/health.", "id": "tests_test_controllers_coverage_rationale_1133" }, @@ -45650,7 +45875,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1147", - "community": 563, + "community": 14, "norm_label": "covers line 35: get /stocks/historical.", "id": "tests_test_controllers_coverage_rationale_1147" }, @@ -45713,7 +45938,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1238", - "community": 528, + "community": 493, "norm_label": "covers line 27: user already has the role.", "id": "tests_test_controllers_coverage_rationale_1238" }, @@ -45749,7 +45974,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1297", - "community": 528, + "community": 493, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1297" }, @@ -45785,7 +46010,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1371", - "community": 525, + "community": 498, "norm_label": "covers line 16: empty password raises valueerror.", "id": "tests_test_controllers_coverage_rationale_1371" }, @@ -45794,7 +46019,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1381", - "community": 525, + "community": 524, "norm_label": "covers lines 45-51: verifyaccesstoken with expired and invalid tokens.", "id": "tests_test_controllers_coverage_rationale_1381" }, @@ -45803,7 +46028,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1384", - "community": 525, + "community": 524, "norm_label": "covers lines 48-49: jwt.expiredsignatureerror.", "id": "tests_test_controllers_coverage_rationale_1384" }, @@ -46307,7 +46532,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L528", - "community": 488, + "community": 3, "norm_label": "regression: is_string_dtype fails when column has strings + none (pandas 2.x).", "id": "tests_test_stocks_api_coverage_rationale_528" }, @@ -46316,7 +46541,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L550", - "community": 520, + "community": 3, "norm_label": "all four special_cols should parse correctly when mixed with none.", "id": "tests_test_stocks_api_coverage_rationale_550" }, @@ -46325,7 +46550,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L575", - "community": 488, + "community": 3, "norm_label": "tests covering query.py lines 50-67.", "id": "tests_test_stocks_api_coverage_rationale_575" }, @@ -46334,7 +46559,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L630", - "community": 28, + "community": 21, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_630" }, @@ -46343,7 +46568,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L668", - "community": 28, + "community": 566, "norm_label": "pass field name without year (how categorizecolumns returns them).", "id": "tests_test_stocks_api_coverage_rationale_668" }, @@ -46496,7 +46721,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L990", - "community": 21, + "community": 488, "norm_label": "cotacao 10y padrao and cotacao 10y ajustada belong to /cotations, not /fundament", "id": "tests_test_stocks_api_coverage_rationale_990" }, @@ -46550,7 +46775,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1216", - "community": 10, + "community": 543, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1216" }, @@ -46568,7 +46793,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1342", - "community": 22, + "community": 136, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1342" }, @@ -46703,7 +46928,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1344", - "community": 22, + "community": 136, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1344" }, @@ -46892,7 +47117,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1400", - "community": 22, + "community": 136, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1400" }, @@ -46910,7 +47135,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L23", - "community": 3, + "community": 21, "norm_label": "return a small dataframe with the columns the query module expects.", "id": "tests_test_stocks_api_coverage_rationale_23" }, @@ -47072,7 +47297,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L527", - "community": 488, + "community": 3, "norm_label": "regression: is_string_dtype fails when column has strings + none (pandas 2.x).", "id": "tests_test_stocks_api_coverage_rationale_527" }, @@ -47081,7 +47306,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L549", - "community": 520, + "community": 3, "norm_label": "all four special_cols should parse correctly when mixed with none.", "id": "tests_test_stocks_api_coverage_rationale_549" }, @@ -47090,7 +47315,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L574", - "community": 488, + "community": 3, "norm_label": "tests covering query.py lines 50-67.", "id": "tests_test_stocks_api_coverage_rationale_574" }, @@ -47099,7 +47324,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L629", - "community": 28, + "community": 21, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_629" }, @@ -47108,7 +47333,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L667", - "community": 28, + "community": 566, "norm_label": "pass field name without year (how categorizecolumns returns them).", "id": "tests_test_stocks_api_coverage_rationale_667" }, @@ -47252,7 +47477,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L986", - "community": 21, + "community": 488, "norm_label": "cotacao 10y padrao and cotacao 10y ajustada belong to /cotations, not /fundament", "id": "tests_test_stocks_api_coverage_rationale_986" }, @@ -47306,7 +47531,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1212", - "community": 10, + "community": 543, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1212" }, @@ -47324,7 +47549,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1396", - "community": 22, + "community": 136, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1396" }, @@ -47360,7 +47585,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1388", - "community": 22, + "community": 136, "norm_label": "get /stocks/realtime-cotation without search returns 422.", "id": "tests_test_stocks_api_coverage_rationale_1388" }, @@ -47450,7 +47675,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1210", - "community": 10, + "community": 543, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1210" }, @@ -47540,7 +47765,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L976", - "community": 21, + "community": 488, "norm_label": "cotacao 10y padrao and cotacao 10y ajustada belong to /cotations, not /fundament", "id": "tests_test_stocks_api_coverage_rationale_976" }, @@ -47594,7 +47819,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1191", - "community": 10, + "community": 543, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1191" }, @@ -48125,7 +48350,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1170", - "community": 10, + "community": 543, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1170" }, @@ -48170,7 +48395,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1141", - "community": 10, + "community": 543, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1141" }, @@ -48233,7 +48458,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L63", - "community": 54, + "community": 197, "norm_label": "getrealtimecotation()", "id": "controller_stocksapi_controller_getrealtimecotation" }, @@ -48251,7 +48476,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L1148", - "community": 10, + "community": 543, "norm_label": "hit the actual /stocks/cotations http endpoint with adjusted=false.", "id": "tests_test_stocks_api_coverage_rationale_1148" }, @@ -48287,7 +48512,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L19", - "community": 186, + "community": 162, "norm_label": "sessionproxy", "id": "prometheus_generation_sessionproxy" }, @@ -48296,7 +48521,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L20", - "community": 186, + "community": 162, "norm_label": ".get()", "id": "prometheus_generation_sessionproxy_get" }, @@ -48305,7 +48530,7 @@ "file_type": "code", "source_file": "main/app/prometheus/generation.py", "source_location": "L23", - "community": 186, + "community": 162, "norm_label": ".post()", "id": "prometheus_generation_sessionproxy_post" }, @@ -48341,7 +48566,7 @@ "file_type": "code", "source_file": "main/controller/stocksapi_controller.py", "source_location": "L23", - "community": 54, + "community": 197, "norm_label": "apikeytest()", "id": "controller_stocksapi_controller_apikeytest" }, @@ -48404,7 +48629,7 @@ "file_type": "code", "source_file": "main/utils/pagination.py", "source_location": "L1", - "community": 474, + "community": 482, "norm_label": "pagination.py", "id": "main_utils_pagination_py" }, @@ -48413,7 +48638,7 @@ "file_type": "code", "source_file": "main/utils/pagination.py", "source_location": "L4", - "community": 474, + "community": 482, "norm_label": "paginationparams", "id": "utils_pagination_paginationparams" }, @@ -48422,7 +48647,7 @@ "file_type": "code", "source_file": "main/utils/pagination.py", "source_location": "L5", - "community": 474, + "community": 482, "norm_label": ".__init__()", "id": "utils_pagination_paginationparams_init" }, @@ -48440,7 +48665,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L75", - "community": 251, + "community": 137, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_75" }, @@ -48548,7 +48773,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L236", - "community": 136, + "community": 110, "norm_label": "integration tests for the verifyapikey function.", "id": "tests_test_api_key_quota_atomic_rationale_236" }, @@ -48557,7 +48782,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L269", - "community": 136, + "community": 110, "norm_label": "test api key verification with invalid key.", "id": "tests_test_api_key_quota_atomic_rationale_269" }, @@ -48566,7 +48791,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L280", - "community": 136, + "community": 110, "norm_label": "test api key verification with missing key.", "id": "tests_test_api_key_quota_atomic_rationale_280" }, @@ -48575,7 +48800,7 @@ "file_type": "rationale", "source_file": "tests/test_api_key_quota_atomic.py", "source_location": "L291", - "community": 136, + "community": 110, "norm_label": "test that api key system can be disabled.", "id": "tests_test_api_key_quota_atomic_rationale_291" }, @@ -48665,7 +48890,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L148", - "community": 498, + "community": 120, "norm_label": "covers lines 44-54, 63, 66-71: register success, valueerror, generic exception.", "id": "tests_test_controllers_coverage_rationale_148" }, @@ -48692,7 +48917,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L228", - "community": 498, + "community": 120, "norm_label": "covers lines 87-93, 102: login success and failure paths.", "id": "tests_test_controllers_coverage_rationale_228" }, @@ -48800,7 +49025,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L425", - "community": 498, + "community": 120, "norm_label": "covers lines 155-156, 158, 160-168, 170-177, 179-184, 186, 190-204: googlecallba", "id": "tests_test_controllers_coverage_rationale_425" }, @@ -48980,7 +49205,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L889", - "community": 16, + "community": 99, "norm_label": "covers lines 33-36: get /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_889" }, @@ -48989,7 +49214,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L907", - "community": 16, + "community": 99, "norm_label": "covers line 52: post /prometheus/sessions.", "id": "tests_test_controllers_coverage_rationale_907" }, @@ -49034,7 +49259,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L955", - "community": 208, + "community": 104, "norm_label": "covers lines 77, 83-84, 86: get /prometheus/history/{sessionid}.", "id": "tests_test_controllers_coverage_rationale_955" }, @@ -49043,7 +49268,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L958", - "community": 208, + "community": 104, "norm_label": "covers lines 77, 86: session found with history.", "id": "tests_test_controllers_coverage_rationale_958" }, @@ -49052,7 +49277,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1002", - "community": 208, + "community": 104, "norm_label": "covers lines 83-84: session not found.", "id": "tests_test_controllers_coverage_rationale_1002" }, @@ -49097,7 +49322,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1063", - "community": 16, + "community": 99, "norm_label": "covers lines 111-112: sessionid is none, new session created.", "id": "tests_test_controllers_coverage_rationale_1063" }, @@ -49106,7 +49331,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1081", - "community": 104, + "community": 16, "norm_label": "covers lines 114-115, 117-120, 122: existing session with verified ownership.", "id": "tests_test_controllers_coverage_rationale_1081" }, @@ -49133,7 +49358,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1181", - "community": 539, + "community": 498, "norm_label": "covers line 18: get /stocks/health.", "id": "tests_test_controllers_coverage_rationale_1181" }, @@ -49151,7 +49376,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1206", - "community": 563, + "community": 14, "norm_label": "covers line 35: get /stocks/historical.", "id": "tests_test_controllers_coverage_rationale_1206" }, @@ -49214,7 +49439,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1356", - "community": 528, + "community": 493, "norm_label": "covers lines 42-44: session validation fails.", "id": "tests_test_controllers_coverage_rationale_1356" }, @@ -49232,7 +49457,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1430", - "community": 525, + "community": 498, "norm_label": "covers line 16: empty password raises valueerror.", "id": "tests_test_controllers_coverage_rationale_1430" }, @@ -49241,7 +49466,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1440", - "community": 525, + "community": 524, "norm_label": "covers lines 45-51: verifyaccesstoken with expired and invalid tokens.", "id": "tests_test_controllers_coverage_rationale_1440" }, @@ -49250,7 +49475,7 @@ "file_type": "rationale", "source_file": "tests/test_controllers_coverage.py", "source_location": "L1443", - "community": 525, + "community": 524, "norm_label": "covers lines 48-49: jwt.expiredsignatureerror.", "id": "tests_test_controllers_coverage_rationale_1443" }, @@ -49295,7 +49520,7 @@ "file_type": "code", "source_file": "tests/test_http_session_coverage.py", "source_location": "L9", - "community": 541, + "community": 522, "norm_label": ".test_creates_new_session()", "id": "tests_test_http_session_coverage_testgetsession_test_creates_new_session" }, @@ -49889,7 +50114,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L526", - "community": 488, + "community": 3, "norm_label": "regression: is_string_dtype fails when column has strings + none (pandas 2.x).", "id": "tests_test_stocks_api_coverage_rationale_526" }, @@ -49898,7 +50123,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L548", - "community": 520, + "community": 3, "norm_label": "all four special_cols should parse correctly when mixed with none.", "id": "tests_test_stocks_api_coverage_rationale_548" }, @@ -49907,7 +50132,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L573", - "community": 488, + "community": 3, "norm_label": "tests covering query.py lines 50-67.", "id": "tests_test_stocks_api_coverage_rationale_573" }, @@ -49916,7 +50141,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L628", - "community": 28, + "community": 21, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_628" }, @@ -49925,7 +50150,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L666", - "community": 28, + "community": 566, "norm_label": "pass field name without year (how categorizecolumns returns them).", "id": "tests_test_stocks_api_coverage_rationale_666" }, @@ -50402,7 +50627,7 @@ "file_type": "rationale", "source_file": "main/app/prometheus/generation.py", "source_location": "L20", - "community": 186, + "community": 162, "norm_label": "thread-safe proxy that delegates to per-thread sessions.", "id": "prometheus_generation_rationale_20" }, @@ -50411,7 +50636,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L582", - "community": 28, + "community": 21, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_582" }, @@ -50420,7 +50645,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L620", - "community": 28, + "community": 566, "norm_label": "pass field name without year (how categorizecolumns returns them).", "id": "tests_test_stocks_api_coverage_rationale_620" }, @@ -50546,7 +50771,7 @@ "file_type": "rationale", "source_file": "tests/test_connectivity_coverage.py", "source_location": "L8", - "community": 566, + "community": 59, "norm_label": "checkmysqlconnection \u2014 success, errors, engine=none paths.", "id": "tests_test_connectivity_coverage_rationale_8" }, @@ -50555,7 +50780,7 @@ "file_type": "rationale", "source_file": "tests/test_connectivity_coverage.py", "source_location": "L105", - "community": 564, + "community": 59, "norm_label": "checkserviceconnection \u2014 success, not found, errors.", "id": "tests_test_connectivity_coverage_rationale_105" }, @@ -50582,7 +50807,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L583", - "community": 28, + "community": 21, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_583" }, @@ -50591,7 +50816,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L621", - "community": 28, + "community": 566, "norm_label": "pass field name without year (how categorizecolumns returns them).", "id": "tests_test_stocks_api_coverage_rationale_621" }, @@ -50771,7 +50996,7 @@ "file_type": "code", "source_file": "main/utils/http_session.py", "source_location": "L9", - "community": 186, + "community": 162, "norm_label": "get_session()", "id": "utils_http_session_get_session" }, @@ -50780,7 +51005,7 @@ "file_type": "rationale", "source_file": "main/utils/http_session.py", "source_location": "L10", - "community": 186, + "community": 162, "norm_label": "return a requests.session for the current thread. sessions are created la", "id": "utils_http_session_rationale_10" }, @@ -51194,7 +51419,7 @@ "file_type": "rationale", "source_file": "main/utils/http_session.py", "source_location": "L9", - "community": 186, + "community": 162, "norm_label": "return a requests.session for the current thread. sessions are created la", "id": "utils_http_session_rationale_9" }, @@ -51221,7 +51446,7 @@ "file_type": "code", "source_file": "main/service/user_service.py", "source_location": "L35", - "community": 110, + "community": 72, "norm_label": "inactivesessionsscheduler()", "id": "service_user_service_inactivesessionsscheduler" }, @@ -51689,7 +51914,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L522", - "community": 488, + "community": 3, "norm_label": "tests covering query.py lines 50-67.", "id": "tests_test_stocks_api_coverage_rationale_522" }, @@ -51698,7 +51923,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L577", - "community": 28, + "community": 21, "norm_label": "tests covering query.py lines 77-132.", "id": "tests_test_stocks_api_coverage_rationale_577" }, @@ -51707,7 +51932,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_api_coverage.py", "source_location": "L615", - "community": 28, + "community": 566, "norm_label": "pass field name without year (how categorizecolumns returns them).", "id": "tests_test_stocks_api_coverage_rationale_615" }, @@ -51833,7 +52058,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L62", - "community": 251, + "community": 137, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_62" }, @@ -51842,7 +52067,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L61", - "community": 251, + "community": 137, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_61" }, @@ -51851,7 +52076,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L57", - "community": 251, + "community": 137, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_57" }, @@ -51860,7 +52085,7 @@ "file_type": "rationale", "source_file": "tests/conftest.py", "source_location": "L49", - "community": 251, + "community": 137, "norm_label": "testclient with all routers mounted \u2014 no lifespan (no db/service init). o", "id": "tests_conftest_rationale_49" }, @@ -52490,7 +52715,7 @@ "file_type": "code", "source_file": "tests/test_stocks_cache.py", "source_location": "L299", - "community": 570, + "community": 502, "norm_label": "testfilterbysearchterms", "id": "tests_test_stocks_cache_testfilterbysearchterms" }, @@ -52499,7 +52724,7 @@ "file_type": "code", "source_file": "tests/test_stocks_cache.py", "source_location": "L302", - "community": 570, + "community": 502, "norm_label": ".test_filter_with_tickerindex()", "id": "tests_test_stocks_cache_testfilterbysearchterms_test_filter_with_tickerindex" }, @@ -52760,7 +52985,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L300", - "community": 570, + "community": 502, "norm_label": "tests for optimized search filtering", "id": "tests_test_stocks_cache_rationale_300" }, @@ -52769,7 +52994,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L303", - "community": 570, + "community": 502, "norm_label": "filter should use ticker index for o(1) lookup", "id": "tests_test_stocks_cache_rationale_303" }, @@ -53048,7 +53273,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L302", - "community": 570, + "community": 502, "norm_label": "tests for optimized search filtering", "id": "tests_test_stocks_cache_rationale_302" }, @@ -53057,7 +53282,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_cache.py", "source_location": "L305", - "community": 570, + "community": 502, "norm_label": "filter should use ticker index for o(1) lookup", "id": "tests_test_stocks_cache_rationale_305" }, @@ -53147,7 +53372,7 @@ "file_type": "code", "source_file": "tests/test_stocks_cache.py", "source_location": "L304", - "community": 570, + "community": 502, "norm_label": ".test_filter_with_tickerindex()", "id": "tests_test_stocks_cache_testfilterbysearchterms_test_filter_with_tickerIndex" }, @@ -53156,7 +53381,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L1", - "community": 183, + "community": 503, "norm_label": "test_stocks_optimization.py", "id": "tests_test_stocks_optimization_py" }, @@ -53273,7 +53498,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L111", - "community": 183, + "community": 503, "norm_label": "testconnectionpool", "id": "tests_test_stocks_optimization_testconnectionpool" }, @@ -53282,7 +53507,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L114", - "community": 183, + "community": 503, "norm_label": ".test_stocks_engine_has_pool_configuration()", "id": "tests_test_stocks_optimization_testconnectionpool_test_stocks_engine_has_pool_configuration" }, @@ -53291,7 +53516,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L123", - "community": 183, + "community": 503, "norm_label": "testlazydeserialization", "id": "tests_test_stocks_optimization_testlazydeserialization" }, @@ -53300,7 +53525,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L126", - "community": 183, + "community": 503, "norm_label": ".test_query_manager_has_deserialize_method()", "id": "tests_test_stocks_optimization_testlazydeserialization_test_query_manager_has_deserialize_method" }, @@ -53309,7 +53534,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L137", - "community": 183, + "community": 215, "norm_label": "testqueryoptimization", "id": "tests_test_stocks_optimization_testqueryoptimization" }, @@ -53318,7 +53543,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L140", - "community": 183, + "community": 215, "norm_label": ".test_all_optimizations_present()", "id": "tests_test_stocks_optimization_testqueryoptimization_test_all_optimizations_present" }, @@ -53327,7 +53552,7 @@ "file_type": "code", "source_file": "tests/test_stocks_optimization.py", "source_location": "L155", - "community": 183, + "community": 215, "norm_label": ".test_query_filter_uses_optimization()", "id": "tests_test_stocks_optimization_testqueryoptimization_test_query_filter_uses_optimization" }, @@ -53543,7 +53768,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L112", - "community": 183, + "community": 503, "norm_label": "tests for connection pool configuration", "id": "tests_test_stocks_optimization_rationale_112" }, @@ -53552,7 +53777,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L115", - "community": 183, + "community": 503, "norm_label": "stocks engine should have optimized pool settings", "id": "tests_test_stocks_optimization_rationale_115" }, @@ -53561,7 +53786,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L124", - "community": 183, + "community": 503, "norm_label": "tests for lazy json deserialization", "id": "tests_test_stocks_optimization_rationale_124" }, @@ -53570,7 +53795,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L127", - "community": 183, + "community": 503, "norm_label": "query manager should have deserialize method", "id": "tests_test_stocks_optimization_rationale_127" }, @@ -53579,7 +53804,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L138", - "community": 183, + "community": 215, "norm_label": "integration tests for all query optimizations", "id": "tests_test_stocks_optimization_rationale_138" }, @@ -53588,7 +53813,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L141", - "community": 183, + "community": 215, "norm_label": "all optimizations should be implemented", "id": "tests_test_stocks_optimization_rationale_141" }, @@ -53597,7 +53822,7 @@ "file_type": "rationale", "source_file": "tests/test_stocks_optimization.py", "source_location": "L156", - "community": 183, + "community": 215, "norm_label": "query filter should use ticker index", "id": "tests_test_stocks_optimization_rationale_156" }, @@ -54024,7 +54249,7 @@ "label": "FastAPI", "file_type": "rationale", "source_file": "README.md", - "community": 474, + "community": 482, "norm_label": "fastapi", "id": "fastapi" }, @@ -54064,7 +54289,7 @@ "label": "Authentication System", "file_type": "document", "source_file": "docs/authentication.md", - "community": 495, + "community": 43, "norm_label": "authentication system", "id": "authentication" }, @@ -54072,7 +54297,7 @@ "label": "JWT Authentication", "file_type": "rationale", "source_file": "docs/authentication.md", - "community": 495, + "community": 43, "norm_label": "jwt authentication", "id": "jwt" }, @@ -54080,7 +54305,7 @@ "label": "Google OAuth", "file_type": "rationale", "source_file": "docs/authentication.md", - "community": 495, + "community": 43, "norm_label": "google oauth", "id": "google_oauth" }, @@ -54168,7 +54393,7 @@ "label": "Pytest Testing", "file_type": "rationale", "source_file": "pyproject.toml", - "community": 541, + "community": 93, "norm_label": "pytest testing", "id": "pytest" }, @@ -54816,6 +55041,16 @@ "source": "prometheus_mcp_mcpclientpool", "target": "server_config_config" }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L4", + "weight": 0.8, + "confidence_score": 0.5, + "source": "prometheus_memory_memorycandidate", + "target": "server_config_config" + }, { "relation": "uses", "confidence": "INFERRED", @@ -59249,6 +59484,16 @@ "source": "authentication_authentication_authenticateuser", "target": "authentication_util_verifypassword" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/authentication/session.py", + "source_location": "L13", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_authentication_session_py", + "target": "authentication_session_parsedevicefields" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -59369,6 +59614,17 @@ "source": "main_app_authentication_session_py", "target": "authentication_session_getsessionbyidsafe" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/authentication/session.py", + "source_location": "L45", + "weight": 1.0, + "confidence_score": 1.0, + "source": "authentication_session_createsession", + "target": "authentication_session_parsedevicefields" + }, { "relation": "uses", "confidence": "INFERRED", @@ -60760,6 +61016,17 @@ "source": "prometheus_agent_prometheus_streammessage", "target": "prometheus_compact_loadfielddata" }, + { + "relation": "calls", + "context": "call", + "confidence": "INFERRED", + "confidence_score": 0.8, + "source_file": "main/app/prometheus/agent.py", + "source_location": "L262", + "weight": 1.0, + "source": "prometheus_agent_prometheus_streammessage", + "target": "prometheus_memory_newtokencache" + }, { "relation": "calls", "context": "call", @@ -61034,6 +61301,16 @@ "source": "prometheus_chat_prometheuschatmanager", "target": "models_prometheus_prometheussession" }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L26", + "weight": 0.8, + "confidence_score": 0.5, + "source": "prometheus_memory_memorycandidate", + "target": "prometheus_chat_prometheuschatmanager" + }, { "relation": "uses", "confidence": "INFERRED", @@ -61206,6 +61483,26 @@ "source": "main_app_prometheus_compact_py", "target": "prometheus_compact_getstocksfieldsurl" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L67", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_compact_py", + "target": "prometheus_compact_istransientfieldserror" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L82", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_compact_py", + "target": "prometheus_compact_fetchfieldspayload" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -61422,6 +61719,17 @@ "source": "prometheus_compact_charcount", "target": "prometheus_compact_counttokens" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L83", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_compact_fetchfieldspayload", + "target": "prometheus_compact_getstocksfieldsurl" + }, { "relation": "calls", "context": "call", @@ -61433,6 +61741,17 @@ "source": "prometheus_compact_loadfielddata", "target": "prometheus_compact_getstocksfieldsurl" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/compact.py", + "source_location": "L92", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_compact_loadfielddata", + "target": "prometheus_compact_fetchfieldspayload" + }, { "relation": "calls", "context": "call", @@ -62068,6 +62387,26 @@ "source": "main_app_prometheus_memory_py", "target": "prometheus_memory_clearall" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L64", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_memorycandidate" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L90", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_prometheus_memory_py", + "target": "prometheus_memory_newtokencache" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -62597,6 +62936,66 @@ "source": "prometheus_memory_clearall", "target": "prometheus_memory_clearallasync" }, + { + "relation": "inherits", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L64", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_memory_memorycandidate", + "target": "basemodel" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L22", + "weight": 0.8, + "confidence_score": 0.5, + "source": "prometheus_memory_memorycandidate", + "target": "models_memory_prometheusmemory" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L23", + "weight": 0.8, + "confidence_score": 0.5, + "source": "prometheus_memory_memorycandidate", + "target": "utils_roles_permission" + }, + { + "relation": "uses", + "confidence": "INFERRED", + "source_file": "main/app/prometheus/memory.py", + "source_location": "L23", + "weight": 0.8, + "confidence_score": 0.5, + "source": "prometheus_memory_memorycandidate", + "target": "utils_roles_roles" + }, + { + "relation": "inherits", + "confidence": "EXTRACTED", + "source_file": "main/utils/errors.py", + "source_location": "L13", + "weight": 1.0, + "confidence_score": 1.0, + "source": "utils_errors_errorresponse", + "target": "basemodel" + }, + { + "relation": "inherits", + "confidence": "EXTRACTED", + "source_file": "tests/test_error_handlers.py", + "source_location": "L20", + "weight": 1.0, + "confidence_score": 1.0, + "source": "basemodel", + "target": "tests_test_error_handlers_samplebody" + }, { "relation": "calls", "context": "call", @@ -64493,6 +64892,26 @@ "source": "prometheus_stream_bus_streambus", "target": "prometheus_stream_bus_streambus_startrun" }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/stream_bus.py", + "source_location": "L86", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_stream_bus_streambus", + "target": "prometheus_stream_bus_streambus_eventgenerator" + }, + { + "relation": "method", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/stream_bus.py", + "source_location": "L109", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_stream_bus_streambus", + "target": "prometheus_stream_bus_streambus_streamresponse" + }, { "relation": "method", "confidence": "EXTRACTED", @@ -64525,6 +64944,17 @@ "source": "prometheus_stream_bus_streambus_startrun", "target": "prometheus_stream_bus_streambus_getorcreate" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/stream_bus.py", + "source_location": "L87", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_stream_bus_streambus_eventgenerator", + "target": "prometheus_stream_bus_streambus_subscribe" + }, { "relation": "calls", "context": "call", @@ -64536,6 +64966,17 @@ "source": "prometheus_stream_bus_streambus_forward", "target": "prometheus_stream_bus_streambus_subscribe" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/stream_bus.py", + "source_location": "L107", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_stream_bus_streambus_eventgenerator", + "target": "prometheus_stream_bus_streambus_unsubscribe" + }, { "relation": "calls", "context": "call", @@ -64547,6 +64988,17 @@ "source": "prometheus_stream_bus_streambus_forward", "target": "prometheus_stream_bus_streambus_unsubscribe" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/prometheus/stream_bus.py", + "source_location": "L110", + "weight": 1.0, + "confidence_score": 1.0, + "source": "prometheus_stream_bus_streambus_streamresponse", + "target": "prometheus_stream_bus_streambus_eventgenerator" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -68151,6 +68603,26 @@ "source": "main_app_stocks_api_query_py", "target": "stocks_api_query_querycotations" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L332", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_istransientliveerror" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L347", + "weight": 1.0, + "confidence_score": 1.0, + "source": "main_app_stocks_api_query_py", + "target": "stocks_api_query_fetchlivepayload" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -68629,6 +69101,17 @@ "source": "controller_stocksapi_controller_getcotations", "target": "stocks_api_query_querycotations" }, + { + "relation": "calls", + "context": "call", + "confidence": "EXTRACTED", + "source_file": "main/app/stocks_api/query.py", + "source_location": "L358", + "weight": 1.0, + "confidence_score": 1.0, + "source": "stocks_api_query_querylivecotation", + "target": "stocks_api_query_fetchlivepayload" + }, { "relation": "calls", "context": "call", @@ -73819,16 +74302,6 @@ "source": "main_utils_errors_py", "target": "utils_errors_register_error_handlers" }, - { - "relation": "inherits", - "confidence": "EXTRACTED", - "source_file": "main/utils/errors.py", - "source_location": "L13", - "weight": 1.0, - "confidence_score": 1.0, - "source": "utils_errors_errorresponse", - "target": "basemodel" - }, { "relation": "calls", "context": "call", @@ -73943,16 +74416,6 @@ "source": "utils_errors_errorresponse", "target": "utils_errors_build_error_response" }, - { - "relation": "inherits", - "confidence": "EXTRACTED", - "source_file": "tests/test_error_handlers.py", - "source_location": "L20", - "weight": 1.0, - "confidence_score": 1.0, - "source": "basemodel", - "target": "tests_test_error_handlers_samplebody" - }, { "relation": "method", "confidence": "EXTRACTED", @@ -76408,6 +76871,16 @@ "source": "agents_md", "target": "server_agents_graphify" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "AGENTS.md", + "source_location": "L60", + "weight": 1.0, + "confidence_score": 1.0, + "source": "agents_md", + "target": "server_agents_swarm_delegation_default" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -76478,56 +76951,6 @@ "source": "server_agents_dev_commands", "target": "server_agents_ci_pipeline_order" }, - { - "relation": "contains", - "confidence": "EXTRACTED", - "source_file": "PONYTAIL.md", - "source_location": "L1", - "weight": 1.0, - "confidence_score": 1.0, - "source": "ponytail_md", - "target": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit" - }, - { - "relation": "contains", - "confidence": "EXTRACTED", - "source_file": "PONYTAIL.md", - "source_location": "L6", - "weight": 1.0, - "confidence_score": 1.0, - "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", - "target": "server_ponytail_proposed_awaiting_approval" - }, - { - "relation": "contains", - "confidence": "EXTRACTED", - "source_file": "PONYTAIL.md", - "source_location": "L64", - "weight": 1.0, - "confidence_score": 1.0, - "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", - "target": "server_ponytail_disputed_already_litigated_needs_your_ruling_to_proceed" - }, - { - "relation": "contains", - "confidence": "EXTRACTED", - "source_file": "PONYTAIL.md", - "source_location": "L72", - "weight": 1.0, - "confidence_score": 1.0, - "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", - "target": "server_ponytail_held_out_your_ignore_rules_not_proposed" - }, - { - "relation": "contains", - "confidence": "EXTRACTED", - "source_file": "PONYTAIL.md", - "source_location": "L78", - "weight": 1.0, - "confidence_score": 1.0, - "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", - "target": "server_ponytail_refused" - }, { "relation": "contains", "confidence": "EXTRACTED", @@ -80378,6 +80801,146 @@ "source": "plans_2026_09_14_memory_postgres_pgvector_plan_task_5_docs_close", "target": "plans_2026_09_14_memory_postgres_pgvector_plan_codeblock_8" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L1", + "weight": 1.0, + "confidence_score": 1.0, + "source": "docs_superpowers_plans_2026_09_15_adopt_libs_md", + "target": "plans_2026_09_15_adopt_libs_adopt_libs_implementation_plan" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L13", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_adopt_libs_implementation_plan", + "target": "plans_2026_09_15_adopt_libs_global_constraints" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L24", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_global_constraints", + "target": "plans_2026_09_15_adopt_libs_task_1_tenacity_replaces_bespoke_retries" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L56", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_global_constraints", + "target": "plans_2026_09_15_adopt_libs_task_2_cashews_native_probe_first" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L76", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_global_constraints", + "target": "plans_2026_09_15_adopt_libs_task_3_pydantic_validates_llm_extraction_json" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L102", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_global_constraints", + "target": "plans_2026_09_15_adopt_libs_task_4_sse_starlette_replaces_hand_sse_bus" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L117", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_global_constraints", + "target": "plans_2026_09_15_adopt_libs_task_5_rapidfuzz_memory_key_dedup" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L132", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_global_constraints", + "target": "plans_2026_09_15_adopt_libs_task_6_cachetools_bounds_token_cache" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L143", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_global_constraints", + "target": "plans_2026_09_15_adopt_libs_task_7_user_agents_fills_device_fields_optional" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L154", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_global_constraints", + "target": "plans_2026_09_15_adopt_libs_task_8_pytest_plugin_set" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L38", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_task_1_tenacity_replaces_bespoke_retries", + "target": "plans_2026_09_15_adopt_libs_codeblock_1" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L51", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_task_1_tenacity_replaces_bespoke_retries", + "target": "plans_2026_09_15_adopt_libs_codeblock_2" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L72", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_task_2_cashews_native_probe_first", + "target": "plans_2026_09_15_adopt_libs_codeblock_3" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "docs/superpowers/plans/2026-09-15-adopt-libs.md", + "source_location": "L88", + "weight": 1.0, + "confidence_score": 1.0, + "source": "plans_2026_09_15_adopt_libs_task_3_pydantic_validates_llm_extraction_json", + "target": "plans_2026_09_15_adopt_libs_codeblock_4" + }, { "relation": "contains", "confidence": "EXTRACTED", @@ -80538,6 +81101,56 @@ "source": "specs_2026_09_04_wallet_design_2_decision_design_a_pure_event_log_derive_at_read_time", "target": "specs_2026_09_04_wallet_design_approaches_considered" }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "PONYTAIL.md", + "source_location": "L1", + "weight": 1.0, + "confidence_score": 1.0, + "source": "ponytail_md", + "target": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "PONYTAIL.md", + "source_location": "L6", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", + "target": "server_ponytail_proposed_awaiting_approval" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "PONYTAIL.md", + "source_location": "L64", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", + "target": "server_ponytail_disputed_already_litigated_needs_your_ruling_to_proceed" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "PONYTAIL.md", + "source_location": "L72", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", + "target": "server_ponytail_held_out_your_ignore_rules_not_proposed" + }, + { + "relation": "contains", + "confidence": "EXTRACTED", + "source_file": "PONYTAIL.md", + "source_location": "L78", + "weight": 1.0, + "confidence_score": 1.0, + "source": "server_ponytail_ponytail_md_proposed_cuts_not_applied_approve_before_any_edit", + "target": "server_ponytail_refused" + }, { "relation": "method", "confidence": "EXTRACTED", @@ -137183,5 +137796,5 @@ "label": "User Authentication & Authorization" } ], - "built_at_commit": "5ad08ba029a1925687e87f67f3278d5498f560e5" + "built_at_commit": "f4e8f0bce3d22a58279ac3f5f92136d2852c9e9d" } \ No newline at end of file diff --git a/graphify-out/manifest.json b/graphify-out/manifest.json index 2b3451d..dd4c3ce 100644 --- a/graphify-out/manifest.json +++ b/graphify-out/manifest.json @@ -15,8 +15,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\run.py": { - "mtime": 1789366057.0017536, - "ast_hash": "35021368aa43aea573173c51037c5c80", + "mtime": 1789433601.1342905, + "ast_hash": "77fcee1422b1ff8f4ce46a5e2e356246", "semantic_hash": "" }, "D:\\Repositories\\server\\frontend\\components.json": { @@ -215,8 +215,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\authentication\\session.py": { - "mtime": 1789365900.6795783, - "ast_hash": "565419026a26fd31b95cadc85814e50d", + "mtime": 1789434849.6886837, + "ast_hash": "e2c239692412e44bd7ff4d4f6a9f8988", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\authentication\\sso.py": { @@ -230,8 +230,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\agent.py": { - "mtime": 1789368603.539152, - "ast_hash": "6e58d02ffd53d80c8e09e2c0b739abc7", + "mtime": 1789438984.8569534, + "ast_hash": "19fb4e9e6da3a76551e55a3436460ed1", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\chat.py": { @@ -240,8 +240,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\compact.py": { - "mtime": 1789428006.4340317, - "ast_hash": "fa10e9be5e7c0a171480655e72976c49", + "mtime": 1789438984.938393, + "ast_hash": "64939e1ae6d23e9f4ca37ac7a492d857", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\mcp.py": { @@ -250,8 +250,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\memory.py": { - "mtime": 1789428072.503439, - "ast_hash": "2a943b7484a3848e473cdfebba416e08", + "mtime": 1789439255.3807392, + "ast_hash": "f4c2b9d14c7f7c1349638230c674a32c", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\sandbox.py": { @@ -260,8 +260,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\stream_bus.py": { - "mtime": 1789266824.6054785, - "ast_hash": "09ed8f9196ab4d41b95499735d2d1af9", + "mtime": 1789439356.61903, + "ast_hash": "18123062622096d1ed80c8d6c41b0169", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\prometheus\\tools.py": { @@ -285,8 +285,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\cache.py": { - "mtime": 1789363514.5006788, - "ast_hash": "9f1efcf706a603e6bba46845bca86508", + "mtime": 1789434714.8335533, + "ast_hash": "f483c0857c4d84c3561a456b168b958c", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\compress.py": { @@ -300,8 +300,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\query.py": { - "mtime": 1789368603.5401547, - "ast_hash": "fac4cd3310f0bb2bf7f5c6864bc78ee8", + "mtime": 1789434788.4910736, + "ast_hash": "d8942fd6280c22db0c7000c0a129f55a", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\stocks_api\\sync_cache.py": { @@ -315,8 +315,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\app\\user\\user.py": { - "mtime": 1789266824.6150067, - "ast_hash": "b9fdcffec5ca0cbad6252af644acbe02", + "mtime": 1789428228.2499757, + "ast_hash": "f10c1e3f5391986c8b725dfe76af4597", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\controller\\authentication_controller.py": { @@ -325,8 +325,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\controller\\prometheus_controller.py": { - "mtime": 1789266824.617007, - "ast_hash": "0af3e9b5a00f92f201cf0a5cc93ba9f6", + "mtime": 1789434877.2972302, + "ast_hash": "f21a938f6fb14fb7773cf4986c6bcd56", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\controller\\stocksapi_controller.py": { @@ -380,7 +380,7 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\service\\authentication_service.py": { - "mtime": 1789266824.6255214, + "mtime": 1789439255.3787396, "ast_hash": "68127fe1d44a44242ce3a5ed2bf4d464", "semantic_hash": "" }, @@ -450,8 +450,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\models\\loader.py": { - "mtime": 1789266824.6350515, - "ast_hash": "53d7f85c943e3cac2acb81fb5ebe5a79", + "mtime": 1789433374.0601785, + "ast_hash": "34ff1ec17a1a053845ea29589b184a4d", "semantic_hash": "" }, "D:\\Repositories\\server\\main\\utils\\models\\__init__.py": { @@ -520,8 +520,8 @@ "semantic_hash": "" }, "D:\\Repositories\\server\\AGENTS.md": { - "mtime": 1789266824.546347, - "ast_hash": "3ebebc033e590dc2507e972b310ffd49", + "mtime": 1789433940.4116547, + "ast_hash": "bf791e7f0c47c9789225de4efea91a83", "semantic_hash": "" }, "D:\\Repositories\\server\\docker-compose.yml": { @@ -534,24 +534,14 @@ "ast_hash": "061d7cea62f7e674af297ae3f858be8f", "semantic_hash": "" }, - "D:\\Repositories\\server\\PONYTAIL.md": { - "mtime": 1789363582.7935076, - "ast_hash": "e1223d3b181dd26939c82be5ed2c4adf", - "semantic_hash": "" - }, "D:\\Repositories\\server\\README.md": { "mtime": 1789266824.5528724, "ast_hash": "eefffc81bc23e76d2429b5d93525910e", "semantic_hash": "" }, "D:\\Repositories\\server\\requirements.txt": { - "mtime": 1789266824.6521552, - "ast_hash": "ca468b8c46eaec66585c6626007b2e6a", - "semantic_hash": "" - }, - "D:\\Repositories\\server\\SWARMS.md": { - "mtime": 1789316049.401499, - "ast_hash": "1267348986aa2996b77607d894b554da", + "mtime": 1789439006.260999, + "ast_hash": "05a6b048172c8140804c4283af13f038", "semantic_hash": "" }, "D:\\Repositories\\server\\TODO.md": { @@ -629,6 +619,11 @@ "ast_hash": "74c6fb495a112e3f6db93a70c6265f21", "semantic_hash": "" }, + "D:\\Repositories\\server\\docs\\superpowers\\plans\\2026-09-15-adopt-libs.md": { + "mtime": 1789434365.4423459, + "ast_hash": "6bbe07e07379d48bbc77c0d367feedc7", + "semantic_hash": "" + }, "D:\\Repositories\\server\\docs\\superpowers\\specs\\2026-09-04-wallet-design.md": { "mtime": 1789266824.564381, "ast_hash": "3ad505fd6016388f87bd14fa8da4f40e",