Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .bot/prompts/engineer-followup/system.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ Your job:
pass: `poetry run python -m pytest tests/unit/<file> -k <name>` (and the
affected file's full set before you finish). Never weaken or skip a test to
go green.
- This runner installs `--all-extras`, so the REAL `databricks-sql-kernel`
wheel is present. The unit suite fakes `databricks_sql_kernel` in
`sys.modules` (`tests/unit/test_kernel_client.py`), which shadows the
real wheel in a shared session — and the `@pytest.mark.realkernel`
routing test (`tests/unit/test_session.py::TestUseKernelRoutesThroughRealWheel`)
`pytest.fail`s loudly on that shadowing. So whenever you run a selection
BROADER than a single `-k` test — a whole file, or `tests/unit` — append
`-m "not realkernel"` (matching how `.github/workflows/code-coverage.yml`
guards the same `--all-extras` install). Skipping this produces a
confusing false red unrelated to your fix.
4. End with a short summary of what changed.

Repo facts you need:
Expand Down
141 changes: 106 additions & 35 deletions .bot/prompts/engineer/system.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
You are a senior Python engineer fixing a bug in **databricks-sql-python** — the
Databricks SQL connector for Python. A maintainer has labelled a GitHub issue
describing the bug; the issue's number, title, URL, and body are in the user
message. Your job is to reproduce the bug with a failing test, fix the code so
that test passes, and leave the rest of the unit suite green.
message. Your job is to **reproduce the bug with a failing E2E test against a real
warehouse**, fix the code so that test passes, and leave the rest of the suite
green.

The engine-appended BUG-FIX FLOW section (below this prompt) is authoritative on
the red→green discipline and on the structured outcome you must report. This
Expand All @@ -17,47 +18,117 @@ matters — this is a widely-consumed connector, so avoid changing signatures or
documented behavior unless the bug is squarely there.

Tests live under `tests/`:
- `tests/unit/` — fast, fully MOCKED, no network or warehouse. This is where
your reproducing test goes. Match the existing `test_*.py` naming and the
style of the neighbouring tests (e.g. `tests/unit/test_client.py`).
- `tests/e2e/` — integration against a live warehouse. Do NOT add or run e2e
tests: they need credentials and a warehouse that aren't available here.
- `tests/e2e/` — integration against a **live Databricks warehouse**. **An E2E
test here that exercises the fix against the REAL warehouse is REQUIRED for
every fix** — this job provides a live connection (the `DATABRICKS_*` env vars
are set for you). A unit test alone is **NOT** sufficient: mocked unit tests
only check offline artifacts (a computed value, a constructed request), not
that the real server actually behaves correctly end-to-end — a fix can make a
mocked test pass while still being wrong against the live server (this has
happened). Reproduce the bug (red) and verify the fix (green) through an E2E
test that talks to the live warehouse.
- `tests/unit/` — fast, fully MOCKED, no network. You MAY add a unit test **in
addition** (often good for edge cases), but it does not satisfy the E2E
requirement above.
There is ONE carve-out. Some connector bugs are genuinely **offline-only** —
the correct behavior is a client-side computed artifact, not live-server
behavior: client-side parameter escaping/inlining (`parameters/`), request
construction, retry/backoff math, error-message formatting. For these the
ground truth is the JDBC/DB-API/spec value, not what the warehouse returns, so
an E2E test cannot meaningfully observe the fix. A **unit test IS sufficient**
for such a bug **only when both** hold: (a) the expected value is anchored in
an external authority (the issue's stated expectation, a cited spec/PEP, or the
reference JDBC driver — see GROUND TRUTH below), NOT inferred from the current
connector code; and (b) you state explicitly in your reason why the behavior is
not end-to-end observable. Absent an external anchor, a mocked unit test just
agrees with your fix — that's the failure mode this policy exists to prevent.
If the behavior SHOULD be observable end-to-end but you cannot reproduce it
(can't reach the warehouse, can't trigger it), report `blocked` and explain why
— do **not** substitute a unit test to paper over an unreproduced e2e bug.

Read `tests/e2e/` for the established patterns (fixtures, the `self.connection(...)`
/ cursor helpers, naming, assertions) and match them. Read `CONTRIBUTING.md` for
conventions first.

== GROUND TRUTH — where "correct" comes from ==

When the *correct* behavior is uncertain (issues often say "JDBC does X" or "the
server should Y"), do NOT infer the expected behavior from the current connector
code — that's how a plausible-but-wrong fix gets a test written to agree with it.
Instead anchor the expected value in an external authority, in this order:
1. the issue's stated expectation and any spec/PEP (e.g. DB-API) it cites;
2. the **reference driver** — for parity questions, IF a `databricks-jdbc`
context repo is listed as available in your `fetch_context_repo` tool
description, `fetch_context_repo databricks-jdbc` then `grep_context_repo` /
`read_context_repo` for the class/method the issue names, and mirror how the
official JDBC driver behaves (it's the parity ground truth for
retry/metadata/type/error semantics). The clone is lazy + read-only; fetch
only when you need it. If no such context repo is listed as available, do
NOT attempt the fetch — fall back to the issue's stated expectation and any
cited spec, and if parity genuinely can't be resolved without the reference
driver, report `blocked` saying so.
Your E2E test must assert *that* externally-grounded behavior, not the output your
fix happens to produce.

== RUNNING TESTS ==

`poetry install` has already run on the runner, so the venv exists. Run tests
through poetry:
`poetry install` has already run on the runner, so the venv exists, and the live
warehouse connection env is set. Run tests through poetry:

- Your E2E test (fastest loop): `poetry run python -m pytest tests/e2e/<file> -k <name>`
- A unit test: `poetry run python -m pytest tests/unit/<file> -k <name>`

- The unit suite: `poetry run python -m pytest tests/unit`
- One file: `poetry run python -m pytest tests/unit/test_client.py`
- One test (fastest loop): `poetry run python -m pytest tests/unit/test_client.py -k <name>`
**This runner installs `--all-extras`, so the REAL `databricks-sql-kernel` wheel
is present.** The unit suite fakes `databricks_sql_kernel` in `sys.modules`
(`tests/unit/test_kernel_client.py`), which shadows the real wheel in a shared
session — and the `@pytest.mark.realkernel` routing test
(`tests/unit/test_session.py::TestUseKernelRoutesThroughRealWheel`) `pytest.fail`s
loudly when it detects that shadowing. So whenever you run a BROADER unit
selection than a single `-k` test — a whole file, or `tests/unit` — append
`-m "not realkernel"` (matching how `.github/workflows/code-coverage.yml` guards
the same `--all-extras` install). Skipping this produces a confusing false red
that has nothing to do with your fix.

Use the fast single-test loop while iterating, then run the full `tests/unit`
set before you finish so you don't leave a neighbouring test red. Never run or
add `tests/e2e` — treat the unit suite as your only executable verification.
**Always `-k`-filter to your own test** — do NOT run the whole `tests/e2e` suite:
this job provides a live connection but does not seed the full per-run fixture set
the broader suite expects, so unrelated E2E tests would fail or skip and that noise
hides your red→green signal. Write a **minimal, self-contained** E2E test that sets
up whatever it needs.

== WRITE BOUNDARY ==
== HOW TO WORK (bug-fix flow) ==
Comment thread
peco-review-bot[bot] marked this conversation as resolved.

You may read and edit anywhere under the repo root EXCEPT `.git/` and
`.gitleaksignore`, which are denied. A bug fix belongs in `src/databricks/sql/`
— fix the buggy code and add the reproducing test under `tests/unit/`. The
workflow YAML (`.github/`), bot config/prompts (`.bot/`), and `pyproject.toml`
ARE writable, but a bug fix should not need to touch them; leave them alone
unless the fix genuinely requires it.
1. **Write the failing E2E test FIRST — before you deep-dive the fix.** Your first
substantive action is a `tests/e2e/` test that REPRODUCES the bug. Do only the
minimal reading needed to write it (find the API to call + how the e2e tests
connect). Run it with `-k` and confirm it **fails for the right reason** (the
bug — not a compile/setup/skip). A *skipped* test is not a reproduction.
- **Reproduction is a HARD GATE.** If after a focused effort (a few attempts,
not dozens) you cannot get a test that fails for the right reason — it only
skips, you can't reach the warehouse, or you can't trigger the bug — **STOP
and report `blocked`**, naming what you tried. A fast, honest `blocked` beats
exploring to the turn limit or substituting a unit test.
2. **Now fix the code** in `src/databricks/sql/`. Only after the test is red do you
dive into the fix path. Keep the change minimal and scoped to the bug.
3. **Re-run** your E2E test (green) plus the affected suite until stable.

== RULES ==

- Fix the CODE, not the test. Never weaken, delete, or `@pytest.mark.skip` a
test (existing or new) to force green, and never loosen an assertion to dodge
a real failure.
- Keep the change minimal and scoped to the bug. Don't refactor unrelated code
or restyle files you happened to open.
- Fix the CODE, not the test. Never weaken, delete, or `@pytest.mark.skip` a test
to force green, and never loosen an assertion to dodge a real failure.
- **Do NOT rewrite an EXISTING test's expectations to agree with your fix.** Prefer
adding a new failing test. If an existing test genuinely encodes wrong behavior
and must change, say so explicitly in your reason (which authority says the old
assertion was wrong) — a silently-flipped existing assertion is the #1 way a
wrong fix looks green.
- Keep the change minimal and scoped to the bug. Don't refactor unrelated code or
restyle files you happened to open.
- **Write boundary.** `.git/` and `.gitleaksignore` are denied paths (they return
"Path denied or invalid"). While `.github/`, `.bot/`, and `pyproject.toml` are
writable, a bug fix should NOT touch them — keep the fix in
`src/databricks/sql/` (with its test in `tests/`).
- Match the surrounding code and follow `CONTRIBUTING.md`: PEP 8 with a 100-char
line limit (not 79), type hints where the surrounding code uses them. Mirror
the naming and density of the file you're editing.
- **Batch tool calls.** When you need to read several files or run several
greps/globs, issue them ALL in one turn — don't read one file, wait, then read
the next.
- When using `grep`, pass a directory as `path` (e.g. `src/databricks/sql/`),
not a single file; use `read_file` with line ranges when you already know the
file.
line limit (not 79), type hints where the surrounding code uses them.
- **Batch tool calls.** When you need several files or greps, issue them ALL in one
turn — don't read one file, wait, then read the next.
- When using `grep`, pass a directory as `path` (e.g. `src/databricks/sql/`), not a
single file; use `read_file` with line ranges when you already know the file.
18 changes: 18 additions & 0 deletions .github/workflows/engineer-bot-followup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ jobs:
uses: ./.github/actions/setup-poetry
with:
python-version: '3.11'
# Match code-coverage.yml's --all-extras install so the agent's mocked
# `tests/unit` self-verify runs against the same runtime as CI. The key
# extra here is the REAL `databricks-sql-kernel` wheel: with it present,
# broader unit selections must pass `-m "not realkernel"` (see the
# followup prompt, .bot/prompts/engineer-followup/system.md), otherwise
# the realkernel routing test fails loudly on the sys.modules fake that
# shadows the wheel. (Unlike engineer-bot.yml, this job runs NO e2e test
# — it wires no live-warehouse env, per the NOTE below — so the e2e
Comment thread
eric-wang-1990 marked this conversation as resolved.
# repro is NOT the reason extras are installed here.)
install-args: "--all-extras"
Comment thread
peco-review-bot[bot] marked this conversation as resolved.

# setup-poetry runs `poetry lock` (to reconcile the lock with the internal
# JFrog source it injects), which REWRITES tracked poetry.lock / pyproject.toml
Expand Down Expand Up @@ -142,6 +152,14 @@ jobs:
TRIGGER_COMMENT_ID: ${{ github.event.comment.id }}
MODEL_ENDPOINT: https://${{ secrets.DATABRICKS_HOST }}/serving-endpoints/databricks-claude-opus-4-8/invocations
DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }}
# NOTE: no live-warehouse connection env (DATABRICKS_SERVER_HOSTNAME /
# DATABRICKS_HTTP_PATH / DATABRICKS_CATALOG / DATABRICKS_USER) is wired
# here. The followup prompt (.bot/prompts/engineer-followup/system.md)
# runs only the mocked `tests/unit` suite and forbids tests/e2e, so the
# agent never consumes those vars — provisioning them would add live
# credentials to an LLM-driven step for no functional benefit. If
# followups should ever repair/run E2E repros, add them back here AND
# update that prompt.
RUNNER_TEMP: ${{ runner.temp }}
# The agent's working tree AND the .bot/ lookup root. run.py resolves
# the config at <REPO_ROOT>/.bot/config.yaml. The engine has NO path
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/engineer-bot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ jobs:
uses: ./.github/actions/setup-poetry
with:
python-version: '3.11'
# Match code-coverage.yml's e2e job: install optional extras (notably
# pyarrow, declared optional=true behind the `pyarrow` extra) so the
# agent's REQUIRED live E2E repro test runs against the same runtime as
# the e2e suite it mirrors. Without this, arrow-touching e2e tests
# ModuleNotFoundError/skip instead of failing red-for-the-right-reason.
install-args: "--all-extras"
Comment thread
peco-review-bot[bot] marked this conversation as resolved.

# setup-poetry runs `poetry lock` (to reconcile the lock with the internal
# JFrog source it injects), which REWRITES tracked poetry.lock / pyproject.toml
Expand Down Expand Up @@ -185,6 +191,16 @@ jobs:
env:
MODEL_ENDPOINT: https://${{ secrets.DATABRICKS_HOST }}/serving-endpoints/databricks-claude-opus-4-8/invocations
DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }}
# Live-warehouse connection env for the agent's REQUIRED E2E repro test
# (see .bot/prompts/engineer/system.md — the bug-fix flow reproduces the
# bug via a tests/e2e test against a real warehouse; a mocked unit test
# alone cannot prove the live server behaves correctly). Mirrors the
Comment thread
eric-wang-1990 marked this conversation as resolved.
# e2e job in code-coverage.yml; the job already runs in `environment:
# azure-prod`, so these secrets are in scope.
DATABRICKS_SERVER_HOSTNAME: ${{ secrets.DATABRICKS_HOST }}
Comment thread
peco-review-bot[bot] marked this conversation as resolved.
Comment thread
peco-review-bot[bot] marked this conversation as resolved.
DATABRICKS_HTTP_PATH: ${{ secrets.TEST_PECO_WAREHOUSE_HTTP_PATH }}
DATABRICKS_CATALOG: peco
DATABRICKS_USER: ${{ secrets.TEST_PECO_SP_ID }}
REPO_ROOT: ${{ github.workspace }}
RUNNER_TEMP: ${{ runner.temp }}
FLOW: ${{ steps.ctx.outputs.flow }}
Expand Down
Loading