Skip to content

DEV-1478: cloud DB conn re-anchor + Mode-B filter normalization - #6

Merged
ZmeiGorynych merged 6 commits into
mainfrom
egor/dev-1478-otf-kb-encoder-vs-hand-audited-reference-households-failure
May 28, 2026
Merged

DEV-1478: cloud DB conn re-anchor + Mode-B filter normalization#6
ZmeiGorynych merged 6 commits into
mainfrom
egor/dev-1478-otf-kb-encoder-vs-hand-audited-reference-households-failure

Conversation

@ZmeiGorynych

@ZmeiGorynych ZmeiGorynych commented May 28, 2026

Copy link
Copy Markdown
Member

Follow-up to #4 (merged). Two commits that landed on the branch after #4 merged — opening a fresh PR so CI + CodeRabbit run on them.

Summary

  • c1c77c4 — re-anchor OTF datasource connection_string in the cloud. The on-the-fly deterministic cache bakes in an absolute local sqlite path; the OTF storage paths only resolved relative connection strings, so a locally-built cache transported into a cloud container kept a nonexistent /home/... path → every agent's + setup-encoder's SLayer query tool failed unable to open database file (all 53 instances in the last full run flew blind). New reanchor_connection_string force-rewrites stale-foreign-absolute paths to <root>/<db>/<db>.sqlite; wired into all three OTF storage sites (build_task_variant_storage, slayer_otf/runtime.py, reference_build.py). Phase-1 eval was unaffected (different DB path), which is why this hid behind plausible-looking scores.

  • e224616 — deterministic case/whitespace normalization of Mode-B query filters. NL questions carry no casing info, so a text-equality filter should match all variants ('Apartment'/'apartment'/' apartment '). New slayer_pipeline/filter_normalization.py parses Mode-B (reusing SLayer's own _preprocess_sql_operators), and for in-scope ==/!=/in/not in against string literals wraps the column in lower(trim(...)) + lowercases the literal. Applied at every in-repo query surface: submit_slayer_query, the OTF-encode process_tool_call facade (before the literal-existence validator), and a new recursive-adapter facade. Mode-A SQL the encoder writes is governed by a strengthened STYLE_GUIDE rule scoped emphatically to filter predicates only. All in-prompt exemplars rephrased to synthetic schemas (no eval-set content).

Test plan

  • Full non-integration suite green: 1241 passed, 92 skipped, 19 deselected
  • New unit coverage: tests/slayer_pipeline/test_portable_connection.py, tests/test_hard8_preprocessor.py, tests/test_slayer_otf_reference_build.py (connection re-anchor); tests/slayer_pipeline/test_filter_normalization.py (33 cases)
  • Codex-reviewed (plan + diff) for both changes
  • CI on this PR
  • CodeRabbit review on this PR
  • End-to-end: re-run a households cloud smoke (agents now non-blind) to confirm case-mismatch wrong_result losses are gone

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Deterministic filter normalization applied to submitted queries and tool calls; dual-eval audited/original fields and metrics are now produced and persisted.
    • Missing local deterministic DB caches are auto-built to allow submission to continue.
  • Bug Fixes

    • Re-anchored stale SQLite connection paths to the current environment.
    • Preserve original solution SQL consistently for dual-eval scoring.
  • Documentation

    • Refined guidance for SQL normalization and encoder prompts.
  • Tests

    • Added tests for filter normalization, portable connections/reanchoring, cache building, and dual-eval plumbing.

Review Change Stack

ZmeiGorynych and others added 2 commits May 28, 2026 11:01
…-1478)

Failure-mode analysis of the 53-instance cloud run found every agent
(and 15-30 of each DB's ~50 setup encoders) hit "Database error: unable
to open database file" on its SLayer query tool — the dominant driver of
the apparent OTF-vs-hand-audited regression (23 vs 30), which is really a
blind-cloud-vs-self-validating-local confound plus brittle ex_base
comparator artifacts and gold defects.

Root cause: the on-the-fly deterministic cache bakes in an ABSOLUTE
sqlite path from the machine that built it (e.g.
sqlite:////home/<user>/.../mini-interact/<db>/<db>.sqlite). The OTF
storage paths re-anchored that path via to_portable→resolve or
resolve-only, both of which PASS A FOREIGN ABSOLUTE PATH THROUGH
UNCHANGED — so a locally-built cache transported into a cloud container
(DB at /data/mini-interact/...) kept the nonexistent local path. Phase-1
eval still worked (it resolves data_path_base from $BIRD_DB_PATH on a
different code path), so only the agent's + encoder's interactive query
tool was blinded. The recursive on-the-fly path was immune because
prepare_task_storage force-rewrites via an _expected_connection_string
helper.

Fix: new `reanchor_connection_string(conn, db, root)` in
slayer_pipeline.portable_connection — relative form resolves against the
root (path preserved, unchanged behaviour); absolute form (incl. the
malformed 5-slash variant) is force-rewritten to the canonical
<root>/<db>/<db>.sqlite ($BIRD_DB_PATH wins). All three OTF datasource
re-anchor sites now delegate to it:
  - hard8_preprocessor.build_task_variant_storage (per-task agent storage)
  - slayer_otf/runtime.py (recursive on-the-fly per-task; dedup of its
    private _expected_connection_string)
  - slayer_otf/reference_build.py::_resolve_datasource_for_build
    (setup-encode build — Codex follow-up; the encoder's own query tool
    was hitting the same error)
The commit-time _portabilise_datasource still emits the relative portable
form for the uploaded/committed reference (fetch-back re-anchors locally).

Tests (1209 passed, +13): portable_connection unit cases for
expected/reanchor (relative resolve, stale-foreign-absolute force,
$BIRD_DB_PATH override, 5-slash normalisation, non-sqlite passthrough);
hard8 + reference_build integration cases asserting a foreign-absolute
cache path is re-anchored to the current root with no foreign-path leak.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lters (DEV-1478)

The 53-task failure analysis found case/whitespace mismatch on text
filters causing wrong_result losses (e.g. an agent's `= 'Apartment'`
missing 'apartment'/' apartment '). The NL questions carry no casing
info, so a text-equality filter semantically matches all variants;
relying on the LLM to remember LOWER(TRIM) is unreliable. Fix:
deterministically normalize text-equality FILTER predicates wherever a
SLayer query flows through this repo's tools.

New `slayer_pipeline/filter_normalization.py`:
* `normalize_mode_b_filter` — Mode-B filters are Python-expression
  syntax, so reuse SLayer's own `_preprocess_sql_operators` (=→==, <>→!=,
  keyword-lowercase; user owns SLayer, reuse over reinvent) then
  `ast.parse`/NodeTransformer/`ast.unparse`. For in-scope comparisons
  (single op Eq/NotEq/In/NotIn, RHS all string literals without `{...}`
  placeholders, LHS a column ref possibly already lower/trim-wrapped):
  canonicalize the LHS to `lower(trim(col))` AND lowercase the
  literal(s). Idempotent (canonical form is a fixed point); fail-safe
  no-op on anything out of scope (LIKE, colon/func aggregations, chained
  compares, numeric/placeholder RHS, non-column LHS, unparseable).
* `normalize_query_payload` (submit path: dict | list of stages) and
  `normalize_tool_filters` (facade: dispatch by tool — query→filters,
  query_nested→queries, create_model→query stages, edit_model→
  source_queries; deep-copied, never mutates input). Mode-A
  add_filters/remove_filters left alone.

Applied at every in-repo SLayer-query surface (no SLayer changes):
* `_submit.py::submit_slayer_query` — normalize before compile (the
  scored path for BOTH adapters). Recorded `submitted_query` stays the
  agent's original DSL; only the compiled `submitted_sql` reflects it.
* otf_encode `_process_tool_call` — normalize tool_args before the
  literal-existence validator (which then runs post-transform; its
  casefold-when-wrapped branch matches the normalized filter).
* recursive adapter `_build_shared_slayer_server` — a new
  process_tool_call normalize-then-forward hook, for apples-to-apples
  parity with the OTF path's exploratory queries.

Mode-A SQL the encoder writes (Column.sql/filter CASE-WHENs) is the
encoder's responsibility: STYLE_GUIDE STRING-NORM is strengthened and
**scoped emphatically to FILTER predicates only** (WRONG/RIGHT
projection example — never normalize a projected/grouped/joined column).

Prompt hygiene: rephrased every real-households exemplar embedded in
the STYLE_GUIDE / SETUP_ENCODER prompt (Tenure_Type / Income_Bracket /
Dwelling_Class caveats; the host-choice, cross-model, and
value-illustration worked examples) into SYNTHETIC fictional schemas
that preserve structure — no eval-set table/column/value/KB-id in any
prompt (per feedback_prompts_synthetic_examples_only).

Tests: 33 cases in tests/slayer_pipeline/test_filter_normalization.py
(== / SQL-style = / <> / IN / not in / already-wrapped-uppercase-literal
/ partial wrap / dotted col / {placeholder} / numeric / compound /
LIKE / colon-agg / combined-agg-boundary / unparseable no-ops; per-tool
arg dispatch; deep-copy non-mutation). Full non-integration suite: 1241
passed, 92 skipped, 19 deselected (was 1209; +32). Codex-reviewed (plan
+ diff).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@linear

linear Bot commented May 28, 2026

Copy link
Copy Markdown

DEV-1478

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3297e78f-f1a3-4d4e-89bd-b371fff8bf29

📥 Commits

Reviewing files that changed from the base of the PR and between f975b06 and 168809d.

📒 Files selected for processing (1)
  • tests/cloud/test_driver.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/cloud/test_driver.py

📝 Walkthrough

Walkthrough

Deterministic Mode-B filter normalization and portable SQLite connection re-anchoring are added, normalization is integrated into submit/encoder/recursive MCP flows, re-anchoring is applied in build/runtime/hard8 paths, prompt guidance is updated, dual-eval golds and metrics are wired, and tests cover these behaviors.

Changes

Filter Normalization and Connection String Re-anchoring

Layer / File(s) Summary
Filter Normalization Core
src/bird_interact_agents/slayer_pipeline/filter_normalization.py, tests/slayer_pipeline/test_filter_normalization.py
New module adds deterministic Mode-B filter text-equality normalization via Python AST transformation to canonical lower(trim(<col>)) == '<lower>' forms. Public entrypoints normalize_mode_b_filter, normalize_query_payload, and normalize_tool_filters apply normalization to single filters, query payloads (dict or stage-list), and MCP tool arguments while preserving caller inputs via deep copy. Comprehensive tests validate in-scope vs out-of-scope rewrites, payload handling, and tool-argument dispatch.
Connection String Re-anchoring Core
src/bird_interact_agents/slayer_pipeline/portable_connection.py, tests/slayer_pipeline/test_portable_connection.py
New helpers expected_connection_string and reanchor_connection_string compute canonical absolute SQLite URIs and re-anchor connection strings to the current root (respecting $BIRD_DB_PATH), classifying inputs by sqlite: slash count and preserving non-sqlite inputs. Tests cover foreign absolute rewrite, malformed 5-slash normalization, relative committed forms, and env-root precedence.
Prompt Guidance Updates
src/bird_interact_agents/agents/pydantic_ai_otf_encode/prompts.py
Refined _STYLE_GUIDE and SETUP_ENCODER_PROMPT examples and STRING-NORM wording to restrict normalization to predicate/filter positions and updated illustrative worked examples.
Submit Query Integration
src/bird_interact_agents/agents/_submit.py
Imports normalize_query_payload and applies it in submit_slayer_query immediately after JSON shape validation and before SQL compilation, ensuring the compiled SQL reflects normalized FILTER predicates while the submitted query record retains the original DSL.
OTF Encoder MCP Integration
src/bird_interact_agents/agents/pydantic_ai_otf_encode/agent.py
Imports normalize_tool_filters and hooks the shared MCP server's process_tool_call to normalize incoming tool_args before validation/persistence, aligning edit/create model FILTER handling with the canonical text form.
Recursive Adapter MCP Integration
src/bird_interact_agents/agents/pydantic_ai_recursive/agent.py
Imports normalize_tool_filters and wires the shared MCPServerStdio process_tool_call hook to normalize query/query_nested/create_model/edit_model arguments, keeping exploratory and eval paths aligned on case/whitespace handling.
Build/Runtime Connection Re-anchoring
src/bird_interact_agents/hard8_preprocessor.py, src/bird_interact_agents/slayer_otf/reference_build.py, src/bird_interact_agents/slayer_otf/runtime.py, tests/test_hard8_preprocessor.py, tests/test_slayer_otf_reference_build.py
Applies reanchor_connection_string across per-task variant build, reference build, and runtime datasource rewrite to ensure cached foreign absolute SQLite paths are re-anchored to the current run root; tests validate foreign path rewriting and $BIRD_DB_PATH precedence.
Dual-eval Gold Preservation and Metrics
src/bird_interact_agents/harness.py, src/bird_interact_agents/cloud/collation.py, tests/cloud/test_collation.py, tests/test_dual_eval.py
Preserves original_sol_sql for each task before audited overlay, persists audited/original Phase 1 verdicts and observations into results.db, extends _build_metrics to report dual-eval counts and audited/original rates, and adds tests covering DB columns, collate output, and evaluation plumbing.
Driver: Build Missing OTF Caches
src/bird_interact_agents/cloud/driver.py, tests/cloud/test_driver.py
Adds local building of missing deterministic slayer_otf_cache via ensure_db_cache (invoked with asyncio.run) instead of fail-fast; updates _check_slayer_setup_present and driver tests to assert self-healing cache build and continued submission.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • MotleyAI/bird-agents#4: Overlapping changes to pydantic_ai_otf_encode MCP tool-call handling and normalization prior to validator steps.
  • MotleyAI/bird-agents#3: Related cloud driver changes affecting _check_slayer_setup_present and OTF cache handling.

Poem

🐰 I nibble strings and tidy their case,
lower(trim(...)) finds a neat little place.
Old SQLite paths I gently retie,
caches now point where the containers lie.
DEV fixes stitched — a small hop, happy sigh.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.51% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main changes: cloud DB connection re-anchoring and Mode-B filter normalization, matching the substantive commits and file modifications.
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.

✏️ 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 egor/dev-1478-otf-kb-encoder-vs-hand-audited-reference-households-failure

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/bird_interact_agents/agents/pydantic_ai_otf_encode/prompts.py`:
- Line 143: In the prompt text containing "PREPEND a 1–2 sentence caveat"
replace the Unicode EN DASH (–) with an ASCII hyphen (-) so the phrase becomes
"PREPEND a 1-2 sentence caveat" to satisfy Ruff RUF001; update the string
literal in prompts.py where that exact phrase appears.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: de99ef38-32d6-4433-870a-4b54ed3de2a2

📥 Commits

Reviewing files that changed from the base of the PR and between 22d6127 and e224616.

📒 Files selected for processing (13)
  • src/bird_interact_agents/agents/_submit.py
  • src/bird_interact_agents/agents/pydantic_ai_otf_encode/agent.py
  • src/bird_interact_agents/agents/pydantic_ai_otf_encode/prompts.py
  • src/bird_interact_agents/agents/pydantic_ai_recursive/agent.py
  • src/bird_interact_agents/hard8_preprocessor.py
  • src/bird_interact_agents/slayer_otf/reference_build.py
  • src/bird_interact_agents/slayer_otf/runtime.py
  • src/bird_interact_agents/slayer_pipeline/filter_normalization.py
  • src/bird_interact_agents/slayer_pipeline/portable_connection.py
  • tests/slayer_pipeline/test_filter_normalization.py
  • tests/slayer_pipeline/test_portable_connection.py
  • tests/test_hard8_preprocessor.py
  • tests/test_slayer_otf_reference_build.py

Comment thread src/bird_interact_agents/agents/pydantic_ai_otf_encode/prompts.py Outdated
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Actionable comments posted: 0

… (DEV-1478)

Cloud `collation._row_to_task_result_row` omitted the four dual-eval
fields, so `results.db` showed NULL for the original-gold score on every
row even though the row JSON / eval.json carried the scored values. Add
the fields (mirroring the local run.py writer) and emit the dual
aggregate in the cloud eval.json for parity.

Also make `apply_audited_gold_overlay` set `original_sol_sql` for EVERY
task (not just edited/unrecoverable), so every row dual-evaluates against
the canonical gold; evaluate_dual_gold short-circuits identical golds so
clean rows cost no extra evaluator call.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/bird_interact_agents/cloud/collation.py`:
- Around line 129-133: The original-counting logic is inconsistent:
`phase1_count_original`/`p1_original` is currently computed across all rows
while `n_dual` only counts rows with non-NULL audited values, causing mismatched
denominators; change the original-pass counts to use the same eligibility filter
as audited (i.e., only rows where r.get("phase1_passed_audited") is not None).
Concretely, update `p1_original`/`phase1_count_original` to sum only over
`canonical_rows` where `phase1_passed_audited` is not None and
`phase1_passed_original` is true, keeping `n_dual`, `p1_audited`, and
`phase1_rate_original` calculations consistent; apply the same fix to the other
occurrence around the `phase1_rate_original` computation (the block referenced
at the second location).
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fd46615f-ef19-4949-9017-7f90684adbb8

📥 Commits

Reviewing files that changed from the base of the PR and between 9df402a and 8db5ccf.

📒 Files selected for processing (4)
  • src/bird_interact_agents/cloud/collation.py
  • src/bird_interact_agents/harness.py
  • tests/cloud/test_collation.py
  • tests/test_dual_eval.py

Comment thread src/bird_interact_agents/cloud/collation.py
…V-1478)

`_check_slayer_setup_present` used to fail-fast when the REQUIRED
`slayer_otf_cache` was absent. Since that cache is free + deterministic
(no LLMs), build it locally via `ensure_db_cache` and proceed instead of
erroring. Non-buildable required artifacts (e.g. `slayer_models`) still
fail fast.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
tests/cloud/test_driver.py (1)

707-717: ⚡ Quick win

Assert ensure_db_cache call kwargs in the new auto-build tests.

These tests currently prove that building is triggered, but not where it builds. Add assertions for cache_root, mini_interact_root, and force=False to lock the contract and catch path-root regressions early.

✅ Suggested test strengthening (example pattern)
-    built: list[str] = []
+    built: list[str] = []
+    seen_kwargs: list[dict] = []

     async def _fake_cache(db, **kw):
         built.append(db)
+        seen_kwargs.append(kw)
@@
     assert dbs == ["db_a", "db_b"]
     assert sorted(built) == ["db_a", "db_b"]
+    assert all(kw["cache_root"] == driver.paths.slayer_otf_cache_root() for kw in seen_kwargs)
+    assert all(kw["mini_interact_root"] == driver.paths.mini_interact_root() for kw in seen_kwargs)
+    assert all(kw["force"] is False for kw in seen_kwargs)

As per coding guidelines **/*.py: “Never depend on a path inside repo_root for gitignored data ... Always use bird_interact_agents.paths.*_root() helpers...”.

Also applies to: 730-739, 974-983

🤖 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 `@tests/cloud/test_driver.py` around lines 707 - 717, The test replaces
driver.ensure_db_cache with _fake_cache but only asserts which DBs were built;
update the fake to capture kwargs and assert that ensure_db_cache was called
with cache_root and mini_interact_root coming from the
bird_interact_agents.paths.*_root() helpers and force=False; locate the usage in
this test around driver._check_slayer_setup_present and FakeSubmitArgs and add
assertions that the captured kwargs include cache_root, mini_interact_root, and
force==False (and apply the same pattern to the other similar test blocks at the
indicated ranges).
src/bird_interact_agents/cloud/driver.py (1)

245-255: ⚡ Quick win

Use a single event loop for _build_missing_otf_caches
ensure_db_cache’s locking is loop-bound (_get_lock keys asyncio.Lock by (id(event_loop), db)), so the current per-DB asyncio.run(...) recreates locks on a new event loop each iteration (extra churn + harder reasoning). Switch _build_missing_otf_caches to asyncio.run once and await ensure_db_cache(...) for all dbs within that same loop.

🤖 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/bird_interact_agents/cloud/driver.py` around lines 245 - 255, The loop
currently calls asyncio.run(...) per-db which creates a new event loop each
iteration; change _build_missing_otf_caches to run asyncio.run once over an
async helper that iterates the dbs and awaits ensure_db_cache(...) for each db
so all locks from _get_lock (which keys asyncio.Lock by (id(event_loop), db))
are created on the same loop; specifically, create an async inner function
(e.g., async def _run_all()) that loops over dbs and awaits ensure_db_cache(db,
cache_root=cache_root, mini_interact_root=mi_root, force=False) and then call
asyncio.run(_run_all()) instead of per-db asyncio.run calls.
🤖 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.

Nitpick comments:
In `@src/bird_interact_agents/cloud/driver.py`:
- Around line 245-255: The loop currently calls asyncio.run(...) per-db which
creates a new event loop each iteration; change _build_missing_otf_caches to run
asyncio.run once over an async helper that iterates the dbs and awaits
ensure_db_cache(...) for each db so all locks from _get_lock (which keys
asyncio.Lock by (id(event_loop), db)) are created on the same loop;
specifically, create an async inner function (e.g., async def _run_all()) that
loops over dbs and awaits ensure_db_cache(db, cache_root=cache_root,
mini_interact_root=mi_root, force=False) and then call asyncio.run(_run_all())
instead of per-db asyncio.run calls.

In `@tests/cloud/test_driver.py`:
- Around line 707-717: The test replaces driver.ensure_db_cache with _fake_cache
but only asserts which DBs were built; update the fake to capture kwargs and
assert that ensure_db_cache was called with cache_root and mini_interact_root
coming from the bird_interact_agents.paths.*_root() helpers and force=False;
locate the usage in this test around driver._check_slayer_setup_present and
FakeSubmitArgs and add assertions that the captured kwargs include cache_root,
mini_interact_root, and force==False (and apply the same pattern to the other
similar test blocks at the indicated ranges).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 832c1547-8273-4df7-84d5-52f9677fce0c

📥 Commits

Reviewing files that changed from the base of the PR and between 8db5ccf and f975b06.

📒 Files selected for processing (2)
  • src/bird_interact_agents/cloud/driver.py
  • tests/cloud/test_driver.py

CodeRabbit quick-win on PR #6: lock the worktree-safe contract by
asserting `ensure_db_cache` is called with the resolved `cache_root` /
`mini_interact_root` and `force=False`, catching wrong-root regressions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Actionable comments posted: 0

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