03 Release and detect
Release the selected agent with a known policy blind spot, then use operational evaluation and real user feedback to detect it.
Starting point
Module 02 is complete. Record the winning config_id selected from the actual Arena
run, then export it from the lab root (ClickHouse_Demos/workshops/agent_arena):
source .env
export WINNER_CONFIG_ID="${WINNER_CONFIG_ID:-qwen3.7-flash__P2_fewshot}"The verified workshop run selected qwen3.7-flash__P2_fewshot; keep your room's
winner if it differs. You will use the same model and prompt that you measured—not a
special failure-only agent.
If your winner is Qwen, OpenRouter Settings → Privacy → Data Policies → Zero Data Retention → Non-frontier must be disabled. The available Alibaba route is rejected when non-frontier ZDR is enforced. Review your privacy requirements before changing this setting for real data.
Why a passing evaluator can still miss user value
An online evaluator measures only the dimension it was designed to measure. Here,
sql-execution-success answers an important operational question: did the agent
produce SQL that ClickHouse could execute? It does not know whether the SQL follows
the current business definition of active customer.
That creates a realistic monitoring gap:
| Signal | Question it answers | Expected value in this incident |
|---|---|---|
sql-execution-success | Did the generated SQL execute successfully? | true |
user-thumbs | Did this answer meet this user's need? | false |
Operational evaluation catches broken SQL, timeouts, and execution errors. Semantic or user evaluation asks whether an executable answer is useful and aligned with business meaning. Neither replaces the other. A thumbs-down is a prioritization signal, not ground truth; a human will investigate it in Module 04.
Goal
Create one real chat_turn trace where the operational evaluator passes but a user
marks the answer down. Record the trace and the two conflicting counts for the human
investigation.
Step 1 — Prove the seeded incident is reproducible
Run the preflight from the lab root before starting the demo server:
source .env
export WINNER_CONFIG_ID="${WINNER_CONFIG_ID:-qwen3.7-flash__P2_fewshot}"
.venv/bin/python -m schema.gen_schema_context
.venv/bin/python -m scripts.check_online_eval_scenario \
--config-id "$WINNER_CONFIG_ID"The command executes both definitions and asks the selected configuration three
paraphrases. It must print different stale_count and current_count values, three
classification_N=policy-v1 lines, and:
If a paraphrase returns ok/unknown, the preflight retries only that same
paraphrase and configuration once. It does not retry policy-v2 or
provider/model/agent failures, and a second ok/unknown remains blocked.
OK: seeded online-evaluation incident is reproducibleIf the counts are equal or any classification is not policy-v1, stop: the contrast
would not be visible in this data/model run.
The current business definition is this exact SQL:
SELECT uniqExact(customer_id) FROM v_orders
WHERE order_ts >= now() - INTERVAL 30 DAY
AND status NOT IN ('cancelled', 'returned')The old policy-v1 definition instead counts customers who signed up in the last 90
days. The SQL the model generates in this module is therefore valid relative to the
explicit policy-v1 instructions. The point is not that the model is unintelligent;
the deployed policy context is stale while the SQL-execution evaluator is too narrow
to notice.
Step 2 — Provision the operational evaluator
Provisioning is idempotent, so it is safe to run again:
source .env
.venv/bin/python -m scripts.provision_online_evaluators --operationalExpect the output to name evaluator sql-execution-success and enabled rule
agent-arena-sql-execution-online.
Step 3 — Start the seeded stale release
In the first terminal, from the lab root, start the server with the old policy explicitly selected and leave it running:
source .env
AGENT_ARENA_POLICY_VERSION=policy-v1 \
.venv/bin/uvicorn serving.api:app --port 8100Do not omit AGENT_ARENA_POLICY_VERSION. The service otherwise defaults to the
current policy-v2, which correctly excludes cancelled and returned orders.
Step 4 — Ask and rate through Chat
In another terminal, start the dashboard if it is not already running:
scripts/arena.sh serveOpen http://localhost:5174, select the Chat tab and $WINNER_CONFIG_ID, then ask:
How many active customers do we have?Read the generated SQL and result. It should follow the seeded 90-day signup
definition from policy-v1. Click 👎 on this answer and wait until the UI says
feedback sent.
This Chat root trace is the single authoritative incident you will score and hand to Module 04.
Step 5 — Find and verify the Chat trace
In Langfuse, open Tracing and filter for user-thumbs = false. Open the newest
root chat_turn whose question is How many active customers do we have?, whose
config matches $WINNER_CONFIG_ID, and whose metadata shows
policyversion=policy-v1. Copy its trace ID and trace URL, then set the ID locally:
export CHAT_TRACE_ID="<paste the Chat trace ID>"
.venv/bin/python -m scripts.verify_online_scores "$CHAT_TRACE_ID" \
sql-execution-success=true user-thumbs=falseVerify that user-thumbs is a Boolean false, not a numeric or text score. The
serving source calls the metadata field policy_version; the OpenTelemetry adapter
sanitizes it to the emitted Langfuse key policyversion.
Step 6 — Reproduce with an unrated curl
The raw API call is a mandatory command-level reproduction and diagnostic. It creates a separate trace, but it is not the feedback incident and must not be rated:
source .env
export WINNER_CONFIG_ID="${WINNER_CONFIG_ID:-qwen3.7-flash__P2_fewshot}"
ASK_BODY=$(.venv/bin/python -c \
'import json,sys; print(json.dumps({"question": sys.argv[1], "config_id": sys.argv[2]}))' \
"How many active customers do we have?" "$WINNER_CONFIG_ID")
CURL_RESPONSE=$(curl -fsS http://localhost:8100/ask \
-H 'content-type: application/json' -d "$ASK_BODY")
printf '%s\n' "$CURL_RESPONSE" | .venv/bin/python -m json.tool
CURL_TRACE_ID=$(printf '%s\n' "$CURL_RESPONSE" | .venv/bin/python -c \
'import json,sys; data=json.load(sys.stdin); assert data.get("policy_version") == "policy-v1"; assert data.get("outcome") == "ok"; trace_id=data.get("trace_id"); assert isinstance(trace_id, str) and trace_id; print(trace_id)')The response must have outcome: "ok", a non-empty trace_id, and
policy_version: "policy-v1".
Wait for the asynchronous evaluator and verify only its operational score:
.venv/bin/python -m scripts.verify_online_scores "$CURL_TRACE_ID" \
sql-execution-success=trueDo not call /feedback for CURL_TRACE_ID and do not put it in the worksheet. It is
only a reproducible API diagnostic; CHAT_TRACE_ID remains the handoff trace.
Step 7 — Compare against the current policy
Execute the current-policy SQL through the same read-only ClickHouse client as the
agent, then compare its single result with the stale result in CURL_RESPONSE:
.venv/bin/python - <<'PY'
from arena.config import load_config
from agents.chclient import ROClickHouseClient
sql = """SELECT uniqExact(customer_id) FROM v_orders
WHERE order_ts >= now() - INTERVAL 30 DAY
AND status NOT IN ('cancelled', 'returned')"""
result = ROClickHouseClient(load_config().clickhouse).query(sql)
print(result.rows[0][0])
PYThis is the exact query you just executed:
SELECT uniqExact(customer_id) FROM v_orders
WHERE order_ts >= now() - INTERVAL 30 DAY
AND status NOT IN ('cancelled', 'returned')The different count is the user-visible failure. The SQL ran; it answered the wrong business definition. Record that count beside the authoritative Chat trace evidence.
Investigation worksheet
Keep this handoff for Module 04:
| Evidence | Your value |
|---|---|
Winner config_id | |
| Authoritative Chat trace ID | |
| Authoritative Chat trace URL | |
Stale policy-v1 count | |
Current policy-v2 count | |
sql-execution-success | true |
user-thumbs | false |
How to verify you are done
- The preflight showed different stale/current counts and all three seeded questions
classified as
policy-v1. - The service ran with
AGENT_ARENA_POLICY_VERSION=policy-v1and/askreturnedoutcome: "ok". - The authoritative Chat trace has
sql-execution-success=trueanduser-thumbs=falsein Langfuse. - The mandatory curl diagnostic returned
outcome: "ok", produced a distinctCURL_TRACE_ID, and was not rated or handed off. - You recorded the authoritative Chat trace ID/URL and both counts without sharing credentials.
- You can explain why a successful SQL execution did not prove semantic correctness.
Continue to Module 04 — Investigate to turn this signal into a human-reviewed diagnosis.