Spaces:
Sleeping
Sleeping
| # DataAgentBench failure analysis β runs of 2026-06-05 | |
| Trajectory analysis of full `--all` sweeps, scored with DAB's own | |
| per-task `validate.py`. Captured with `--log-dir` (full per-turn prompts, | |
| raw LLM responses, tool args, and untruncated results); diagnoses below | |
| cite those traces. | |
| ## Run config | |
| ``` | |
| python -m benchmark.dab.runner --all --llm lexsi --log-dir artifacts/dab_runs/new_tool | |
| ``` | |
| - 5 of 17 datasets runnable (sqlite/duckdb); 12 skipped (postgres/mongo). | |
| - **Score: 10/17 tasks passed** β `consolidate_tables` (fix B) recovered | |
| stockmarket/query4 + query5 over the pre-tool baseline of 8/17 (both | |
| confirmed using the tool; see Β§B). | |
| > **Measurement note.** Single-run pass@1 carries per-task sampling | |
| > noise β any system-prompt change re-rolls multi-step trajectories, so a | |
| > few tasks can flip run-to-run. Use `--iterations 3` (majority vote) to | |
| > pin a stable number before trusting a future delta. | |
| ## Results | |
| β = pass, β = fail, π― = recovered by `consolidate_tables`. | |
| | Dataset | Query | Result | Validator reason / note | | |
| |---|---|---|---| | |
| | DEPS_DEV_V1 | query1 | β | Missing name `@dmrvos/infrajs>0.0.6>typescript` (Β§C/Β§D) | | |
| | DEPS_DEV_V1 | query2 | β | Missing project `mui-org/material-ui` (Β§D) | | |
| | GITHUB_REPOS | query1 | β | No value rounds to 0.33 β wrong join (Β§A note) | | |
| | GITHUB_REPOS | query2 | β | Fuzzy matched `swiftandroid/swift` | | |
| | GITHUB_REPOS | query3 | β | Found 1077 | | |
| | GITHUB_REPOS | query4 | β | All repo names matched | | |
| | music_brainz_20k | query1 | β | Ground truth found | | |
| | music_brainz_20k | query2 | β | Ground truth found | | |
| | music_brainz_20k | query3 | β | Wrong song (`Zo gaat het levenβ¦`) (Β§D) | | |
| | stockindex | query1 | β | `399001.SZ` primary | | |
| | stockindex | query2 | β | `IXIC` not in first 200 chars (Β§C) | | |
| | stockindex | query3 | β | All name-country pairs matched | | |
| | stockmarket | query1 | β | 18.44 β 18.44 | | |
| | stockmarket | query2 | β | Missing number 31 β consolidated, but count SQL still wrong (Β§B) | | |
| | stockmarket | query3 | β | `Apex Global Brands Inc` β consolidated, but avg-volume SQL still wrong (Β§B) | | |
| | stockmarket | query4 | π―β | `MFA Financial, Inc` found β **recovered via `consolidate_tables`** | | |
| | stockmarket | query5 | π―β | `Synthesis Energy Systems, Inc` found β **recovered via `consolidate_tables`** | | |
| **Total: 10/17** β 8 baseline passers + 2 π― recoveries via `consolidate_tables`. | |
| --- | |
| ## Failure taxonomy | |
| ### A. Harness bug β history truncates tool-call args, agent thinks its SQL is broken (1 task, systemic) | |
| **GITHUB_REPOS/query1.** The agent wrote a complete 960-char query and | |
| `run_sql` **executed it fine** (returned `1 row Γ 3 cols`). But the loop | |
| echoes each tool call into the observation history truncated to 400 | |
| chars ([loop.py:236](../lexsi_ds/agent/loop.py#L236)): | |
| ```python | |
| f"TOOL CALL: {tool_name}({json.dumps(args_obj, default=str)[:400]})\n" | |
| ``` | |
| The 400-char cut lands mid-`JOIN`, and the appended `)` makes the echo | |
| read as a query that ends `β¦JOIN artifacts_database_contents c ON c)` β | |
| i.e. **truncated mid-join**. The agent re-read this, concluded the | |
| tooling was broken, re-ran the same query 10 times, and gave up: | |
| > "every `run_sql` execution shown is truncated mid-join | |
| > (`JOIN artifacts_database_contents c ON c)`), which causes the query | |
| > to effectively fail" β *agent's final answer* | |
| So a runnable task was lost to a display artifact, not a real error. | |
| (The SQL logic was also likely wrong β proportion β 0.33 β but the agent | |
| never got far enough to find out.) | |
| **Fix (done).** [loop.py](../lexsi_ds/agent/loop.py) now echoes args via | |
| `_echo_args()`: full up to an 8000-char cap, and when it must truncate | |
| it appends an explicit `β¦ [+N chars truncated for display only; the full | |
| args above were executed]` marker β so a display cut can never read as a | |
| broken statement. The 960-char query that triggered this is now echoed | |
| in full. | |
| ### B. Scale β per-shard table explosion vs the 12-step budget (4 tasks) β FIXED via `consolidate_tables` | |
| **The problem.** stockmarket materializes **2753 `stocktrade_database_<ticker>` | |
| tables** (one per symbol, identical schema `Date,Open,High,Low,Close, | |
| Adj Close,Volume`, ~410 rows each) plus one `stockinfo` table. The shard | |
| key (ticker) lives in the **table name, not a column**. A question like | |
| "across all NYSE stocksβ¦" is a `GROUP BY ticker` that can only be | |
| expressed as a 2753-way `UNION ALL` β unwriteable in a 12-step budget. | |
| All four tasks hit step 13 and surrendered: | |
| > "the query requires scanning/UNIONing thousands of | |
| > `stocktrade_database_<ticker>` tables, and I ran out of allowed tool | |
| > calls" β *query3, baseline* | |
| **The fix (done): a generic `consolidate_tables` tool** | |
| ([consolidate_tables.py](../lexsi_ds/agent/tools/consolidate_tables.py)). | |
| It folds a sharded family into one table in a single call β the giant | |
| `UNION ALL BY NAME` is generated in our code, never against the agent's | |
| step budget: | |
| ```json | |
| {"tool": "consolidate_tables", | |
| "args": {"pattern": "stocktrade_database_*", "into": "stocktrade", "key_column": "ticker"}} | |
| ``` | |
| It auto-derives the key from the pattern's literal prefix (β bare | |
| tickers), schema-guards (unions only same-schema shards, reports the | |
| rest), and defaults to a cheap VIEW. Generic by design: per-ticker, | |
| per-day, per-region β any BYO datalake with sharded tables. Planner | |
| rule 14 tells the agent to reach for it when `inspect_data` shows many | |
| same-prefix tables. | |
| **Measured:** 2753 tables β one 6.47M-row view in **1.2s**; the | |
| previously-timed-out cross-ticker query runs in **~1s**. On the | |
| `new_tool/` sweep the agent called it in all 4 stockmarket tasks and | |
| **recovered query4 + query5** (the name-lookup tasks). query2 (count off | |
| by the "31") and query3 (avg-volume per company) still fail: the tool | |
| removes the *structural* blocker, but the agent must still write correct | |
| analytical SQL on top β which it nailed for q4/q5 and missed for q2/q3 | |
| (the latter compounded by Β§E coded values). | |
| ### C. Output format / "primary answer" expectations (2 tasks) | |
| - **stockindex/query2** β the answer was **correct** (`IXIC`: 44 up / 31 | |
| down) but the validator requires the target index in the first 200 | |
| chars as the *primary* answer; the agent buried it after a prose | |
| preamble and a markdown table, and added a second index (`GSPTSE`). | |
| Penalized on presentation, not correctness. | |
| - **DEPS_DEV_V1/query1** β the agent's query *did* surface the | |
| composite-key rows (`@dmrvos/infrajs>0.0.5>typescript`) but (a) chose | |
| version **0.0.5**, not the ground-truth **0.0.6** ("latest release" | |
| logic wrong β see Β§D), and (b) hedged/refused because the values | |
| "look like dependency paths rather than just the package name". | |
| **Fix:** a benchmark-mode answer directive β lead with the bare | |
| answer/identifier in the exact requested format, then optional detail. | |
| ### D. Wrong query semantics β confidently wrong values (2 tasks) | |
| - **DEPS_DEV_V1/query2** β returned `react-component/picker`, `tailwindcss/typography`, β¦; | |
| ground truth is `mui-org/material-ui`. The "marked as release" filter | |
| + fork-count join produced a different top-5. | |
| - **music_brainz_20k/query3** β answered `"Groovey" by Rich Matteson, | |
| $4,128.59` in a single `run_sql`; ground truth is | |
| `"Zo gaat het leven aan je voor"`. Revenue was almost certainly | |
| aggregated by the wrong entity (track title vs. recording, or not | |
| summed across stores). The agent was overconfident β 4 steps, one | |
| query, no cross-check. | |
| **Fix:** these need the DAB `db_description` field-semantics to be | |
| weighted more (e.g. how "latest release" / "revenue" are defined), and a | |
| self-check step before finalizing on aggregation questions. | |
| ### E. Coded-value / data-semantics gaps (compounds B) | |
| **stockmarket/query5, query3** β the agent filtered on | |
| `Listing Exchange='Q' AND Market Category='QCM'`, got 0 rows, and | |
| concluded the data didn't match. `Listing Exchange`/`Market Category`/ | |
| `Financial Status` are **coded** columns whose codes differ from the | |
| agent's assumptions. It spent steps probing codes instead of answering, | |
| which (with Β§B) guaranteed a timeout. | |
| --- | |
| ## Priorities | |
| | Fix | Status | Impact | | |
| |---|---|---| | |
| | **A.** `_echo_args()` no longer cuts SQL mid-string | β done | Removes false "truncated SQL" failures; helps any long-SQL task | | |
| | **B.** `consolidate_tables` folds sharded families into one table | β done | **+2** (stockmarket q4, q5); generic for any sharded datalake | | |
| | **D/E.** Lean on `db_description` semantics + a pre-final self-check | open | DEPS/query2, music_brainz/query3, stockmarket q2/q3 SQL logic | | |
| | **C.** Benchmark answer-format directive (lead with bare answer) | open | stockindex/query2 (+ partial DEPS/query1) | | |
| **Net effect of A + B: 10/17.** A is a correctness floor (no more false | |
| failures); B is the +2 (stockmarket q4, q5). The remaining levers are | |
| **D/E** (analytical-SQL / coded-value semantics β the dominant failure | |
| mode now that the structural blockers are gone) and **C** (output | |
| format). | |
| **Measure with `--iterations`.** Single-run pass@1 is noisy β a prompt | |
| change re-rolls every multi-step task. Run `--iterations 3` (majority | |
| vote) before trusting a future delta. | |
| ## Reproduce / inspect | |
| ```bash | |
| # Noise-adjusted measurement run (majority vote per task): | |
| python -m benchmark.dab.runner --all --llm lexsi --iterations 3 \ | |
| --log-dir artifacts/dab_runs/measure_v1 | |
| # Inspect one trajectory end-to-end (prompts, raw responses, SQL, payloads): | |
| python -c "import json; d=json.load(open('artifacts/dab_runs/new_tool/stockmarket_query4_iter0.json')); \ | |
| print(d['reason']); [print(s['n'], s['tool'], (s['args'] or {}).get('sql','')[:80]) for s in d['run']['steps']]" | |
| # Confirm the new tool fired on the stockmarket tasks: | |
| grep -l consolidate_tables artifacts/dab_runs/new_tool/stockmarket_*.json | |
| ``` |