Skip to content

feat(kg): expire stale entity/relation facts via reconciliation pass#316

Merged
EtanHey merged 9 commits into
mainfrom
feat/kg-stateful-reconciliation
May 23, 2026
Merged

feat(kg): expire stale entity/relation facts via reconciliation pass#316
EtanHey merged 9 commits into
mainfrom
feat/kg-stateful-reconciliation

Conversation

@EtanHey
Copy link
Copy Markdown
Owner

@EtanHey EtanHey commented May 23, 2026

Mandate

Implements the user mandate for PHASE 1 — KG STATEFUL RECONCILIATION on branch feat/kg-stateful-reconciliation, following the Etan-mandate 2026-05-22 plan and /pr-loop invariant.

Source citations:

  • Phase scope states the forward-only KG bug and stale brainlayer depends_on fastapi example: docs.local/plans/2026-05-22-brainlayer-actually-works/phase-1-kg-stateful/scope.md:8-17.
  • Phase scope requires reconciliation, no deletes, default search filtering, schema columns, indexes, and tests: docs.local/plans/2026-05-22-brainlayer-actually-works/phase-1-kg-stateful/scope.md:21-32, :48-58.
  • Issue 1b audit maps KG ingest to code_intelligence.py and confirms brainlayer -> fastapi depends_on persisted without validity state: /Users/etanheyman/Gits/orchestrator/docs.local/audits/2026-05-22-issue-1b-fts5-kg-investigation.md:7-17.
  • Collab invariants require TDD, full /pr-loop, all 7 checks green, no squash, and brain_store on merge: docs.local/plans/2026-05-22-brainlayer-actually-works/collab.md:38-47.

Implementation

  • Adds idempotent KG validity schema support for kg_entities.expired_at, existing/required validity columns, and expired indexes in src/brainlayer/vector_store.py:1184-1216.
  • Adds code-intelligence schema guard for lightweight DBs and kg_current_facts view compatibility in src/brainlayer/pipeline/code_intelligence.py:75-104.
  • Writes observation validity on each code-intelligence scan and tracks observed dependency targets in src/brainlayer/pipeline/code_intelligence.py:239-365.
  • Re-observation refreshes valid_until and clears expired_at; missing code-intelligence depends_on facts are soft-expired without deletes in src/brainlayer/pipeline/code_intelligence.py:368-501.
  • Re-adding entities/relations through KG repo revives soft-expired facts by clearing expired_at in src/brainlayer/kg_repo.py:168-230, :282-299.
  • brain_search SQL KG fallback now excludes expired relations/entities and invalid validity windows by default in src/brainlayer/mcp/search_handler.py:420-430.
  • Readonly search bootstrap now detects stale KG validity schemas before opening readonly in src/brainlayer/mcp/_shared.py:29-56.
  • Hardened eval benchmark fallback for Ranx/Numba order-sensitive failures encountered during the local CI-equivalent test gate in src/brainlayer/eval/benchmark.py:165-267.

Regression Tests

  • Removed dependency expires and disappears from current facts: tests/test_code_intelligence.py:319-368.
  • Re-observed dependency refreshes valid_until and remains unexpired: tests/test_code_intelligence.py:370-415.
  • brain_search SQL KG path excludes expired relations: tests/test_search_filter_params.py:19-40.
  • Schema/index guards cover expired_at on entities and expired indexes: tests/test_kg_schema.py:74-135, tests/test_kg_standard.py:153-228.

Acceptance

  • Ingest (brainlayer, depends_on, fastapi), remove fastapi, rerun reconcile, and assert expired_at != NULL plus exclusion from kg_current_facts.
  • Re-observation updates valid_until and clears/does not set expired_at.
  • No deletes; stale facts retain audit trail through soft expiry.
  • brain_search default SQL KG query excludes expired facts.
  • Existing KG tests pass locally.
  • Local CI-equivalent gate passed before push.

Validation

  • RED first: targeted new tests failed on missing expired_at/valid_until, missing expired indexes, and _kg_facts_sql returning a soft-closed relation.
  • GREEN focused: .venv/bin/pytest tests/test_code_intelligence.py tests/test_kg_schema.py tests/test_kg_standard.py tests/test_search_filter_params.py -q131 passed.
  • Lint/format: .venv/bin/ruff check src/ tests/ && .venv/bin/ruff format --check src/ tests/ → passed.
  • CI-equivalent local: .venv/bin/pytest tests/ -m "not integration and not live" -x2139 passed, 9 skipped, 75 deselected, 1 xfailed.
  • Pre-push hook: passed unit pytest, MCP registration pytest, isolated eval/hook routing pytest, bun test, and FTS5 determinism shell regression.

Review Requests

@codex review
@cursor review
@BugBot review


Note

Medium Risk
Touches KG reconciliation update logic for existing relations, which could affect provenance metadata and whether edges are considered current/expired across scans.

Overview
Ensures enrich_projects updates kg_relations.properties when a previously expired, non-code_intelligence depends_on relation is re-observed, merging provenance so the edge can be revived without taking ownership.

Updates the regression test to assert the merged sources provenance and adds coverage that the revived manual edge is later soft-expired and removed from kg_current_facts when the dependency disappears again.

Reviewed by Cursor Bugbot for commit 0d1f6ba. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Expire stale entity and relation facts via reconciliation pass in code intelligence

  • Adds valid_from, valid_until, and expired_at columns to kg_entities and kg_relations, with indexes and a rebuilt kg_current_facts view using julianday-based timestamp comparisons in vector_store.py and code_intelligence.py.
  • During enrich_projects, dependency relations not observed in the current scan are marked expired; library entities with no remaining active facts are also expired via _expire_stale_dependency_relations.
  • Entities and relations that are re-observed have their valid_until refreshed and expired_at cleared, preserving provenance and avoiding duplicates.
  • A pidfile-backed single-writer lock (with PID + start-time validation and fcntl fallback) prevents concurrent enrichment runs from corrupting the KG.
  • Bootstrap for readonly search now triggers when KG tables are partially present or missing the required validity/expiry columns.
  • Risk: Existing deployments will have the schema migrated on first run; entities and relations without validity windows will not appear in kg_current_facts until re-observed.

Macroscope summarized 0d1f6ba.

Summary by CodeRabbit

  • New Features

    • Added validity/expiration tracking and timestamp-aware view logic so search and KG queries ignore outdated facts; schema upgrades applied where needed.
    • Improved dependency reconciliation with observation/validity windows to refresh or expire scanner-owned relations.
  • Bug Fixes

    • Made evaluation resilient to external library failures with a guarded fallback and manual metric computation.
    • Search-store bootstrap now detects partial KG schemas and triggers repair.
  • Performance

    • Added indexes to speed expiration-aware filtering.
  • Tests

    • Expanded regression coverage for reconciliation, expiry, evaluation fallbacks, locking, and timestamp handling.

Review Change Stack

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

📝 Walkthrough

Walkthrough

Adds KG expiration/validity columns and indexes, updates repo and search paths to respect validity, refactors code-intelligence to track/refresh/expire observed dependencies, and hardens benchmark evaluation with a ranx Run/Qrels fallback plus manual metric computations.

Changes

KG Validity and Expiration System

Layer / File(s) Summary
Schema foundation: expiration columns and indexes
src/brainlayer/vector_store.py, tests/test_kg_schema.py
VectorStore adds expired_at TEXT to kg_entities and creates idx_kg_entities_expired / idx_kg_relations_expired; kg_current_facts view now uses timestamp-aware julianday(...) comparisons; tests updated to expect these schema changes.
KG repository integration: reading and clearing expired_at
src/brainlayer/kg_repo.py, tests/test_kg_standard.py
KGMixin and repo methods include expired_at in deserialization and SELECTs; upserts and ON CONFLICT update paths clear expired_at (set NULL) to refresh active entities/relations; tests assert default NULL behavior.
KG fact filtering and bootstrap validation
src/brainlayer/mcp/_shared.py, src/brainlayer/mcp/search_handler.py, tests/test_search_filter_params.py, tests/test_vector_store_readonly.py
Search-store bootstrap now validates required KG tables/columns; _kg_facts_sql filters out expired relations/entities and enforces valid_from/valid_until bounds; tests verify exclusion of soft-closed relations and timestamp-aware validity.
Code-intelligence reconciliation: tracking observation and expiration
src/brainlayer/pipeline/code_intelligence.py, tests/test_code_intelligence.py
Adds observation/validity constants and helpers, _ensure_reconciliation_schema schema migration, computes observed_at/valid_until per run, updates _upsert_project and _add_dependency_relation to persist/refresh validity and clear expired_at, and expires stale dependencies; extensive regression tests added.

Benchmark Evaluation Resilience

Layer / File(s) Summary
Ranx fallback with manual metrics
src/brainlayer/eval/benchmark.py, tests/test_eval_framework.py
Introduces guarded monkey-patch (_patch_ranx_run_fallback, _RANX_RUN_FALLBACK_PATCHED, _run_from_dict) and _build_ranx_qrels; evaluate_pipeline/compare_pipelines prefer ranx when possible, otherwise _evaluate_without_ranx computes ndcg@k, recall@k, map@k, and mrr@k from qrels and run dicts; tests validate fallback behavior.

Sequence Diagrams

sequenceDiagram
  participant Enrich as enrich_projects
  participant Schema as _ensure_reconciliation_schema
  participant Upsert as _upsert_project
  participant AddRel as _add_dependency_relation
  participant Expire as _expire_stale_dependency_relations
  participant DB as SQLite KG DB

  Enrich->>Schema: ensure validity columns and indexes
  Schema->>DB: ALTER TABLE / CREATE INDEX
  Enrich->>Enrich: compute observed_at, valid_until
  Enrich->>Upsert: upsert project with timestamps
  Upsert->>DB: UPDATE/INSERT (refresh valid_until, clear expired_at)
  Enrich->>AddRel: add dependency for notable libraries
  AddRel->>DB: INSERT/UPDATE depends_on (set valid_from/valid_until, clear expired_at)
  Enrich->>Expire: expire unobserved depends_on relations
  Expire->>DB: UPDATE relations/entities -> set expired_at
Loading
sequenceDiagram
  participant RunPipeline as run_pipeline
  participant Eval as evaluate_pipeline
  participant Ranx as ranx.evaluate
  participant Fallback as _evaluate_without_ranx

  RunPipeline->>Eval: provide run dict (wrapped by _run_from_dict)
  Eval->>Eval: has ranx_qrels?
  alt ranx_qrels exists
    Eval->>Ranx: call ranx.evaluate()
    Ranx-->>Eval: ranx metrics
  else
    Eval->>Fallback: call _evaluate_without_ranx()
    Fallback-->>Eval: manual metrics (ndcg/recall/map/mrr)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • EtanHey/brainlayer#191: Related edits to the pure-SQL _kg_facts_sql path in src/brainlayer/mcp/search_handler.py.
  • EtanHey/brainlayer#46: Prior KG-standard schema work that introduced related validity/expiration schema concepts.
  • EtanHey/brainlayer#201: Related changes to src/brainlayer/eval/benchmark.py and ranx evaluation handling.

Poem

🐰 I nudge the graph to note what's past its best,

expired_at whispers when relations should rest.
Pipelines refresh, old links gently fade,
and benchmarks fallback when ranx can't be made.
🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding expiration/reconciliation logic to manage stale KG facts through soft-expiry rather than deletion.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/kg-stateful-reconciliation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread src/brainlayer/pipeline/code_intelligence.py
Comment thread src/brainlayer/pipeline/code_intelligence.py
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8169a6a468

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +423 to +424
SET properties = ?, confidence = 0.99, valid_from = COALESCE(valid_from, ?),
valid_until = ?, expired_at = NULL
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve existing depends_on provenance on re-observation

When a depends_on edge already exists for the same (source_id, target_id), this update unconditionally rewrites properties to {"source": "code_intelligence"} and resets confidence. That mutates non-code-intelligence facts (for example, manually curated or pipeline-generated facts) into code-intelligence facts, which then makes them eligible for later reconciliation expiry and loses original provenance/evidence.

Useful? React with 👍 / 👎.

Comment on lines +489 to +491
has_active_code_fact = any(_is_code_intelligence_relation(properties) for (properties,) in active_rows)
if has_active_code_fact:
continue
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Prevent expiring libraries still referenced by active non-code facts

This liveness check only looks for active code-intelligence relations, so a library is marked expired even when active non-code depends_on relations still point to it. Because search now filters on se/te.expired_at IS NULL, expiring the entity hides still-valid manual/other-pipeline facts across the KG, which is a correctness regression for retrieval.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/brainlayer/pipeline/code_intelligence.py (1)

414-427: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not overwrite non-code-intelligence relation properties on refresh.

The current update path rewrites properties to {"source":"code_intelligence"} for any existing depends_on triple. That can clobber non-code-intelligence provenance and later make unrelated facts eligible for stale-expiry logic.

💡 Suggested patch
-    existing = conn.execute(
-        "SELECT id FROM kg_relations WHERE source_id = ? AND target_id = ? AND relation_type = 'depends_on'",
+    existing = conn.execute(
+        "SELECT id, properties FROM kg_relations WHERE source_id = ? AND target_id = ? AND relation_type = 'depends_on'",
         (source_id, target_id),
     ).fetchone()

     if existing:
-        if not dry_run:
+        rel_id, rel_props = existing
+        if not dry_run and (not rel_props or _is_code_intelligence_relation(rel_props)):
             conn.execute(
                 """UPDATE kg_relations
                    SET properties = ?, confidence = 0.99, valid_from = COALESCE(valid_from, ?),
                        valid_until = ?, expired_at = NULL
                    WHERE id = ?""",
-                (json.dumps({"source": CODE_INTELLIGENCE_SOURCE}), observed_at, valid_until, existing[0]),
+                (json.dumps({"source": CODE_INTELLIGENCE_SOURCE}), observed_at, valid_until, rel_id),
             )
         return target_id
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/brainlayer/pipeline/code_intelligence.py` around lines 414 - 427, The
update currently overwrites the entire properties column with {"source":
CODE_INTELLIGENCE_SOURCE} which clobbers existing provenance; instead, fetch the
current properties for the matched relation (kg_relations row id from
existing[0]), parse the JSON, merge/augment it so you add or record
CODE_INTELLIGENCE_SOURCE without removing other keys (e.g., preserve an existing
"source" value by turning it into a list or appending CODE_INTELLIGENCE_SOURCE,
or add a new key like "sources"), then write the merged JSON back in the UPDATE
for the kg_relations row (keep the same UPDATE fields
confidence/valid_from/valid_until/expired_at but replace the hard overwrite of
properties with the merged JSON).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/brainlayer/pipeline/code_intelligence.py`:
- Around line 269-273: After switching the DB to WAL mode (where conn =
sqlite3.connect(...) and conn.execute("PRAGMA journal_mode = WAL") is called)
add explicit checkpoints: call conn.execute("PRAGMA wal_checkpoint(FULL)")
immediately after switching to WAL and again after the bulk
reconciliation/upsert work but before the final conn.commit(); only perform
these checkpoints when not dry_run and around the bulk reconciliation pass that
follows _ensure_reconciliation_schema(conn) so the WAL is
flushed/checked-pointed before and after heavy KG upserts.
- Around line 269-273: enrich_projects() currently opens a raw sqlite3 writer
and runs DDL/long transactional writes without the one-writer pidfile,
SQLITE_BUSY retry/busy-timeout, or WAL checkpointing and also clobbers
kg_relations.properties; fix it by (1) acquiring the same one-writer pidfile
mutex used in src/brainlayer/vector_store.py before opening/doing writes in
enrich_projects(), (2) set a busy timeout or retry loop around sqlite3
operations to retry on SQLITE_BUSY (wrap commits/executes that can block), (3)
run PRAGMA wal_checkpoint(FULL) before the big write and again after the final
conn.commit() to reduce WAL bloat, and (4) when updating kg_relations in the
branch that currently uses json.dumps({"source": CODE_INTELLIGENCE_SOURCE}),
merge the existing properties JSON with {"source": CODE_INTELLIGENCE_SOURCE}
(preserve other keys) instead of overwriting; reference the connection variable
conn, _ensure_reconciliation_schema(conn), CODE_INTELLIGENCE_SOURCE and the
kg_relations UPDATE/INSERT logic to locate changes.

---

Outside diff comments:
In `@src/brainlayer/pipeline/code_intelligence.py`:
- Around line 414-427: The update currently overwrites the entire properties
column with {"source": CODE_INTELLIGENCE_SOURCE} which clobbers existing
provenance; instead, fetch the current properties for the matched relation
(kg_relations row id from existing[0]), parse the JSON, merge/augment it so you
add or record CODE_INTELLIGENCE_SOURCE without removing other keys (e.g.,
preserve an existing "source" value by turning it into a list or appending
CODE_INTELLIGENCE_SOURCE, or add a new key like "sources"), then write the
merged JSON back in the UPDATE for the kg_relations row (keep the same UPDATE
fields confidence/valid_from/valid_until/expired_at but replace the hard
overwrite of properties with the merged JSON).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0336d3b0-eb97-4264-a186-48e96a02ca1b

📥 Commits

Reviewing files that changed from the base of the PR and between 5e8c315 and 8169a6a.

📒 Files selected for processing (10)
  • src/brainlayer/eval/benchmark.py
  • src/brainlayer/kg_repo.py
  • src/brainlayer/mcp/_shared.py
  • src/brainlayer/mcp/search_handler.py
  • src/brainlayer/pipeline/code_intelligence.py
  • src/brainlayer/vector_store.py
  • tests/test_code_intelligence.py
  • tests/test_kg_schema.py
  • tests/test_kg_standard.py
  • tests/test_search_filter_params.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Flag risky DB or concurrency changes explicitly and do not hand-wave lock behavior
Enforce one-write-at-a-time concurrency constraint; reads are safe but brain_digest is write-heavy and must not run in parallel with other MCP work
Run pytest before claiming behavior changed safely; current test suite has 929 tests

**/*.py: Use paths.py:get_db_path() for all database path resolution; all scripts and CLI must use this function rather than hardcoding paths
When performing bulk database operations: stop enrichment workers first, checkpoint WAL before and after, drop FTS triggers before bulk deletes, batch deletes in 5-10K chunks, and checkpoint every 3 batches

Files:

  • tests/test_search_filter_params.py
  • src/brainlayer/mcp/_shared.py
  • src/brainlayer/mcp/search_handler.py
  • tests/test_kg_standard.py
  • tests/test_kg_schema.py
  • src/brainlayer/vector_store.py
  • tests/test_code_intelligence.py
  • src/brainlayer/kg_repo.py
  • src/brainlayer/eval/benchmark.py
  • src/brainlayer/pipeline/code_intelligence.py
src/brainlayer/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/brainlayer/**/*.py: Use retry logic on SQLITE_BUSY errors; each worker must use its own database connection to handle concurrency safely
Classification must preserve ai_code, stack_trace, and user_message verbatim; skip noise entries entirely and summarize build_log and dir_listing entries (structure only)
Use AST-aware chunking via tree-sitter; never split stack traces; mask large tool output
For enrichment backend selection: use Groq as primary backend (cloud, configured in launchd plist), Gemini as fallback via enrichment_controller.py, and Ollama as offline last-resort; allow override via BRAINLAYER_ENRICH_BACKEND env var
Configure enrichment rate via BRAINLAYER_ENRICH_RATE environment variable (default 0.2 = 12 RPM)
Implement chunk lifecycle columns: superseded_by, aggregated_into, archived_at on chunks table; exclude lifecycle-managed chunks from default search; allow include_archived=True to show history
Implement brain_supersede with safety gate for personal data (journals, notes, health/finance); use soft-delete for brain_archive with timestamp
Add supersedes parameter to brain_store for atomic store-and-replace operations
Run linting and formatting with: ruff check src/ && ruff format src/
Run tests with pytest
Use PRAGMA wal_checkpoint(FULL) before and after bulk database operations to prevent WAL bloat

Files:

  • src/brainlayer/mcp/_shared.py
  • src/brainlayer/mcp/search_handler.py
  • src/brainlayer/vector_store.py
  • src/brainlayer/kg_repo.py
  • src/brainlayer/eval/benchmark.py
  • src/brainlayer/pipeline/code_intelligence.py
🪛 OpenGrep (1.21.0)
src/brainlayer/pipeline/code_intelligence.py

[ERROR] 83-83: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)


[ERROR] 92-92: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

🔇 Additional comments (14)
src/brainlayer/eval/benchmark.py (10)

6-6: LGTM!

Also applies to: 10-10, 22-22


165-195: LGTM!


204-204: LGTM!

Also applies to: 212-217


231-231: LGTM!


233-245: LGTM!


247-267: LGTM!


269-296: LGTM!


298-303: LGTM!


305-313: LGTM!


315-340: LGTM!

tests/test_kg_schema.py (2)

91-91: LGTM!


130-137: LGTM!

tests/test_kg_standard.py (2)

163-163: LGTM!


230-230: LGTM!

Comment thread src/brainlayer/pipeline/code_intelligence.py Outdated
Comment thread src/brainlayer/pipeline/code_intelligence.py Outdated
Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4eaa1d370d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if not properties:
return False
try:
return json.loads(properties).get("source") == CODE_INTELLIGENCE_SOURCE
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Handle non-object relation properties safely

Guarding json.loads(properties).get("source") assumes every JSON payload is an object, but valid JSON scalars/arrays ("foo", 123, null, [1,2]) raise AttributeError here and crash reconciliation. In that case enrich_projects aborts while expiring/refreshing dependencies, so a single malformed or legacy kg_relations.properties value can stop the entire code-intelligence pass.

Useful? React with 👍 / 👎.

continue
hits += 1
precision_sum += hits / rank
return precision_sum / len(relevant)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Normalize AP@k by cutoff-aware relevant count

The fallback MAP implementation divides AP by len(relevant) even when a cutoff is requested (e.g. map@10), which under-scores runs whenever relevant docs exceed k. For a perfect top-10 with 20 relevant docs this returns 0.5 instead of 1.0, so benchmark comparisons become biased whenever ranx falls back to this path.

Useful? React with 👍 / 👎.

Comment thread src/brainlayer/eval/benchmark.py Outdated
def _ndcg(self, run: dict[str, Any], query_id: str, cutoff: int | None) -> float:
ranked = self._ranked_docs(run, cutoff)
gains = self.qrels.get(query_id, {})
dcg = sum((2 ** gains.get(doc_id, 0) - 1) / math.log2(rank + 2) for rank, doc_id in enumerate(ranked))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use linear-gain formula for ndcg fallback

ndcg fallback is computed with Burges gain (2^rel-1), but the metric name requested in this file is ndcg (not ndcg_burges), so fallback scores diverge from normal ranx ndcg on graded qrels. This changes absolute scores and can reorder pipeline comparisons when ranx is unavailable or errors.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 23, 2026

@coderabbitai review

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 23, 2026

@codex review

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 23, 2026

@cursor @BugBot re-review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 23, 2026

You need to increase your spend limit or enable usage-based billing to run background agents. Go to Cursor

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Comment thread src/brainlayer/pipeline/code_intelligence.py Outdated
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/brainlayer/pipeline/code_intelligence.py
Comment thread src/brainlayer/pipeline/code_intelligence.py
Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1bc7ef8d29

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +640 to +643
FROM kg_current_facts
WHERE target_id = ?
AND relation_type = 'depends_on'
LIMIT 1
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid expiring libraries that still have active facts

When deciding whether to expire a library entity, the liveness check only looks for active depends_on rows, so libraries with other active relations (for example uses_tool) are still marked expired. Because _kg_facts_sql now filters out rows where either endpoint has expired_at, this hides still-valid facts from retrieval even though their relations remain active. Fresh evidence: reproducing with an active uses_tool relation to fastapi still results in fastapi.expired_at being set and _kg_facts_sql(..., "mytool") returning no facts.

Useful? React with 👍 / 👎.

Comment on lines +208 to +212
owner_pid, owner_start_time = _read_pidfile_owner(pidfile)
if owner_pid is not None and _pidfile_owner_matches(owner_pid, owner_start_time):
raise RuntimeError(f"another writer is using {db_path} (pid {owner_pid})")
try:
pidfile.unlink()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve lockfile while owner info may still be written

In the FileExistsError path, an unreadable/empty pidfile is treated as stale and unlinked immediately. There is a race where another writer has created the pidfile but has not finished writing payload yet; _read_pidfile_owner then returns (None, None), this branch deletes the live lockfile, and a second writer can acquire the lock concurrently. That breaks the one-writer guarantee and can reintroduce DB write contention/corruption under concurrent starts.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 23, 2026

@coderabbitai review
@codex review
@cursor @BugBot re-review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

@EtanHey I'll start a review of the changes in this PR right away!

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 635e3db. Configure here.

Comment thread src/brainlayer/pipeline/code_intelligence.py
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/brainlayer/eval/benchmark.py`:
- Around line 333-334: The average-precision computation currently divides
precision_sum by denominator which can become zero or negative when cutoff is 0
or <0; add a guard before computing denominator in the function that uses
precision_sum/relevant/cutoff (the block that sets denominator =
min(len(relevant), cutoff) ...) to validate cutoff: if cutoff is None proceed as
before, but if cutoff <= 0 raise a clear ValueError (or return 0 if you prefer a
silent result) with a message mentioning the invalid cutoff, preventing
ZeroDivisionError and invalid scores.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b44afa44-cd1c-4960-a2b8-e1c55ee57a47

📥 Commits

Reviewing files that changed from the base of the PR and between 8169a6a and 635e3db.

📒 Files selected for processing (8)
  • src/brainlayer/eval/benchmark.py
  • src/brainlayer/mcp/_shared.py
  • src/brainlayer/mcp/search_handler.py
  • src/brainlayer/pipeline/code_intelligence.py
  • tests/test_code_intelligence.py
  • tests/test_eval_framework.py
  • tests/test_search_filter_params.py
  • tests/test_vector_store_readonly.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.12)
  • GitHub Check: Macroscope - Correctness Check
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Flag risky DB or concurrency changes explicitly and do not hand-wave lock behavior
Enforce one-write-at-a-time concurrency constraint; reads are safe but brain_digest is write-heavy and must not run in parallel with other MCP work
Run pytest before claiming behavior changed safely; current test suite has 929 tests

**/*.py: Use paths.py:get_db_path() for all database path resolution; all scripts and CLI must use this function rather than hardcoding paths
When performing bulk database operations: stop enrichment workers first, checkpoint WAL before and after, drop FTS triggers before bulk deletes, batch deletes in 5-10K chunks, and checkpoint every 3 batches

Files:

  • src/brainlayer/mcp/search_handler.py
  • tests/test_vector_store_readonly.py
  • tests/test_search_filter_params.py
  • tests/test_eval_framework.py
  • src/brainlayer/mcp/_shared.py
  • tests/test_code_intelligence.py
  • src/brainlayer/eval/benchmark.py
  • src/brainlayer/pipeline/code_intelligence.py
src/brainlayer/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/brainlayer/**/*.py: Use retry logic on SQLITE_BUSY errors; each worker must use its own database connection to handle concurrency safely
Classification must preserve ai_code, stack_trace, and user_message verbatim; skip noise entries entirely and summarize build_log and dir_listing entries (structure only)
Use AST-aware chunking via tree-sitter; never split stack traces; mask large tool output
For enrichment backend selection: use Groq as primary backend (cloud, configured in launchd plist), Gemini as fallback via enrichment_controller.py, and Ollama as offline last-resort; allow override via BRAINLAYER_ENRICH_BACKEND env var
Configure enrichment rate via BRAINLAYER_ENRICH_RATE environment variable (default 0.2 = 12 RPM)
Implement chunk lifecycle columns: superseded_by, aggregated_into, archived_at on chunks table; exclude lifecycle-managed chunks from default search; allow include_archived=True to show history
Implement brain_supersede with safety gate for personal data (journals, notes, health/finance); use soft-delete for brain_archive with timestamp
Add supersedes parameter to brain_store for atomic store-and-replace operations
Run linting and formatting with: ruff check src/ && ruff format src/
Run tests with pytest
Use PRAGMA wal_checkpoint(FULL) before and after bulk database operations to prevent WAL bloat

Files:

  • src/brainlayer/mcp/search_handler.py
  • src/brainlayer/mcp/_shared.py
  • src/brainlayer/eval/benchmark.py
  • src/brainlayer/pipeline/code_intelligence.py
🔇 Additional comments (20)
src/brainlayer/eval/benchmark.py (1)

293-293: LGTM!

Also applies to: 308-312

tests/test_eval_framework.py (1)

5-5: LGTM!

Also applies to: 91-132

src/brainlayer/mcp/_shared.py (1)

29-30: LGTM!

Also applies to: 50-59

src/brainlayer/mcp/search_handler.py (1)

427-428: LGTM!

tests/test_search_filter_params.py (1)

14-14: LGTM!

Also applies to: 20-45, 48-82

tests/test_vector_store_readonly.py (1)

222-236: LGTM!

src/brainlayer/pipeline/code_intelligence.py (8)

69-72: LGTM!


75-110: LGTM!


113-241: LGTM!


244-270: LGTM!


449-465: LGTM!


470-535: LGTM!


538-614: LGTM!


617-672: LGTM!

tests/test_code_intelligence.py (6)

4-4: LGTM!

Also applies to: 6-6


321-417: LGTM!


419-584: LGTM!


586-624: LGTM!


626-698: LGTM!


700-766: LGTM!

Comment thread src/brainlayer/eval/benchmark.py Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 635e3dbf4e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

python -m brainlayer.pipeline.code_intelligence [--base-dir ~/Gits] [--dry-run]
"""

import fcntl
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Make writer lock import portable across non-Unix platforms

Importing brainlayer.pipeline.code_intelligence now fails on Windows because fcntl is imported at module load time, but Python documents fcntl as Unix-only. That means any workflow that imports this module (including enrich_projects) crashes before execution on Windows hosts, which regresses the cross-platform behavior expected for this package. Please guard this import behind a platform check or move it inside the Unix-specific lock path with a non-Unix fallback.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 23, 2026

@coderabbitai review
@codex review
@cursor @BugBot re-review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

@EtanHey I'll kick off a review of the changes in this PR right away!

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c237216ef7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/brainlayer/eval/benchmark.py Outdated
continue
hits += 1
precision_sum += hits / rank
denominator = min(len(relevant), cutoff) if cutoff is not None else len(relevant)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use full relevant count in MAP@k denominator

When Ranx is unavailable, _average_precision computes map@k with min(len(relevant), k) as the denominator, which inflates scores versus Ranx semantics. For example, with 20 relevant docs and a perfect top-10 ranking, this fallback returns 1.0 while Ranx returns 0.5, so benchmark comparisons become inconsistent exactly in the degraded mode this commit introduced.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 23, 2026

@coderabbitai review
@codex review
@cursor @BugBot re-review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

@EtanHey I'll kick off a fresh review of the changes in this PR right away!

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 332c688399

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +595 to +596
if not _is_code_intelligence_relation(existing[1]):
return target_id
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Revive observed dependency despite soft-closed manual fact

When a depends_on row already exists for the same (source_id, target_id) but is not tagged as code-intelligence, this early return skips any reactivation/update even if the dependency is currently observed in the project scan. If that existing row was previously soft-closed (expired_at set), reconciliation leaves the dependency absent from kg_current_facts, producing a false negative in KG/search despite live evidence in code. This is reproducible with an expired manual relation on the same edge.

Useful? React with 👍 / 👎.

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 23, 2026

@coderabbitai review
@codex review
@cursor @BugBot re-review

Follow-up pushed for current-head Codex finding: observed expired manual depends_on facts are reactivated without taking code_intelligence ownership. Local validation: targeted red/green, focused KG suite, ruff, full non-live pytest, and pre-push gate passed.

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

@EtanHey Thanks for the detailed update! The fix ensuring that observed expired manual depends_on facts are reactivated without transferring code_intelligence ownership sounds like a solid edge-case closure. I'll kick off a fresh review of the latest commits now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 78ca0ac44c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +603 to +607
conn.execute(
"""UPDATE kg_relations
SET valid_from = COALESCE(valid_from, ?),
valid_until = ?, expired_at = NULL
WHERE id = ?""",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve scanner ownership when reviving expired depends_on facts

When an observed depends_on relation already exists but is not tagged as code-intelligence, this branch reactivates it by clearing expired_at without updating properties to include the code-intelligence source. That makes the fact visible again, but future reconciliation skips it because _expire_stale_dependency_relations only expires relations recognized as code-intelligence-owned, so the relation can become permanently stale after the dependency is removed again.

Useful? React with 👍 / 👎.

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 23, 2026

@coderabbitai review
@codex review
@cursor @BugBot re-review

Follow-up pushed for current-head Codex finding: revived expired manual depends_on facts now preserve manual provenance while adding code_intelligence evidence, so later absence scans can expire them again. Local validation: red/green regression, focused KG suite, ruff, full non-live pytest, and pre-push gate passed.

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

@EtanHey Thanks for the detailed context! The provenance-merging fix — reviving expired manual depends_on facts by preserving the original manual source while layering code_intelligence evidence on top — is a clean solution. It correctly keeps the soft-expiry mechanism intact for code-intelligence-managed facts without clobbering manually curated relationships. I'll kick off a fresh review of the latest commits now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/brainlayer/eval/benchmark.py (1)

165-187: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Broad exception silencing in fallback paths may hide root causes.

The fallback mechanism uses bare except Exception: pass in multiple locations (lines 193, 215-216, 243-244, 260-261). While this ensures resilience, it silently swallows all errors including unexpected ones (e.g., TypeError from API changes, MemoryError).

Consider logging the exception at DEBUG level before falling back, so debugging is possible when the fallback is triggered unexpectedly:

♻️ Optional: Add debug logging for suppressed exceptions
+import logging
+
+_logger = logging.getLogger(__name__)
+
 def _run_from_dict(run_dict: dict[str, dict[str, float]]) -> Run:
     try:
         return Run(run=run_dict)
     except Exception:
+        _logger.debug("ranx.Run() failed, applying fallback patch", exc_info=True)
         _patch_ranx_run_fallback()
         return Run(run=run_dict)

Apply similarly to _build_ranx_qrels, evaluate_pipeline, and compare_pipelines.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/brainlayer/eval/benchmark.py` around lines 165 - 187, Replace the bare
"except Exception: pass" in the fallback/backup blocks with an explicit
exception capture and debug log so failures are visible: in _build_ranx_qrels,
evaluate_pipeline, compare_pipelines (and any similar fallback in
_patch_ranx_run_fallback) change to "except Exception as e:" and call the module
logger at DEBUG (e.g., logger.debug("Suppressed exception in <function_name>
fallback", exc_info=True)) before performing the fallback behavior; ensure a
module-level logger is imported/created if missing and avoid catching
BaseException/KeyboardInterrupt by keeping Exception as the caught type.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/brainlayer/eval/benchmark.py`:
- Around line 165-187: Replace the bare "except Exception: pass" in the
fallback/backup blocks with an explicit exception capture and debug log so
failures are visible: in _build_ranx_qrels, evaluate_pipeline, compare_pipelines
(and any similar fallback in _patch_ranx_run_fallback) change to "except
Exception as e:" and call the module logger at DEBUG (e.g.,
logger.debug("Suppressed exception in <function_name> fallback", exc_info=True))
before performing the fallback behavior; ensure a module-level logger is
imported/created if missing and avoid catching BaseException/KeyboardInterrupt
by keeping Exception as the caught type.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 51b85acc-2ee1-415b-909e-ea00d703359b

📥 Commits

Reviewing files that changed from the base of the PR and between 635e3db and 0d1f6ba.

📒 Files selected for processing (6)
  • src/brainlayer/eval/benchmark.py
  • src/brainlayer/pipeline/code_intelligence.py
  • src/brainlayer/vector_store.py
  • tests/test_code_intelligence.py
  • tests/test_eval_framework.py
  • tests/test_kg_schema.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Flag risky DB or concurrency changes explicitly and do not hand-wave lock behavior
Enforce one-write-at-a-time concurrency constraint; reads are safe but brain_digest is write-heavy and must not run in parallel with other MCP work
Run pytest before claiming behavior changed safely; current test suite has 929 tests

**/*.py: Use paths.py:get_db_path() for all database path resolution; all scripts and CLI must use this function rather than hardcoding paths
When performing bulk database operations: stop enrichment workers first, checkpoint WAL before and after, drop FTS triggers before bulk deletes, batch deletes in 5-10K chunks, and checkpoint every 3 batches

Files:

  • src/brainlayer/vector_store.py
  • tests/test_kg_schema.py
  • tests/test_eval_framework.py
  • src/brainlayer/eval/benchmark.py
  • tests/test_code_intelligence.py
  • src/brainlayer/pipeline/code_intelligence.py
src/brainlayer/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/brainlayer/**/*.py: Use retry logic on SQLITE_BUSY errors; each worker must use its own database connection to handle concurrency safely
Classification must preserve ai_code, stack_trace, and user_message verbatim; skip noise entries entirely and summarize build_log and dir_listing entries (structure only)
Use AST-aware chunking via tree-sitter; never split stack traces; mask large tool output
For enrichment backend selection: use Groq as primary backend (cloud, configured in launchd plist), Gemini as fallback via enrichment_controller.py, and Ollama as offline last-resort; allow override via BRAINLAYER_ENRICH_BACKEND env var
Configure enrichment rate via BRAINLAYER_ENRICH_RATE environment variable (default 0.2 = 12 RPM)
Implement chunk lifecycle columns: superseded_by, aggregated_into, archived_at on chunks table; exclude lifecycle-managed chunks from default search; allow include_archived=True to show history
Implement brain_supersede with safety gate for personal data (journals, notes, health/finance); use soft-delete for brain_archive with timestamp
Add supersedes parameter to brain_store for atomic store-and-replace operations
Run linting and formatting with: ruff check src/ && ruff format src/
Run tests with pytest
Use PRAGMA wal_checkpoint(FULL) before and after bulk database operations to prevent WAL bloat

Files:

  • src/brainlayer/vector_store.py
  • src/brainlayer/eval/benchmark.py
  • src/brainlayer/pipeline/code_intelligence.py
🔇 Additional comments (8)
src/brainlayer/eval/benchmark.py (3)

288-295: LGTM!


327-338: LGTM!


190-196: LGTM!

Also applies to: 212-217, 269-286, 297-325, 340-345

tests/test_eval_framework.py (1)

91-141: LGTM!

src/brainlayer/vector_store.py (1)

1313-1315: LGTM!

tests/test_kg_schema.py (1)

15-15: LGTM!

Also applies to: 140-161

src/brainlayer/pipeline/code_intelligence.py (1)

25-28: LGTM!

Also applies to: 214-215, 589-610

tests/test_code_intelligence.py (1)

421-424: LGTM!

Also applies to: 465-555, 827-839

@EtanHey EtanHey merged commit a44f758 into main May 23, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant