diff --git a/.demo_qa.mk b/.demo_qa.mk new file mode 100644 index 00000000..adfa2a57 --- /dev/null +++ b/.demo_qa.mk @@ -0,0 +1,7 @@ +# Локальные настройки demo_qa (генерируется командой: make init) +# Можно редактировать руками. Рекомендуется добавить в .gitignore. +DATA=_demo_data/shop +SCHEMA=_demo_data/shop/schema.yaml +CASES=examples/demo_qa/cases/retail_cases.json +# OUT можно не задавать: по умолчанию OUT=${DATA}/.runs/results.jsonl +# OUT=_demo_data/shop/.runs/results.jsonl diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml new file mode 100644 index 00000000..33ae56d6 --- /dev/null +++ b/.github/workflows/pytest.yml @@ -0,0 +1,24 @@ +name: pytest + +on: + pull_request: + +jobs: + pytest: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: python -m pip install --upgrade pip && python -m pip install -e ".[dev]" + + - name: Run pytest (not slow, not known_bad) + env: + PYTHONPATH: .:src + run: python -m pytest -q -m "not slow and not known_bad" diff --git a/.gitignore b/.gitignore index 0904cb2c..d8711ef1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ build/ .env.demo_qa _demo_data/*/.runs/* .coverage +.DS_Store diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 09d79d2a..238158e0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,4 +5,4 @@ repos: name: pytest language: system pass_filenames: false - entry: bash -lc 'source .venv/bin/activate PYTHONPATH=".:src:${PYTHONPATH}"; python -m pytest -q -m "not slow"' \ No newline at end of file + entry: bash -lc 'source .venv/bin/activate PYTHONPATH=".:src:${PYTHONPATH}"; python -m pytest -q -m "not slow and not known_bad"' \ No newline at end of file diff --git a/Makefile b/Makefile index d0e24544..31458374 100644 --- a/Makefile +++ b/Makefile @@ -66,6 +66,11 @@ COMPARE_TAG_JUNIT ?= $(DATA)/.runs/diff.tags.junit.xml MAX_FAILS ?= 5 +PURGE_RUNS ?= 0 +PRUNE_HISTORY ?= 0 +PRUNE_CASE_HISTORY ?= 0 +DRY ?= 0 + # ============================================================================== # 6) Настройки LLM-конфига (редактирование/просмотр) # ============================================================================== @@ -94,7 +99,7 @@ LIMIT_FLAG := $(if $(strip $(LIMIT)),--limit $(LIMIT),) batch batch-tag batch-failed batch-failed-from \ batch-missed batch-missed-from batch-failed-tag batch-missed-tag \ batch-fail-fast batch-max-fails \ - stats history-case report-tag report-tag-changes tags case-run case-open compare compare-tag + stats history-case report-tag report-tag-changes tags tag-rm case-run case-open compare compare-tag # ============================================================================== # help (на русском) @@ -142,6 +147,14 @@ help: @echo " make case-run CASE=case_42 - прогнать один кейс" @echo " make case-open CASE=case_42 - открыть артефакты кейса" @echo "" + @echo "Уборка:" + @echo " make tag-rm TAG=... [DRY=1] [PURGE_RUNS=1] [PRUNE_HISTORY=1] [PRUNE_CASE_HISTORY=1]" + @echo " - удаляет effective snapshot тега и tag-latest* указатели" + @echo " DRY=1 - dry-run: только показать, что будет удалено" + @echo " PURGE_RUNS=1 - дополнительно удалить все runs, где run_meta.tag == TAG" + @echo " PRUNE_HISTORY=1 - вычистить записи с этим тегом из $${DATA}/.runs/history.jsonl" + @echo " PRUNE_CASE_HISTORY=1 - вычистить записи с этим тегом из $${DATA}/.runs/runs/cases/*.jsonl" + @echo "" @echo "Сравнение результатов:" @echo " make compare BASE=... NEW=... [DIFF_OUT=...] [JUNIT=...]" @echo " make compare-tag BASE_TAG=baseline NEW_TAG=... [COMPARE_TAG_OUT=...] [COMPARE_TAG_JUNIT=...]" @@ -340,3 +353,14 @@ compare-tag: check --new-tag "$(NEW_TAG)" \ --out "$(OUT)" \ --junit "$(JUNIT)" + +# команды очистки + +tag-rm: + @test -n "$(strip $(TAG))" || (echo "TAG обязателен: make tag-rm TAG=..." && exit 1) + @TAG="$(TAG)" DATA="$(DATA)" PURGE_RUNS="$(PURGE_RUNS)" PRUNE_HISTORY="$(PRUNE_HISTORY)" PRUNE_CASE_HISTORY="$(PRUNE_CASE_HISTORY)" DRY="$(DRY)" $(PYTHON) -m scripts.tag_rm + + + + + diff --git a/caffeinate_make.sh b/caffeinate_make.sh new file mode 100644 index 00000000..f585217c --- /dev/null +++ b/caffeinate_make.sh @@ -0,0 +1,87 @@ +#!/bin/sh +set -u + +### ================== НАСТРОЙКИ (менять тут) ================== +DELAY=0 # 65 минут до первого запуска +INTERVAL=5400 # 90 минут между запусками +TICK=300 # печатать обратный отсчёт раз в 5 минут + +# (опционально) папка проекта, где надо выполнять make +WORKDIR=/Users/alexanderonishchenko/Documents/_Projects/fetchgraph + +LOG="$HOME/batch_tag.log" + +# Команда для ПЕРВОГО запуска +FIRST_CMD='make batch-tag TAG=my_tag NOTE="прогон перед мерджем"' + +# Команда для ПОВТОРНЫХ запусков +REPEAT_CMD='make batch-tag TAG=my_tag NOTE="прогон перед мерджем"' +### ============================================================ + +LOCKDIR="/tmp/batch_tag_runner.lock" + +log() { printf '%s\n' "$*" | tee -a "$LOG"; } + +cleanup() { + [ -n "${CAF_PID:-}" ] && kill "$CAF_PID" 2>/dev/null || true + rmdir "$LOCKDIR" 2>/dev/null || true +} +trap 'cleanup' EXIT INT TERM HUP + +# Защита от двух копий +if ! mkdir "$LOCKDIR" 2>/dev/null; then + echo "Похоже, уже запущено (lock: $LOCKDIR). Если уверены — удалите lock и запустите снова." >&2 + exit 1 +fi + +log "PID $$ started at $(date '+%F %T')" + +# Не даём Mac уснуть +if command -v caffeinate >/dev/null 2>&1; then + caffeinate -dimsu -w $$ & + CAF_PID=$! + log "caffeinate pid: $CAF_PID" +else + log "WARNING: caffeinate не найден — Mac может уснуть." +fi + +# Переходим в папку проекта (если существует) +if [ -d "$WORKDIR" ]; then + cd "$WORKDIR" || exit 1 +else + log "WARNING: WORKDIR не существует: $WORKDIR (останусь в текущей папке)" +fi + +countdown() { + total="$1" + label="$2" + + while [ "$total" -gt 0 ]; do + mins=$(( total / 60 )) + secs=$(( total % 60 )) + log "$label: осталось ${mins}m$(printf '%02d' "$secs")s ($(date '+%F %T'))" + + step=$TICK + [ "$total" -lt "$step" ] && step=$total + sleep "$step" || exit 1 + total=$(( total - step )) + done +} + +run_cmd() { + label="$1" + cmd="$2" + + log "---- $label $(date '+%F %T') ----" + log "CMD: $cmd" + sh -c "$cmd" 2>&1 | tee -a "$LOG" + log "" +} + +countdown "$DELAY" "До первого запуска" +run_cmd "FIRST RUN" "$FIRST_CMD" + +while :; do + countdown "$INTERVAL" "До следующего запуска" + run_cmd "REPEAT RUN" "$REPEAT_CMD" +done diff --git a/examples/demo_qa/demo_qa.toml b/examples/demo_qa/demo_qa.toml index a1d9ede8..e1f4f251 100644 --- a/examples/demo_qa/demo_qa.toml +++ b/examples/demo_qa/demo_qa.toml @@ -1,5 +1,5 @@ [llm] -base_url = "http://localhost:8000/v1" +base_url = "http://localhost:8002/v1" plan_model = "default" synth_model = "default" plan_temperature = 0.0 diff --git a/examples/demo_qa/runner.py b/examples/demo_qa/runner.py index 43d524e7..f78ce2aa 100644 --- a/examples/demo_qa/runner.py +++ b/examples/demo_qa/runner.py @@ -210,6 +210,14 @@ def _stringify(value: object | None) -> str | None: return str(value) +def _normalize_text(value: str) -> str: + return value.strip().casefold() + + +def _normalize_strings(values: Iterable[object]) -> list[str]: + return [_normalize_text(str(value)) for value in values] + + def _match_expected(case: Case, answer: str | None) -> ExpectedCheck | None: if not case.has_asserts: return None @@ -218,7 +226,15 @@ def _match_expected(case: Case, answer: str | None) -> ExpectedCheck | None: return ExpectedCheck(mode="none", expected=expected_value, passed=False, detail="no answer") if case.expected is not None: expected_str = _stringify(case.expected) or "" - passed = answer.strip() == expected_str.strip() + if isinstance(case.expected, (list, tuple, set)): + expected_items = _normalize_strings(case.expected) + answer_items = _normalize_strings(answer) if isinstance(answer, (list, tuple, set)) else [] + if isinstance(case.expected, set) or isinstance(answer, set): + passed = set(expected_items) == set(answer_items) + else: + passed = expected_items == answer_items + else: + passed = _normalize_text(answer) == _normalize_text(expected_str) detail = None if passed else f"expected={expected_str!r}, got={answer!r}" return ExpectedCheck(mode="exact", expected=expected_str, passed=passed, detail=detail) if case.expected_regex is not None: @@ -229,7 +245,7 @@ def _match_expected(case: Case, answer: str | None) -> ExpectedCheck | None: return ExpectedCheck(mode="regex", expected=expected_regex, passed=passed, detail=detail) if case.expected_contains is not None: expected_contains = _stringify(case.expected_contains) or "" - passed = expected_contains in answer + passed = _normalize_text(expected_contains) in _normalize_text(answer) detail = None if passed else f"expected to contain {expected_contains!r}" return ExpectedCheck(mode="contains", expected=expected_contains, passed=passed, detail=detail) return None diff --git a/examples/demo_qa/tests/test_demo_qa_runner.py b/examples/demo_qa/tests/test_demo_qa_runner.py index 67fc66fb..f9723dd2 100644 --- a/examples/demo_qa/tests/test_demo_qa_runner.py +++ b/examples/demo_qa/tests/test_demo_qa_runner.py @@ -32,7 +32,7 @@ def test_match_expected_coerces_non_string_expected_values() -> None: def test_match_expected_contains_pass_and_fail() -> None: case = Case(id="c2", question="Q", expected_contains="bar") - match = _match_expected(case, "value bar baz") + match = _match_expected(case, "value BAR baz") assert match is not None assert match.passed is True @@ -47,6 +47,26 @@ def test_match_expected_contains_pass_and_fail() -> None: assert missing_answer.detail == "no answer" +def test_match_expected_equals_is_case_insensitive() -> None: + case = Case(id="c3", question="Q", expected="Alpha") + + match = _match_expected(case, "alpha") + assert match is not None + assert match.passed is True + + +def test_match_expected_list_comparison_normalizes_elements() -> None: + case = Case(id="c4", question="Q", expected=["Foo", "Bar"]) + + match = _match_expected(case, cast(str, ["foo", "bar"])) + assert match is not None + assert match.passed is True + + mismatch = _match_expected(case, cast(str, ["foo", "baz"])) + assert mismatch is not None + assert mismatch.passed is False + + def test_diff_runs_tracks_regressions_and_improvements() -> None: baseline = [ RunResult( diff --git a/pyproject.toml b/pyproject.toml index 68c158ea..b3e82dec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "fetchgraph" -version = "0.2.0" +version = "0.2.1" description = "Graph-like planning → context fetching → synthesis agent (library-style)." readme = "README.md" requires-python = ">=3.11" diff --git a/pytest.ini b/pytest.ini index 6b10b085..742f400d 100644 --- a/pytest.ini +++ b/pytest.ini @@ -45,6 +45,7 @@ markers = slow: slow tests (exclude via -m "not slow") integration: integration tests (providers / IO / external deps) e2e: end-to-end scenarios + known_bad: real-world TDD cases that are allowed to fail (excluded from CI by default) # Удобные дефолты для логов в CI и локально log_cli = true diff --git a/scripts/tag_rm.py b/scripts/tag_rm.py new file mode 100644 index 00000000..935958f3 --- /dev/null +++ b/scripts/tag_rm.py @@ -0,0 +1,192 @@ +import json +import os +import shutil +from datetime import datetime +from pathlib import Path + +tag = os.environ["TAG"] +data = Path(os.environ["DATA"]) +purge_runs = os.environ.get("PURGE_RUNS","0") in ("1","true","yes","on") +prune_history = os.environ.get("PRUNE_HISTORY","0") in ("1","true","yes","on") +prune_case_history = os.environ.get("PRUNE_CASE_HISTORY","0") in ("1","true","yes","on") +dry = os.environ.get("DRY","0") in ("1","true","yes","on") + +artifacts_dir = data / ".runs" +runs_root = artifacts_dir / "runs" + +def sanitize(t: str) -> str: + cleaned = "".join(ch if ch.isalnum() or ch in "-_." else "_" for ch in t) + return cleaned or "tag" + +slug = sanitize(tag) + +tag_dir = runs_root / "tags" / slug +tag_markers = [ + runs_root / f"tag-latest-complete-{slug}.txt", + runs_root / f"tag-latest-results-{slug}.txt", + runs_root / f"tag-latest-any-{slug}.txt", + runs_root / f"tag-latest-{slug}.txt", +] + +global_markers = { + "latest_any": runs_root / "latest_any.txt", + "latest_complete": runs_root / "latest_complete.txt", + "latest_results": runs_root / "latest_results.txt", + "latest_legacy": runs_root / "latest.txt", +} + +def rm_file(p: Path): + if not p.exists(): + return + print("rm", p) + if not dry: + p.unlink() + +def rm_dir(p: Path): + if not p.exists(): + return + print("rm -r", p) + if not dry: + shutil.rmtree(p) + +def parse_dt(s: str) -> datetime | None: + if not s: + return None + try: + return datetime.fromisoformat(s.replace("Z","+00:00")) + except Exception: + return None + +def iter_run_dirs(): + if not runs_root.exists(): + return + for p in runs_root.iterdir(): + if not p.is_dir(): + continue + if p.name == "tags": + continue + yield p + +print(f"== Deleting tag {tag!r} (slug={slug}) ==") +print(f"artifacts_dir: {artifacts_dir}") +print(f"DRY={dry} PURGE_RUNS={purge_runs} PRUNE_HISTORY={prune_history} PRUNE_CASE_HISTORY={prune_case_history}") + +for m in tag_markers: + rm_file(m) +rm_dir(tag_dir) + +deleted_runs: list[Path] = [] + +if purge_runs and runs_root.exists(): + for run_dir in iter_run_dirs(): + meta = run_dir / "run_meta.json" + if not meta.exists(): + continue + try: + obj = json.loads(meta.read_text(encoding="utf-8")) + except Exception: + continue + if obj.get("tag") == tag: + deleted_runs.append(run_dir) + rm_dir(run_dir) + +if prune_history: + hist = artifacts_dir / "history.jsonl" + if hist.exists(): + print("prune", hist, "(remove entries with tag ==)", tag) + if not dry: + tmp = hist.with_suffix(".jsonl.tmp") + bak = hist.with_suffix(".jsonl.bak") + with hist.open("r", encoding="utf-8") as r, tmp.open("w", encoding="utf-8") as w: + for line in r: + line = line.strip() + if not line: + continue + try: + obj = json.loads(line) + except Exception: + w.write(line + "\n") + continue + if obj.get("tag") == tag: + continue + w.write(json.dumps(obj, ensure_ascii=False) + "\n") + if bak.exists(): + bak.unlink() + hist.replace(bak) + tmp.replace(hist) + print("backup written:", bak) + +if prune_case_history: + cases_dir = runs_root / "cases" + if cases_dir.exists(): + print("prune case history under", cases_dir) + if not dry: + for p in cases_dir.glob("*.jsonl"): + tmp = p.with_suffix(".jsonl.tmp") + changed = False + with p.open("r", encoding="utf-8") as r, tmp.open("w", encoding="utf-8") as w: + for line in r: + line = line.strip() + if not line: + continue + try: + obj = json.loads(line) + except Exception: + w.write(line + "\n") + continue + if obj.get("tag") == tag: + changed = True + continue + w.write(json.dumps(obj, ensure_ascii=False) + "\n") + if changed: + p.replace(p.with_suffix(".jsonl.bak")) + tmp.replace(p) + else: + tmp.unlink(missing_ok=True) + +if purge_runs and deleted_runs: + def pick_latest(require_complete: bool): + best_dt = None + best_run = None + best_results = None + for rd in iter_run_dirs(): + summ = rd / "summary.json" + if not summ.exists(): + continue + try: + s = json.loads(summ.read_text(encoding="utf-8")) + except Exception: + continue + if require_complete and not s.get("results_complete", False): + continue + dt = parse_dt(s.get("ended_at") or s.get("started_at") or "") + if dt is None: + continue + if best_dt is None or dt > best_dt: + best_dt = dt + best_run = rd + rp = s.get("results_path") + best_results = Path(rp) if rp else (rd / "results.jsonl") + return best_run, best_results + + any_run, _ = pick_latest(require_complete=False) + complete_run, complete_results = pick_latest(require_complete=True) + + def write_marker(p: Path, val: Path | None): + if val is None: + if p.exists(): + print("rm", p, "(no replacement)") + if not dry: + p.unlink() + return + print("write", p, "->", val) + if not dry: + p.parent.mkdir(parents=True, exist_ok=True) + p.write_text(str(val), encoding="utf-8") + + write_marker(global_markers["latest_any"], any_run) + write_marker(global_markers["latest_complete"], complete_run) + write_marker(global_markers["latest_legacy"], complete_run) + write_marker(global_markers["latest_results"], complete_results) + +print("== Done ==") \ No newline at end of file diff --git a/src/fetchgraph/core/context.py b/src/fetchgraph/core/context.py index eb1d7b0f..0a0c08b8 100644 --- a/src/fetchgraph/core/context.py +++ b/src/fetchgraph/core/context.py @@ -6,6 +6,7 @@ from typing import Any, Callable, Dict, List, Optional from ..parsing.plan_parser import PlanParser +from ..planning.normalize import PlanNormalizer from .models import ( BaselineSpec, ContextFetchSpec, @@ -327,6 +328,7 @@ def __init__( verifiers: List[Verifier], packer: ContextPacker, plan_parser: Optional[Callable[[RawLLMOutput], Plan]] = None, + plan_normalizer: Optional[PlanNormalizer] = None, baseline: Optional[List[BaselineSpec]] = None, max_retries: int = 2, task_profile: Optional[TaskProfile] = None, @@ -344,7 +346,18 @@ def __init__( self.plan_parser = PlanParser().parse else: self.plan_parser = plan_parser + self.plan_normalizer = plan_normalizer or PlanNormalizer.from_providers( + providers + ) self.baseline = baseline or [] + if self.plan_normalizer is not None and self.baseline: + normalized_specs = self.plan_normalizer.normalize_specs( + [spec.spec for spec in self.baseline] + ) + self.baseline = [ + BaselineSpec(spec=normalized, required=baseline_spec.required) + for baseline_spec, normalized in zip(self.baseline, normalized_specs) + ] self.max_retries = max_retries self.task_profile = task_profile or TaskProfile() self.llm_refetch = llm_refetch @@ -353,13 +366,15 @@ def __init__( logger.info( "BaseGraphAgent initialized " "(task_name=%r, providers=%d, verifiers=%d, " - "baseline_specs=%d, max_retries=%d, max_refetch_iters=%d)", + "baseline_specs=%d, max_retries=%d, max_refetch_iters=%d, " + "plan_normalizer=%s)", self.task_profile.task_name, len(self.providers), len(self.verifiers), len(self.baseline), self.max_retries, self.max_refetch_iters, + self.plan_normalizer.__class__.__name__ if self.plan_normalizer else None, ) # ---- public API ---- @@ -440,6 +455,8 @@ def _plan(self, feature_name: str) -> Plan: plan = self.plan_parser(plan_raw) else: plan = Plan.model_validate_json(plan_raw.text) + if self.plan_normalizer is not None: + plan = self.plan_normalizer.normalize(plan) elapsed = time.perf_counter() - t0 logger.info( "Planning finished for feature_name=%r in %.3fs " @@ -469,9 +486,8 @@ def _merge_baseline_with_plan(self, plan: Plan) -> List[ContextFetchSpec]: by_provider.setdefault(b.spec.provider, b.spec) for s in plan.context_plan or []: by_provider[s.provider] = s - if not plan.context_plan: - for p in plan.required_context or []: - by_provider.setdefault(p, ContextFetchSpec(provider=p, mode="full")) + for p in plan.required_context or []: + by_provider.setdefault(p, ContextFetchSpec(provider=p, mode="full")) specs = list(by_provider.values()) logger.debug( "Merged baseline with plan: context_plan_nodes=%d, baseline_specs=%d, " diff --git a/src/fetchgraph/planning/__init__.py b/src/fetchgraph/planning/__init__.py new file mode 100644 index 00000000..9d03a91f --- /dev/null +++ b/src/fetchgraph/planning/__init__.py @@ -0,0 +1,3 @@ +"""Planning package exports.""" + +__all__ = [] \ No newline at end of file diff --git a/src/fetchgraph/planning/normalize/__init__.py b/src/fetchgraph/planning/normalize/__init__.py new file mode 100644 index 00000000..1e4b3944 --- /dev/null +++ b/src/fetchgraph/planning/normalize/__init__.py @@ -0,0 +1,5 @@ +"""Normalization utilities for planning.""" + +from .plan_normalizer import NormalizedPlan, PlanNormalizer, PlanNormalizerOptions + +__all__ = ["NormalizedPlan", "PlanNormalizer", "PlanNormalizerOptions"] \ No newline at end of file diff --git a/src/fetchgraph/planning/normalize/plan_normalizer.py b/src/fetchgraph/planning/normalize/plan_normalizer.py new file mode 100644 index 00000000..11c3fa24 --- /dev/null +++ b/src/fetchgraph/planning/normalize/plan_normalizer.py @@ -0,0 +1,324 @@ +from __future__ import annotations + +import json +import logging +from dataclasses import dataclass +from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple + +from pydantic import Field, TypeAdapter, ValidationError + +from ...core.models import ContextFetchSpec, Plan, ProviderInfo +from ...core.protocols import ContextProvider, SupportsDescribe, SupportsFilter +from ...relational.models import RelationalRequest +from ...relational.normalize import normalize_relational_selectors +from ...relational.providers.base import RelationalDataProvider + +logger = logging.getLogger(__name__) + + +class NormalizedPlan(Plan): + normalization_notes: List[str] = Field(default_factory=list) + + +@dataclass(frozen=True) +class PlanNormalizerOptions: + allow_unknown_providers: bool = False + coerce_provider_case: bool = True + dedupe_required_context: bool = True + dedupe_context_plan: bool = True + trim_text_fields: bool = True + filter_selectors_by_schema: bool = True + default_mode: str = "full" + + +@dataclass(frozen=True) +class SelectorNormalizationRule: + validator: TypeAdapter[Any] + normalize_selectors: Callable[[Any], Any] + + +class PlanNormalizer: + def __init__( + self, + provider_catalog: Dict[str, ProviderInfo], + schema_registry: Optional[Dict[str, Dict[str, Any]]] = None, + normalizer_registry: Optional[Dict[str, SelectorNormalizationRule]] = None, + options: Optional[PlanNormalizerOptions] = None, + ) -> None: + self.provider_catalog = dict(provider_catalog) + self.schema_registry = schema_registry or {} + self.normalizer_registry = normalizer_registry or {} + self.options = options or PlanNormalizerOptions() + self._provider_aliases = self._build_provider_aliases(self.provider_catalog) + + @classmethod + def from_providers( + cls, + providers: Dict[str, ContextProvider], + *, + options: Optional[PlanNormalizerOptions] = None, + ) -> "PlanNormalizer": + catalog: Dict[str, ProviderInfo] = {} + schema_registry: Dict[str, Dict[str, Any]] = {} + normalizer_registry: Dict[str, SelectorNormalizationRule] = {} + for key, prov in providers.items(): + info: Optional[ProviderInfo] = None + if isinstance(prov, SupportsDescribe): + try: + info = prov.describe() + except Exception: + info = None + if info is None: + caps = [] + if isinstance(prov, SupportsFilter): + caps = ["filter", "slice"] + info = ProviderInfo(name=getattr(prov, "name", key), capabilities=caps) + catalog[key] = info + if info.selectors_schema: + schema_registry[key] = info.selectors_schema + if isinstance(prov, RelationalDataProvider): + normalizer_registry[key] = SelectorNormalizationRule( + validator=TypeAdapter(RelationalRequest), + normalize_selectors=normalize_relational_selectors, + ) + return cls( + catalog, + schema_registry=schema_registry, + normalizer_registry=normalizer_registry, + options=options, + ) + + def normalize(self, plan: Plan) -> NormalizedPlan: + notes: List[str] = [] + required_context = self._normalize_required_context(plan.required_context, notes) + context_plan = self._normalize_context_plan(plan.context_plan, notes) + + # IMPORTANT: + # Do NOT synthesize ContextFetchSpec from required_context here. + # Baseline/plan merge owns "ensure required providers exist" logic, + # and must do it in a baseline-safe way (never overriding baseline selectors/mode). + + context_plan = self._normalize_specs(context_plan, notes) + + adr_queries = self._normalize_text_list(plan.adr_queries, notes, "adr_queries") + constraints = self._normalize_text_list( + plan.constraints, notes, "constraints" + ) + + normalized = NormalizedPlan( + required_context=required_context, + context_plan=context_plan, + adr_queries=adr_queries, + constraints=constraints, + entities=list(plan.entities or []), + dtos=list(plan.dtos or []), + normalization_notes=notes, + ) + return normalized + + def normalize_specs( + self, + specs: Iterable[ContextFetchSpec], + *, + notes: Optional[List[str]] = None, + ) -> List[ContextFetchSpec]: + local_notes: List[str] = [] + normalized = self._normalize_specs(specs, local_notes) + if notes is not None: + notes.extend(local_notes) + if local_notes: + logger.debug( + "PlanNormalizer selectors normalization notes: %s", + "; ".join(local_notes), + ) + return normalized + + def _normalize_specs( + self, specs: Iterable[ContextFetchSpec], notes: List[str] + ) -> List[ContextFetchSpec]: + normalized: List[ContextFetchSpec] = [] + for spec in specs: + rule = self.normalizer_registry.get(spec.provider) + if rule is None: + normalized.append(spec) + continue + orig = spec.selectors + before_ok = self._validate_selectors(rule.validator, orig) + decision = "keep_original_valid" if before_ok else "keep_original_still_invalid" + use = orig + after_ok = before_ok + if not before_ok: + candidate = rule.normalize_selectors(orig) + after_ok = self._validate_selectors(rule.validator, candidate) + if after_ok: + decision = "use_normalized_fixed" + use = candidate + elif candidate != orig: + decision = "use_normalized_unvalidated" + use = candidate + notes.append( + self._format_selectors_note( + spec.provider, + before_ok, + after_ok, + decision, + selectors_before=orig, + selectors_after=use, + ) + ) + if use is orig: + normalized.append(spec) + continue + data = spec.model_dump() + data["selectors"] = use + normalized.append(ContextFetchSpec(**data)) + return normalized + + @staticmethod + def _validate_selectors(adapter: TypeAdapter[Any], selectors: Any) -> bool: + try: + adapter.validate_python(selectors) + except ValidationError: + return False + return True + + @staticmethod + def _format_selectors_note( + provider: str, + before_ok: bool, + after_ok: bool, + decision: str, + *, + selectors_before: Any, + selectors_after: Any, + ) -> str: + payload = { + "provider": provider, + "selectors_validate_before": "ok" if before_ok else "error", + "selectors_validate_after": "ok" if after_ok else "error", + "selectors_normalization_decision": decision, + } + if decision != "keep_original_valid": + payload["selectors_before"] = selectors_before + payload["selectors_after"] = selectors_after + return json.dumps(payload, ensure_ascii=False, default=str) + + def _normalize_required_context( + self, values: Iterable[str], notes: List[str] + ) -> List[str]: + normalized: List[str] = [] + seen: set[str] = set() + for raw in values or []: + name = self._resolve_provider(raw) + if name is None: + if self.options.allow_unknown_providers: + name = str(raw) + else: + notes.append(f"required_context_unknown:{raw}") + continue + if self.options.dedupe_required_context: + if name in seen: + notes.append(f"required_context_duplicate:{name}") + continue + seen.add(name) + normalized.append(name) + return normalized + + def _normalize_context_plan( + self, specs: Iterable[ContextFetchSpec], notes: List[str] + ) -> List[ContextFetchSpec]: + normalized: List[ContextFetchSpec] = [] + seen: set[Tuple[str, str, str]] = set() + for spec in specs or []: + provider = self._resolve_provider(spec.provider) + if provider is None: + if self.options.allow_unknown_providers: + provider = spec.provider + else: + notes.append(f"context_plan_unknown:{spec.provider}") + continue + mode = str(spec.mode or self.options.default_mode) + if mode not in {"full", "slice"}: + notes.append(f"context_plan_mode_defaulted:{provider}:{mode}") + mode = self.options.default_mode + selectors = spec.selectors or {} + if not isinstance(selectors, dict): + notes.append(f"context_plan_selectors_invalid:{provider}") + selectors = {} + selectors = self._filter_selectors(provider, selectors, notes) + key = ( + provider, + mode, + json.dumps(selectors, sort_keys=True, ensure_ascii=False), + ) + if self.options.dedupe_context_plan and key in seen: + notes.append(f"context_plan_duplicate:{provider}:{mode}") + continue + seen.add(key) + normalized.append( + ContextFetchSpec( + provider=provider, + mode=mode, + selectors=selectors, + max_tokens=spec.max_tokens, + ) + ) + return normalized + + def _normalize_text_list( + self, + values: Optional[Iterable[Any]], + notes: List[str], + label: str, + ) -> List[str]: + if values is None: + return [] + normalized: List[str] = [] + for raw in values: + if not isinstance(raw, str): + notes.append(f"{label}_non_string") + continue + item = raw.strip() if self.options.trim_text_fields else raw + if not item: + notes.append(f"{label}_empty") + continue + normalized.append(item) + return normalized + + def _filter_selectors( + self, provider: str, selectors: Dict[str, Any], notes: List[str] + ) -> Dict[str, Any]: + if not self.options.filter_selectors_by_schema: + return selectors + schema = self.schema_registry.get(provider) + if not schema: + return selectors + properties = schema.get("properties") + if not isinstance(properties, dict): + return selectors + allowed = set(properties.keys()) + filtered = {key: value for key, value in selectors.items() if key in allowed} + if len(filtered) != len(selectors): + notes.append(f"context_plan_selectors_filtered:{provider}") + return filtered + + def _resolve_provider(self, name: Any) -> Optional[str]: + if name is None: + return None + name_str = str(name) + if name_str in self.provider_catalog: + return name_str + if not self.options.coerce_provider_case: + return None + key = self._provider_aliases.get(name_str.lower()) + return key + + @staticmethod + def _build_provider_aliases( + catalog: Dict[str, ProviderInfo] + ) -> Dict[str, str]: + aliases: Dict[str, str] = {} + for key, info in catalog.items(): + aliases[key.lower()] = key + aliases[info.name.lower()] = key + return aliases diff --git a/src/fetchgraph/relational/dsl/__init__.py b/src/fetchgraph/relational/dsl/__init__.py deleted file mode 100644 index 502d01d7..00000000 --- a/src/fetchgraph/relational/dsl/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Relational DSL components (parsing, AST, compilation).""" diff --git a/src/fetchgraph/relational/dsl/ast.py b/src/fetchgraph/relational/dsl/ast.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/fetchgraph/relational/dsl/compile.py b/src/fetchgraph/relational/dsl/compile.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/fetchgraph/relational/dsl/diagnostics.py b/src/fetchgraph/relational/dsl/diagnostics.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/fetchgraph/relational/dsl/normalize.py b/src/fetchgraph/relational/dsl/normalize.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/fetchgraph/relational/dsl/parser.py b/src/fetchgraph/relational/dsl/parser.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/fetchgraph/relational/dsl/spec.yaml b/src/fetchgraph/relational/dsl/spec.yaml deleted file mode 100644 index a7275a90..00000000 --- a/src/fetchgraph/relational/dsl/spec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -# Placeholder for relational DSL specification. -# TODO: define keys, aliases, defaults, and operations. diff --git a/src/fetchgraph/relational/normalize.py b/src/fetchgraph/relational/normalize.py new file mode 100644 index 00000000..6ef0a7d1 --- /dev/null +++ b/src/fetchgraph/relational/normalize.py @@ -0,0 +1,196 @@ +from __future__ import annotations + +import re +from typing import Any, Dict, Optional +from collections.abc import Callable, MutableMapping + +from .types import SelectorsDict + +_AGG_REGEX = re.compile(r"^(?P[a-zA-Z_][\w]*)\s*\(\s*(?P[^)]+)\s*\)$") + +def _set_list_field( + out: MutableMapping[str, Any], + key: str, + value: Any, + normalizer: Callable[[Any], Any], +) -> None: + """ + Нормализует поле, которое по контракту должно быть list. + + Правило: + - если нормализатор вернул list -> ставим + - иначе -> удаляем ключ (не оставляем None и не оставляем мусор) + + Это делает normalize_* "неухудшающим": не превращает отсутствующее поле в None + и не создаёт гарантированную ошибку list_type. + """ + normalized = normalizer(value) + if isinstance(normalized, list): + out[key] = normalized + else: + out.pop(key, None) + + +def normalize_relational_selectors(selectors: SelectorsDict) -> SelectorsDict: + if not isinstance(selectors, dict): + return selectors + + normalized: dict[str, Any] = dict(selectors) + + op = normalized.get("op") + if op == "aggregate": + normalized["op"] = "query" + op = "query" + if op != "query": + return normalized + + _set_list_field( + normalized, "aggregations", normalized.get("aggregations"), _normalize_aggregations + ) + _set_list_field(normalized, "group_by", normalized.get("group_by"), _normalize_group_by) + + normalized_filters = _normalize_filters(normalized.get("filters")) + normalized["filters"] = normalized_filters + + normalized = _normalize_min_max_filter(normalized, normalized_filters) + + return normalized + + +def _normalize_aggregations(value: Any) -> Any: + if value is None: + return None + if not isinstance(value, list): + value = [value] + normalized: list[Any] = [] + for item in value: + if item is None: + continue + if isinstance(item, str): + parsed = _parse_agg_field(item) + if parsed: + agg, field_name = parsed + normalized.append({"field": field_name, "agg": agg, "alias": None}) + continue + if not isinstance(item, dict): + continue + entry = dict(item) + if not entry.get("agg"): + field = entry.get("field") + parsed = _parse_agg_field(field) + if parsed: + agg, field_name = parsed + entry.setdefault("agg", agg) + entry["field"] = field_name + if entry.get("field") and entry.get("agg"): + normalized.append(entry) + return normalized + + +def _parse_agg_field(value: Any) -> Optional[tuple[str, str]]: + if not isinstance(value, str): + return None + match = _AGG_REGEX.match(value.strip()) + if not match: + return None + agg = match.group("agg").lower() + field = match.group("field").strip() + return agg, field + +def _normalize_filters(value: Any) -> Any: + if isinstance(value, list): + clauses = _flatten_filter_clauses(value) + if not clauses: + return None + if len(clauses) == 1: + return clauses[0] + return {"type": "logical", "op": "and", "clauses": clauses} + if isinstance(value, dict) and "clauses" in value and "type" not in value: + normalized = dict(value) + normalized.setdefault("type", "logical") + normalized.setdefault("op", "and") + # return normalized + return _normalize_logical_filter(normalized) + if isinstance(value, dict) and value.get("type") == "logical": + return _normalize_logical_filter(value) + return value + + +def _normalize_min_max_filter(selectors: SelectorsDict, filters: Any) -> SelectorsDict: + if not isinstance(filters, dict): + return selectors + if filters.get("type") != "comparison": + return selectors + op = filters.get("op") + if not isinstance(op, str): + return selectors + op_lower = op.lower() + if op_lower not in {"min", "max"}: + return selectors + if "value" in filters and filters.get("value") is not None: + return selectors + field = filters.get("field") + if not isinstance(field, str) or not field.strip(): + return selectors + raw_aggregations = selectors.get("aggregations") + if isinstance(raw_aggregations, list): + aggregations = list(raw_aggregations) + elif raw_aggregations is None: + aggregations = [] + else: + aggregations = [raw_aggregations] + aggregations.append({"field": field, "agg": op_lower, "alias": f"{op_lower}_{field}"}) + normalized = dict(selectors) + normalized["aggregations"] = _normalize_aggregations(aggregations) + normalized["filters"] = None + return normalized + + +def _normalize_group_by(value: Any) -> Any: + if value is None: + return [] + if not isinstance(value, list): + if isinstance(value, (str, dict)): + value = [value] + else: + return [] + normalized: list[dict[str, Any]] = [] + for item in value: + if item is None: + continue + if isinstance(item, str): + field = item.strip() + if field: + normalized.append({"field": field}) + continue + if not isinstance(item, dict): + continue + field = item.get("field") + if isinstance(field, str) and field.strip(): + entry = dict(item) + entry["field"] = field.strip() + normalized.append(entry) + return normalized + + +def _flatten_filter_clauses(value: list[Any]) -> list[Any]: + flattened: list[Any] = [] + for clause in value: + if clause is None: + continue + if isinstance(clause, list): + flattened.extend(_flatten_filter_clauses(clause)) + else: + flattened.append(clause) + return flattened + + +def _normalize_logical_filter(value: Dict[str, Any]) -> Dict[str, Any]: + normalized = dict(value) + op = normalized.get("op") + if isinstance(op, str): + normalized["op"] = op.lower() + clauses = normalized.get("clauses") + if isinstance(clauses, list): + normalized["clauses"] = _flatten_filter_clauses(clauses) + return normalized diff --git a/src/fetchgraph/relational/providers/base.py b/src/fetchgraph/relational/providers/base.py index 0c99912b..5563d1c4 100644 --- a/src/fetchgraph/relational/providers/base.py +++ b/src/fetchgraph/relational/providers/base.py @@ -305,4 +305,4 @@ def _handle_query(self, req: RelationalQuery) -> QueryResult: # pragma: no cove raise NotImplementedError -__all__ = ["RelationalDataProvider"] +__all__ = ["RelationalDataProvider"] \ No newline at end of file diff --git a/src/fetchgraph/relational/providers/composite_provider.py b/src/fetchgraph/relational/providers/composite_provider.py index 581a9383..368c6f55 100644 --- a/src/fetchgraph/relational/providers/composite_provider.py +++ b/src/fetchgraph/relational/providers/composite_provider.py @@ -1080,4 +1080,4 @@ def describe(self): return info -__all__ = ["CompositeRelationalProvider"] +__all__ = ["CompositeRelationalProvider"] \ No newline at end of file diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0001_20260119_133537_692233_orders_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0001_20260119_133537_692233_orders_._plan_trace.txt new file mode 100644 index 00000000..3bd10852 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0001_20260119_133537_692233_orders_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(*)", + "alias": "total_orders" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "total_orders" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(*)", + "alias": "total_orders" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "total_orders" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(*)", + "alias": "total_orders" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "total_orders" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0002_20260119_133537_708677_customers_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0002_20260119_133537_708677_customers_._plan_trace.txt new file mode 100644 index 00000000..3115fc28 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0002_20260119_133537_708677_customers_._plan_trace.txt @@ -0,0 +1,82 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "aggregations": [ + { + "field": "customer_id", + "agg": "count_distinct", + "alias": "total_customers" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "aggregations": [ + { + "field": "customer_id", + "agg": "count_distinct", + "alias": "total_customers" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "aggregations": [ + { + "field": "customer_id", + "agg": "count_distinct", + "alias": "total_customers" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0004_20260119_133537_736816_order_items_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0004_20260119_133537_736816_order_items_._plan_trace.txt new file mode 100644 index 00000000..2214c35b --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0004_20260119_133537_736816_order_items_._plan_trace.txt @@ -0,0 +1,85 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "aggregations": [ + { + "field": "order_item_id", + "agg": "count", + "alias": "total_rows" + } + ], + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "aggregations": [ + { + "field": "order_item_id", + "agg": "count", + "alias": "total_rows" + } + ], + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "aggregations": [ + { + "field": "order_item_id", + "agg": "count", + "alias": "total_rows" + } + ], + "limit": 1 + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0006_20260119_133537_770370_min_orders.order_date_YYYY-MM-DD._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0006_20260119_133537_770370_min_orders.order_date_YYYY-MM-DD._plan_trace.txt new file mode 100644 index 00000000..75d6f9cf --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0006_20260119_133537_770370_min_orders.order_date_YYYY-MM-DD._plan_trace.txt @@ -0,0 +1,103 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "min_order_date" + } + ], + "aggregations": [ + { + "field": "orders.order_date", + "agg": "min", + "alias": "min_order_date" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "min_order_date" + } + ], + "aggregations": [ + { + "field": "orders.order_date", + "agg": "min", + "alias": "min_order_date" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "min_order_date" + } + ], + "aggregations": [ + { + "field": "orders.order_date", + "agg": "min", + "alias": "min_order_date" + } + ], + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0007_20260119_133537_787946_max_orders.order_date_YYYY-MM-DD._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0007_20260119_133537_787946_max_orders.order_date_YYYY-MM-DD._plan_trace.txt new file mode 100644 index 00000000..4648c31d --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0007_20260119_133537_787946_max_orders.order_date_YYYY-MM-DD._plan_trace.txt @@ -0,0 +1,97 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "latest_order_date" + } + ], + "aggregations": [ + { + "field": "orders.order_date", + "agg": "max" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "latest_order_date" + } + ], + "aggregations": [ + { + "field": "orders.order_date", + "agg": "max" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "latest_order_date" + } + ], + "aggregations": [ + { + "field": "orders.order_date", + "agg": "max" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0008_20260119_133537_808662_sum_orders.order_total_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0008_20260119_133537_808662_sum_orders.order_total_2_._plan_trace.txt new file mode 100644 index 00000000..94cac19f --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0008_20260119_133537_808662_sum_orders.order_total_2_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "select": [ + { + "expr": "total_revenue", + "alias": "total_revenue" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "select": [ + { + "expr": "total_revenue", + "alias": "total_revenue" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "select": [ + { + "expr": "total_revenue", + "alias": "total_revenue" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0009_20260119_133537_829192_avg_orders.order_total_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0009_20260119_133537_829192_avg_orders.order_total_2_._plan_trace.txt new file mode 100644 index 00000000..e6553863 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0009_20260119_133537_829192_avg_orders.order_total_2_._plan_trace.txt @@ -0,0 +1,82 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "aggregations": [ + { + "field": "order_total", + "agg": "avg", + "alias": "average_order_total" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "aggregations": [ + { + "field": "order_total", + "agg": "avg", + "alias": "average_order_total" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "aggregations": [ + { + "field": "order_total", + "agg": "avg", + "alias": "average_order_total" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0010_20260119_133537_844853_median_orders.order_total_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0010_20260119_133537_844853_median_orders.order_total_2_._plan_trace.txt new file mode 100644 index 00000000..8b6b710f --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0010_20260119_133537_844853_median_orders.order_total_2_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "aggregations": [ + { + "field": "orders.order_total", + "agg": "median", + "alias": "median_order_total" + } + ], + "select": [ + { + "expr": "median_order_total" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "aggregations": [ + { + "field": "orders.order_total", + "agg": "median", + "alias": "median_order_total" + } + ], + "select": [ + { + "expr": "median_order_total" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "aggregations": [ + { + "field": "orders.order_total", + "agg": "median", + "alias": "median_order_total" + } + ], + "select": [ + { + "expr": "median_order_total" + } + ], + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0011_20260119_133537_860976_min_orders.order_total_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0011_20260119_133537_860976_min_orders.order_total_2_._plan_trace.txt new file mode 100644 index 00000000..784dd5ee --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0011_20260119_133537_860976_min_orders.order_total_2_._plan_trace.txt @@ -0,0 +1,79 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "MIN(orders.order_total)" + } + ], + "case_sensitivity": false + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "MIN(orders.order_total)" + } + ], + "case_sensitivity": false + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "MIN(orders.order_total)" + } + ], + "case_sensitivity": false + }, + "max_tokens": 2000 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0012_20260119_133537_878573_max_orders.order_total_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0012_20260119_133537_878573_max_orders.order_total_2_._plan_trace.txt new file mode 100644 index 00000000..94f681a4 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0012_20260119_133537_878573_max_orders.order_total_2_._plan_trace.txt @@ -0,0 +1,79 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "MAX(orders.order_total)" + } + ], + "case_sensitivity": false + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "MAX(orders.order_total)" + } + ], + "case_sensitivity": false + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "MAX(orders.order_total)" + } + ], + "case_sensitivity": false + }, + "max_tokens": 2000 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0013_20260119_133537_895165_order_id_order_total_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0013_20260119_133537_895165_order_id_order_total_._plan_trace.txt new file mode 100644 index 00000000..41e6bb38 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0013_20260119_133537_895165_order_id_order_total_._plan_trace.txt @@ -0,0 +1,103 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "order_id", + "alias": "order_id" + } + ], + "aggregations": [ + { + "field": "order_total", + "agg": "max", + "alias": "max_order_total" + } + ], + "limit": 1 + }, + "max_tokens": 200 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "order_id", + "alias": "order_id" + } + ], + "aggregations": [ + { + "field": "order_total", + "agg": "max", + "alias": "max_order_total" + } + ], + "limit": 1 + }, + "max_tokens": 200 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "order_id", + "alias": "order_id" + } + ], + "aggregations": [ + { + "field": "order_total", + "agg": "max", + "alias": "max_order_total" + } + ], + "limit": 1 + }, + "max_tokens": 200 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0014_20260119_133537_910859_order_id_order_total_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0014_20260119_133537_910859_order_id_order_total_._plan_trace.txt new file mode 100644 index 00000000..242b0437 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0014_20260119_133537_910859_order_id_order_total_._plan_trace.txt @@ -0,0 +1,103 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "order_id", + "alias": "order_id" + } + ], + "aggregations": [ + { + "field": "order_total", + "agg": "min", + "alias": "min_order_total" + } + ], + "limit": 1 + }, + "max_tokens": 200 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "order_id", + "alias": "order_id" + } + ], + "aggregations": [ + { + "field": "order_total", + "agg": "min", + "alias": "min_order_total" + } + ], + "limit": 1 + }, + "max_tokens": 200 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "order_id", + "alias": "order_id" + } + ], + "aggregations": [ + { + "field": "order_total", + "agg": "min", + "alias": "min_order_total" + } + ], + "limit": 1 + }, + "max_tokens": 200 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0015_20260119_133537_928468_cancelled_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0015_20260119_133537_928468_cancelled_._plan_trace.txt new file mode 100644 index 00000000..fbca5ef9 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0015_20260119_133537_928468_cancelled_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(*)", + "alias": "cancelled_orders_count" + } + ], + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "cancelled" + }, + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(*)", + "alias": "cancelled_orders_count" + } + ], + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "cancelled" + }, + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(*)", + "alias": "cancelled_orders_count" + } + ], + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "cancelled" + }, + "case_sensitivity": false + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0016_20260119_133537_944943_delivered_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0016_20260119_133537_944943_delivered_._plan_trace.txt new file mode 100644 index 00000000..297c48c2 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0016_20260119_133537_944943_delivered_._plan_trace.txt @@ -0,0 +1,97 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "delivered_orders_count" + } + ], + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "delivered" + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "delivered_orders_count" + } + ], + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "delivered" + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "delivered_orders_count" + } + ], + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "delivered" + } + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0017_20260119_133537_961602_pending_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0017_20260119_133537_961602_pending_._plan_trace.txt new file mode 100644 index 00000000..0053d385 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0017_20260119_133537_961602_pending_._plan_trace.txt @@ -0,0 +1,118 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "pending" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "pending_orders_count" + } + ], + "select": [ + { + "expr": "pending_orders_count", + "alias": "pending_orders_count" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "pending" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "pending_orders_count" + } + ], + "select": [ + { + "expr": "pending_orders_count", + "alias": "pending_orders_count" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "pending" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "pending_orders_count" + } + ], + "select": [ + { + "expr": "pending_orders_count", + "alias": "pending_orders_count" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0018_20260119_133537_978273_processing_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0018_20260119_133537_978273_processing_._plan_trace.txt new file mode 100644 index 00000000..ebf57ff4 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0018_20260119_133537_978273_processing_._plan_trace.txt @@ -0,0 +1,103 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "processing" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "processing" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "processing" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0019_20260119_133537_995082_shipped_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0019_20260119_133537_995082_shipped_._plan_trace.txt new file mode 100644 index 00000000..3d9ad265 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0019_20260119_133537_995082_shipped_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "shipped" + }, + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "shipped" + }, + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "status", + "op": "=", + "value": "shipped" + }, + "case_sensitivity": false + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0020_20260119_133538_011607_online_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0020_20260119_133538_011607_online_._plan_trace.txt new file mode 100644 index 00000000..637b8720 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0020_20260119_133538_011607_online_._plan_trace.txt @@ -0,0 +1,118 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "order_id" + } + ], + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "online" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "case_sensitivity": false + }, + "max_tokens": 500 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "order_id" + } + ], + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "online" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "case_sensitivity": false + }, + "max_tokens": 500 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "order_id" + } + ], + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "online" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "case_sensitivity": false + }, + "max_tokens": 500 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0021_20260119_133538_028336_partner_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0021_20260119_133538_028336_partner_._plan_trace.txt new file mode 100644 index 00000000..31e7c4fd --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0021_20260119_133538_028336_partner_._plan_trace.txt @@ -0,0 +1,115 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "partner" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "order_count" + } + ] + }, + "max_tokens": 200 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "partner" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "order_count" + } + ] + }, + "max_tokens": 200 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "partner" + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "order_count" + } + ] + }, + "max_tokens": 200 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0022_20260119_133538_055979_phone_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0022_20260119_133538_055979_phone_._plan_trace.txt new file mode 100644 index 00000000..461cd605 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0022_20260119_133538_055979_phone_._plan_trace.txt @@ -0,0 +1,97 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "phone" + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "phone" + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "phone" + } + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0023_20260119_133538_084494_retail_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0023_20260119_133538_084494_retail_._plan_trace.txt new file mode 100644 index 00000000..1221c95e --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0023_20260119_133538_084494_retail_._plan_trace.txt @@ -0,0 +1,118 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "retail" + }, + "aggregations": [ + { + "field": "*", + "agg": "count", + "alias": "order_count" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "retail" + }, + "aggregations": [ + { + "field": "*", + "agg": "count", + "alias": "order_count" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "channel", + "op": "=", + "value": "retail" + }, + "aggregations": [ + { + "field": "*", + "agg": "count", + "alias": "order_count" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0024_20260119_133538_114093_2022_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0024_20260119_133538_114093_2022_._plan_trace.txt new file mode 100644 index 00000000..76bd83f5 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0024_20260119_133538_114093_2022_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "total_orders" + } + ], + "filters": { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2022-01-01" + }, + "case_sensitivity": false + }, + "max_tokens": 200 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "total_orders" + } + ], + "filters": { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2022-01-01" + }, + "case_sensitivity": false + }, + "max_tokens": 200 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "total_orders" + } + ], + "filters": { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2022-01-01" + }, + "case_sensitivity": false + }, + "max_tokens": 200 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0025_20260119_133538_142347_2023_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0025_20260119_133538_142347_2023_._plan_trace.txt new file mode 100644 index 00000000..7db5ce36 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0025_20260119_133538_142347_2023_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(*)", + "alias": "total_orders" + } + ], + "filters": { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2023-01-01" + }, + "case_sensitivity": false + }, + "max_tokens": 50 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(*)", + "alias": "total_orders" + } + ], + "filters": { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2023-01-01" + }, + "case_sensitivity": false + }, + "max_tokens": 50 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(*)", + "alias": "total_orders" + } + ], + "filters": { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2023-01-01" + }, + "case_sensitivity": false + }, + "max_tokens": 50 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0026_20260119_133538_157966_2024_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0026_20260119_133538_157966_2024_._plan_trace.txt new file mode 100644 index 00000000..a5f65a68 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0026_20260119_133538_157966_2024_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "total_orders" + } + ], + "filters": { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2024-01-01" + }, + "case_sensitivity": false + }, + "max_tokens": 50 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "total_orders" + } + ], + "filters": { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2024-01-01" + }, + "case_sensitivity": false + }, + "max_tokens": 50 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "total_orders" + } + ], + "filters": { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2024-01-01" + }, + "case_sensitivity": false + }, + "max_tokens": 50 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0027_20260119_133538_174624_YYYY-MM._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0027_20260119_133538_174624_YYYY-MM._plan_trace.txt new file mode 100644 index 00000000..741570fb --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0027_20260119_133538_174624_YYYY-MM._plan_trace.txt @@ -0,0 +1,130 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "group_by": [ + { + "field": "order_month", + "alias": "order_month" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "order_month" + }, + { + "expr": "order_count" + } + ], + "limit": 1000, + "case_sensitivity": false + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "group_by": [ + { + "field": "order_month", + "alias": "order_month" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "order_month" + }, + { + "expr": "order_count" + } + ], + "limit": 1000, + "case_sensitivity": false + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "group_by": [ + { + "field": "order_month", + "alias": "order_month" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "order_month" + }, + { + "expr": "order_count" + } + ], + "limit": 1000, + "case_sensitivity": false + }, + "max_tokens": 2000 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0028_20260119_133538_194420_YYYY-MM._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0028_20260119_133538_194420_YYYY-MM._plan_trace.txt new file mode 100644 index 00000000..ca47c4b4 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0028_20260119_133538_194420_YYYY-MM._plan_trace.txt @@ -0,0 +1,151 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "group_by": [ + { + "field": "order_month", + "alias": "month" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "month", + "alias": "month" + }, + { + "expr": "order_count", + "alias": "order_count" + } + ], + "limit": 12, + "order_by": [ + { + "field": "order_count", + "direction": "asc" + } + ] + }, + "max_tokens": 1000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "group_by": [ + { + "field": "order_month", + "alias": "month" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "month", + "alias": "month" + }, + { + "expr": "order_count", + "alias": "order_count" + } + ], + "limit": 12, + "order_by": [ + { + "field": "order_count", + "direction": "asc" + } + ] + }, + "max_tokens": 1000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "group_by": [ + { + "field": "order_month", + "alias": "month" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "month", + "alias": "month" + }, + { + "expr": "order_count", + "alias": "order_count" + } + ], + "limit": 12, + "order_by": [ + { + "field": "order_count", + "direction": "asc" + } + ] + }, + "max_tokens": 1000 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0029_20260119_133538_211755_2022-03_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0029_20260119_133538_211755_2022-03_._plan_trace.txt new file mode 100644 index 00000000..0dc6f9a2 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0029_20260119_133538_211755_2022-03_._plan_trace.txt @@ -0,0 +1,151 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2022-03-01" + }, + { + "type": "comparison", + "field": "order_date", + "op": "<=", + "value": "2022-03-31" + } + ] + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "order_count" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2022-03-01" + }, + { + "type": "comparison", + "field": "order_date", + "op": "<=", + "value": "2022-03-31" + } + ] + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "order_count" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2022-03-01" + }, + { + "type": "comparison", + "field": "order_date", + "op": "<=", + "value": "2022-03-31" + } + ] + }, + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + } + ], + "select": [ + { + "expr": "order_count" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0030_20260119_133538_229173_2022-07_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0030_20260119_133538_229173_2022-07_._plan_trace.txt new file mode 100644 index 00000000..785ad222 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0030_20260119_133538_229173_2022-07_._plan_trace.txt @@ -0,0 +1,139 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": ">=", + "value": "2022-07-01" + }, + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": "<", + "value": "2022-08-01" + } + ] + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": ">=", + "value": "2022-07-01" + }, + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": "<", + "value": "2022-08-01" + } + ] + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": ">=", + "value": "2022-07-01" + }, + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": "<", + "value": "2022-08-01" + } + ] + } + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0031_20260119_133538_245323_order_items.line_total_category_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0031_20260119_133538_245323_order_items.line_total_category_._plan_trace.txt new file mode 100644 index 00000000..046585d9 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0031_20260119_133538_245323_order_items.line_total_category_._plan_trace.txt @@ -0,0 +1,130 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "products.category", + "alias": "category" + } + ], + "relations": [ + "items_to_products" + ], + "aggregations": [ + { + "field": "order_items.line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "group_by": [ + { + "field": "products.category", + "alias": "category" + } + ], + "limit": 10 + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "products.category", + "alias": "category" + } + ], + "relations": [ + "items_to_products" + ], + "aggregations": [ + { + "field": "order_items.line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "group_by": [ + { + "field": "products.category", + "alias": "category" + } + ], + "limit": 10 + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "products.category", + "alias": "category" + } + ], + "relations": [ + "items_to_products" + ], + "aggregations": [ + { + "field": "order_items.line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "group_by": [ + { + "field": "products.category", + "alias": "category" + } + ], + "limit": 10 + }, + "max_tokens": 2000 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0032_20260119_133539_259529_sum_line_total_toys_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0032_20260119_133539_259529_sum_line_total_toys_2_._plan_trace.txt new file mode 100644 index 00000000..dacc77d6 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0032_20260119_133539_259529_sum_line_total_toys_2_._plan_trace.txt @@ -0,0 +1,151 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "toys" + } + ] + }, + "relations": [ + "items_to_products" + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue_toys" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "toys" + } + ] + }, + "relations": [ + "items_to_products" + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue_toys" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "toys" + } + ] + }, + "relations": [ + "items_to_products" + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue_toys" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0033_20260119_133539_279390_sum_line_total_toys_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0033_20260119_133539_279390_sum_line_total_toys_2_._plan_trace.txt new file mode 100644 index 00000000..dacc77d6 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0033_20260119_133539_279390_sum_line_total_toys_2_._plan_trace.txt @@ -0,0 +1,151 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "toys" + } + ] + }, + "relations": [ + "items_to_products" + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue_toys" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "toys" + } + ] + }, + "relations": [ + "items_to_products" + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue_toys" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "toys" + } + ] + }, + "relations": [ + "items_to_products" + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue_toys" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0034_20260119_133539_305892_sum_line_total_books_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0034_20260119_133539_305892_sum_line_total_books_2_._plan_trace.txt new file mode 100644 index 00000000..d895a760 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0034_20260119_133539_305892_sum_line_total_books_2_._plan_trace.txt @@ -0,0 +1,133 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "books" + }, + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "books" + }, + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "books" + }, + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0035_20260119_133539_332861_sum_line_total_electronics_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0035_20260119_133539_332861_sum_line_total_electronics_2_._plan_trace.txt new file mode 100644 index 00000000..ac39e3c2 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0035_20260119_133539_332861_sum_line_total_electronics_2_._plan_trace.txt @@ -0,0 +1,130 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "electronics" + }, + "aggregations": [ + { + "field": "order_items.line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 1000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "electronics" + }, + "aggregations": [ + { + "field": "order_items.line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 1000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "electronics" + }, + "aggregations": [ + { + "field": "order_items.line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 1000 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0036_20260119_133539_360048_sum_line_total_furniture_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0036_20260119_133539_360048_sum_line_total_furniture_2_._plan_trace.txt new file mode 100644 index 00000000..662c78ef --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0036_20260119_133539_360048_sum_line_total_furniture_2_._plan_trace.txt @@ -0,0 +1,133 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "furniture" + }, + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "furniture" + }, + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "furniture" + }, + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0037_20260119_133539_389073_sum_line_total_office_supplies_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0037_20260119_133539_389073_sum_line_total_office_supplies_2_._plan_trace.txt new file mode 100644 index 00000000..073c478c --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0037_20260119_133539_389073_sum_line_total_office_supplies_2_._plan_trace.txt @@ -0,0 +1,130 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "office_supplies" + }, + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 500 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "office_supplies" + }, + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 500 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.line_total" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "office_supplies" + }, + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "case_sensitivity": false + }, + "max_tokens": 500 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0038_20260119_133539_411584_sum_line_total_outdoors_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0038_20260119_133539_411584_sum_line_total_outdoors_2_._plan_trace.txt new file mode 100644 index 00000000..164198f7 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0038_20260119_133539_411584_sum_line_total_outdoors_2_._plan_trace.txt @@ -0,0 +1,112 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "sum(order_items.line_total)", + "alias": "total_revenue" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "outdoors" + }, + "case_sensitivity": false + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "sum(order_items.line_total)", + "alias": "total_revenue" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "outdoors" + }, + "case_sensitivity": false + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "sum(order_items.line_total)", + "alias": "total_revenue" + } + ], + "relations": [ + "items_to_products" + ], + "filters": { + "type": "comparison", + "entity": "products", + "field": "category", + "op": "=", + "value": "outdoors" + }, + "case_sensitivity": false + }, + "max_tokens": 2000 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0039_20260119_133539_433448_product_id_max_products.price_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0039_20260119_133539_433448_product_id_max_products.price_._plan_trace.txt new file mode 100644 index 00000000..86123003 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0039_20260119_133539_433448_product_id_max_products.price_._plan_trace.txt @@ -0,0 +1,103 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "select": [ + { + "expr": "products.product_id", + "alias": "product_id" + } + ], + "aggregations": [ + { + "field": "products.price", + "agg": "max", + "alias": "max_price" + } + ], + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "select": [ + { + "expr": "products.product_id", + "alias": "product_id" + } + ], + "aggregations": [ + { + "field": "products.price", + "agg": "max", + "alias": "max_price" + } + ], + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "select": [ + { + "expr": "products.product_id", + "alias": "product_id" + } + ], + "aggregations": [ + { + "field": "products.price", + "agg": "max", + "alias": "max_price" + } + ], + "limit": 1 + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0040_20260119_133539_457942_max_products.price_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0040_20260119_133539_457942_max_products.price_._plan_trace.txt new file mode 100644 index 00000000..28ef32a5 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0040_20260119_133539_457942_max_products.price_._plan_trace.txt @@ -0,0 +1,97 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "aggregations": [ + { + "field": "price", + "agg": "max", + "alias": "max_price" + } + ], + "select": [ + { + "expr": "max_price" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "aggregations": [ + { + "field": "price", + "agg": "max", + "alias": "max_price" + } + ], + "select": [ + { + "expr": "max_price" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "aggregations": [ + { + "field": "price", + "agg": "max", + "alias": "max_price" + } + ], + "select": [ + { + "expr": "max_price" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0041_20260119_133539_480567_product_id_min_products.price_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0041_20260119_133539_480567_product_id_min_products.price_._plan_trace.txt new file mode 100644 index 00000000..14e4c5cb --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0041_20260119_133539_480567_product_id_min_products.price_._plan_trace.txt @@ -0,0 +1,94 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "aggregations": [ + { + "field": "price", + "agg": "min" + } + ], + "select": [ + { + "expr": "product_id" + } + ] + }, + "max_tokens": 200 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "aggregations": [ + { + "field": "price", + "agg": "min" + } + ], + "select": [ + { + "expr": "product_id" + } + ] + }, + "max_tokens": 200 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "aggregations": [ + { + "field": "price", + "agg": "min" + } + ], + "select": [ + { + "expr": "product_id" + } + ] + }, + "max_tokens": 200 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0042_20260119_133539_504992_min_products.price_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0042_20260119_133539_504992_min_products.price_._plan_trace.txt new file mode 100644 index 00000000..d6b8ebca --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0042_20260119_133539_504992_min_products.price_._plan_trace.txt @@ -0,0 +1,97 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "aggregations": [ + { + "field": "price", + "agg": "min", + "alias": "min_price" + } + ], + "select": [ + { + "expr": "min_price" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "aggregations": [ + { + "field": "price", + "agg": "min", + "alias": "min_price" + } + ], + "select": [ + { + "expr": "min_price" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "aggregations": [ + { + "field": "price", + "agg": "min", + "alias": "min_price" + } + ], + "select": [ + { + "expr": "min_price" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0043_20260119_133539_527837_product_id_sum_order_items.line_total_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0043_20260119_133539_527837_product_id_sum_order_items.line_total_._plan_trace.txt new file mode 100644 index 00000000..9f77e23c --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0043_20260119_133539_527837_product_id_sum_order_items.line_total_._plan_trace.txt @@ -0,0 +1,121 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.product_id" + } + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "group_by": [ + { + "field": "product_id", + "alias": "product_id" + } + ], + "limit": 1, + "case_sensitivity": false + }, + "max_tokens": 500 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.product_id" + } + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "group_by": [ + { + "field": "product_id", + "alias": "product_id" + } + ], + "limit": 1, + "case_sensitivity": false + }, + "max_tokens": 500 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.product_id" + } + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "group_by": [ + { + "field": "product_id", + "alias": "product_id" + } + ], + "limit": 1, + "case_sensitivity": false + }, + "max_tokens": 500 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0044_20260119_133540_291264_product_id-_sum_line_total_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0044_20260119_133540_291264_product_id-_sum_line_total_2_._plan_trace.txt new file mode 100644 index 00000000..aa6c477f --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0044_20260119_133540_291264_product_id-_sum_line_total_2_._plan_trace.txt @@ -0,0 +1,136 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.product_id", + "alias": "product_id" + }, + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "group_by": [ + { + "entity": "order_items", + "field": "product_id", + "alias": "product_id" + } + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.product_id", + "alias": "product_id" + }, + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "group_by": [ + { + "entity": "order_items", + "field": "product_id", + "alias": "product_id" + } + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_items.product_id", + "alias": "product_id" + }, + { + "expr": "order_items.line_total", + "alias": "line_total" + } + ], + "group_by": [ + { + "entity": "order_items", + "field": "product_id", + "alias": "product_id" + } + ], + "aggregations": [ + { + "field": "line_total", + "agg": "sum", + "alias": "total_revenue" + } + ], + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0045_20260119_133540_822643_sum_order_items.quantity_-_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0045_20260119_133540_822643_sum_order_items.quantity_-_._plan_trace.txt new file mode 100644 index 00000000..aa8dbf41 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0045_20260119_133540_822643_sum_order_items.quantity_-_._plan_trace.txt @@ -0,0 +1,142 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "select": [ + { + "expr": "products.product_id", + "alias": "product_id" + } + ], + "aggregations": [ + { + "field": "order_items.quantity", + "agg": "sum", + "alias": "total_quantity" + } + ], + "group_by": [ + { + "field": "products.product_id", + "alias": "product_id" + } + ], + "relations": [ + "items_to_products" + ], + "limit": 1, + "order_by": { + "field": "total_quantity", + "desc": true + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "select": [ + { + "expr": "products.product_id", + "alias": "product_id" + } + ], + "aggregations": [ + { + "field": "order_items.quantity", + "agg": "sum", + "alias": "total_quantity" + } + ], + "group_by": [ + { + "field": "products.product_id", + "alias": "product_id" + } + ], + "relations": [ + "items_to_products" + ], + "limit": 1, + "order_by": { + "field": "total_quantity", + "desc": true + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "products", + "select": [ + { + "expr": "products.product_id", + "alias": "product_id" + } + ], + "aggregations": [ + { + "field": "order_items.quantity", + "agg": "sum", + "alias": "total_quantity" + } + ], + "group_by": [ + { + "field": "products.product_id", + "alias": "product_id" + } + ], + "relations": [ + "items_to_products" + ], + "limit": 1, + "order_by": { + "field": "total_quantity", + "desc": true + } + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0046_20260119_133541_342609_sum_order_items.quantity_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0046_20260119_133541_342609_sum_order_items.quantity_._plan_trace.txt new file mode 100644 index 00000000..fd08216d --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0046_20260119_133541_342609_sum_order_items.quantity_._plan_trace.txt @@ -0,0 +1,82 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "aggregations": [ + { + "field": "quantity", + "agg": "sum", + "alias": "total_quantity_sold" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "aggregations": [ + { + "field": "quantity", + "agg": "sum", + "alias": "total_quantity_sold" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "aggregations": [ + { + "field": "quantity", + "agg": "sum", + "alias": "total_quantity_sold" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0048_20260119_133541_375247_1_order_items_per_order_id_1_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0048_20260119_133541_375247_1_order_items_per_order_id_1_._plan_trace.txt new file mode 100644 index 00000000..76f5d9ed --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0048_20260119_133541_375247_1_order_items_per_order_id_1_._plan_trace.txt @@ -0,0 +1,139 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_id", + "alias": "order_id" + } + ], + "group_by": [ + { + "field": "order_id", + "alias": "order_id" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "item_count" + } + ], + "filters": { + "type": "comparison", + "field": "item_count", + "op": "=", + "value": 1 + }, + "case_sensitivity": false + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_id", + "alias": "order_id" + } + ], + "group_by": [ + { + "field": "order_id", + "alias": "order_id" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "item_count" + } + ], + "filters": { + "type": "comparison", + "field": "item_count", + "op": "=", + "value": 1 + }, + "case_sensitivity": false + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "order_id", + "alias": "order_id" + } + ], + "group_by": [ + { + "field": "order_id", + "alias": "order_id" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "item_count" + } + ], + "filters": { + "type": "comparison", + "field": "item_count", + "op": "=", + "value": 1 + }, + "case_sensitivity": false + }, + "max_tokens": 2000 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0049_20260119_133541_393992_San_Antonio_2022-03_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0049_20260119_133541_393992_San_Antonio_2022-03_._plan_trace.txt new file mode 100644 index 00000000..479aeba9 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0049_20260119_133541_393992_San_Antonio_2022-03_._plan_trace.txt @@ -0,0 +1,148 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "customers", + "field": "city", + "op": "=", + "value": "San Antonio" + }, + { + "type": "comparison", + "field": "order_date", + "op": "starts_with", + "value": "2022-03" + } + ] + }, + "relations": [ + "orders_to_customers" + ], + "case_sensitivity": false + }, + "max_tokens": 500 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "customers", + "field": "city", + "op": "=", + "value": "San Antonio" + }, + { + "type": "comparison", + "field": "order_date", + "op": "starts_with", + "value": "2022-03" + } + ] + }, + "relations": [ + "orders_to_customers" + ], + "case_sensitivity": false + }, + "max_tokens": 500 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "customers", + "field": "city", + "op": "=", + "value": "San Antonio" + }, + { + "type": "comparison", + "field": "order_date", + "op": "starts_with", + "value": "2022-03" + } + ] + }, + "relations": [ + "orders_to_customers" + ], + "case_sensitivity": false + }, + "max_tokens": 500 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0050_20260119_133541_413772_shipped_San_Antonio_2022-03_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0050_20260119_133541_413772_shipped_San_Antonio_2022-03_._plan_trace.txt new file mode 100644 index 00000000..08150ea9 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0050_20260119_133541_413772_shipped_San_Antonio_2022-03_._plan_trace.txt @@ -0,0 +1,202 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "orders", + "field": "status", + "op": "=", + "value": "shipped" + }, + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": ">=", + "value": "2022-03-01T00:00:00Z" + }, + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": "<", + "value": "2022-04-01T00:00:00Z" + } + ] + }, + "relations": [ + "orders_to_customers" + ], + "semantic_clauses": [ + { + "entity": "customers", + "query": "San Antonio", + "fields": [ + "city" + ], + "mode": "filter" + } + ], + "case_sensitivity": false + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "orders", + "field": "status", + "op": "=", + "value": "shipped" + }, + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": ">=", + "value": "2022-03-01T00:00:00Z" + }, + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": "<", + "value": "2022-04-01T00:00:00Z" + } + ] + }, + "relations": [ + "orders_to_customers" + ], + "semantic_clauses": [ + { + "entity": "customers", + "query": "San Antonio", + "fields": [ + "city" + ], + "mode": "filter" + } + ], + "case_sensitivity": false + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "orders", + "field": "status", + "op": "=", + "value": "shipped" + }, + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": ">=", + "value": "2022-03-01T00:00:00Z" + }, + { + "type": "comparison", + "entity": "orders", + "field": "order_date", + "op": "<", + "value": "2022-04-01T00:00:00Z" + } + ] + }, + "relations": [ + "orders_to_customers" + ], + "semantic_clauses": [ + { + "entity": "customers", + "query": "San Antonio", + "fields": [ + "city" + ], + "mode": "filter" + } + ], + "case_sensitivity": false + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0051_20260119_133541_432318_Los_Angeles_2023-08_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0051_20260119_133541_432318_Los_Angeles_2023-08_._plan_trace.txt new file mode 100644 index 00000000..df2d17f2 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0051_20260119_133541_432318_Los_Angeles_2023-08_._plan_trace.txt @@ -0,0 +1,166 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "customers", + "field": "city", + "op": "=", + "value": "Los Angeles" + }, + { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2023-08-01" + }, + { + "type": "comparison", + "field": "order_date", + "op": "<=", + "value": "2023-08-31" + } + ] + }, + "relations": [ + "orders_to_customers" + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "customers", + "field": "city", + "op": "=", + "value": "Los Angeles" + }, + { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2023-08-01" + }, + { + "type": "comparison", + "field": "order_date", + "op": "<=", + "value": "2023-08-31" + } + ] + }, + "relations": [ + "orders_to_customers" + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "customers", + "field": "city", + "op": "=", + "value": "Los Angeles" + }, + { + "type": "comparison", + "field": "order_date", + "op": ">=", + "value": "2023-08-01" + }, + { + "type": "comparison", + "field": "order_date", + "op": "<=", + "value": "2023-08-31" + } + ] + }, + "relations": [ + "orders_to_customers" + ], + "case_sensitivity": false + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0052_20260119_133541_448371_customer_id_323_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0052_20260119_133541_448371_customer_id_323_._plan_trace.txt new file mode 100644 index 00000000..e3f359e4 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0052_20260119_133541_448371_customer_id_323_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "limit": 1 + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0053_20260119_133541_464736_customer_id_323_consumer_corporate_home_office._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0053_20260119_133541_464736_customer_id_323_consumer_corporate_home_office._plan_trace.txt new file mode 100644 index 00000000..27d210b4 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0053_20260119_133541_464736_customer_id_323_consumer_corporate_home_office._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "limit": 1 + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0054_20260119_133541_480392_customers.signup_date_customer_id_323_YYYY-MM-DD._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0054_20260119_133541_480392_customers.signup_date_customer_id_323_YYYY-MM-DD._plan_trace.txt new file mode 100644 index 00000000..ec4dbbda --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0054_20260119_133541_480392_customers.signup_date_customer_id_323_YYYY-MM-DD._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0055_20260119_133541_500165_customer_id_323_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0055_20260119_133541_500165_customer_id_323_._plan_trace.txt new file mode 100644 index 00000000..f2876f64 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0055_20260119_133541_500165_customer_id_323_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(*)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "case_sensitivity": false + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0056_20260119_163550_586309_customer_id_323_sum_orders.order_total_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0056_20260119_163550_586309_customer_id_323_sum_orders.order_total_2_._plan_trace.txt new file mode 100644 index 00000000..044280fe --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0056_20260119_163550_586309_customer_id_323_sum_orders.order_total_2_._plan_trace.txt @@ -0,0 +1,121 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_total", + "alias": "total_spent" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_total", + "alias": "total_spent" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_total", + "alias": "total_spent" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ], + "case_sensitivity": false + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0057_20260119_163556_526136_customer_id_323_YYYY-MM-DD._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0057_20260119_163556_526136_customer_id_323_YYYY-MM-DD._plan_trace.txt new file mode 100644 index 00000000..1e773ad8 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0057_20260119_163556_526136_customer_id_323_YYYY-MM-DD._plan_trace.txt @@ -0,0 +1,121 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 323 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0058_20260119_163557_042633_customer_id_536_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0058_20260119_163557_042633_customer_id_536_._plan_trace.txt new file mode 100644 index 00000000..31f97525 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0058_20260119_163557_042633_customer_id_536_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "limit": 1 + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0059_20260119_163557_528349_customer_id_536_consumer_corporate_home_office._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0059_20260119_163557_528349_customer_id_536_consumer_corporate_home_office._plan_trace.txt new file mode 100644 index 00000000..cd57f376 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0059_20260119_163557_528349_customer_id_536_consumer_corporate_home_office._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0060_20260119_163604_515336_customers.signup_date_customer_id_536_YYYY-MM-DD._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0060_20260119_163604_515336_customers.signup_date_customer_id_536_YYYY-MM-DD._plan_trace.txt new file mode 100644 index 00000000..85649060 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0060_20260119_163604_515336_customers.signup_date_customer_id_536_YYYY-MM-DD._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0061_20260119_163606_123642_customer_id_536_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0061_20260119_163606_123642_customer_id_536_._plan_trace.txt new file mode 100644 index 00000000..3f306e7c --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0061_20260119_163606_123642_customer_id_536_._plan_trace.txt @@ -0,0 +1,97 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + } + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0062_20260119_163606_140388_customer_id_536_sum_orders.order_total_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0062_20260119_163606_140388_customer_id_536_sum_orders.order_total_2_._plan_trace.txt new file mode 100644 index 00000000..513d428a --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0062_20260119_163606_140388_customer_id_536_sum_orders.order_total_2_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0063_20260119_163606_850367_customer_id_536_YYYY-MM-DD._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0063_20260119_163606_850367_customer_id_536_YYYY-MM-DD._plan_trace.txt new file mode 100644 index 00000000..6a71321d --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0063_20260119_163606_850367_customer_id_536_YYYY-MM-DD._plan_trace.txt @@ -0,0 +1,121 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 536 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0064_20260119_163607_536957_customer_id_692_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0064_20260119_163607_536957_customer_id_692_._plan_trace.txt new file mode 100644 index 00000000..31f389a4 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0064_20260119_163607_536957_customer_id_692_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0065_20260119_163608_189367_customer_id_692_consumer_corporate_home_office._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0065_20260119_163608_189367_customer_id_692_consumer_corporate_home_office._plan_trace.txt new file mode 100644 index 00000000..2c6ef491 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0065_20260119_163608_189367_customer_id_692_consumer_corporate_home_office._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "limit": 1 + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0066_20260119_163608_690578_customers.signup_date_customer_id_692_YYYY-MM-DD._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0066_20260119_163608_690578_customers.signup_date_customer_id_692_YYYY-MM-DD._plan_trace.txt new file mode 100644 index 00000000..9f603398 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0066_20260119_163608_690578_customers.signup_date_customer_id_692_YYYY-MM-DD._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0067_20260119_163638_280588_customer_id_692_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0067_20260119_163638_280588_customer_id_692_._plan_trace.txt new file mode 100644 index 00000000..05047d91 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0067_20260119_163638_280588_customer_id_692_._plan_trace.txt @@ -0,0 +1,109 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "entity": "customers", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "relations": [ + "orders_to_customers" + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "entity": "customers", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "relations": [ + "orders_to_customers" + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "entity": "customers", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "relations": [ + "orders_to_customers" + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0068_20260119_163638_300137_customer_id_692_sum_orders.order_total_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0068_20260119_163638_300137_customer_id_692_sum_orders.order_total_2_._plan_trace.txt new file mode 100644 index 00000000..eed41ba0 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0068_20260119_163638_300137_customer_id_692_sum_orders.order_total_2_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ] + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ] + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0069_20260119_163638_822771_customer_id_692_YYYY-MM-DD._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0069_20260119_163638_822771_customer_id_692_YYYY-MM-DD._plan_trace.txt new file mode 100644 index 00000000..b43b77eb --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0069_20260119_163638_822771_customer_id_692_YYYY-MM-DD._plan_trace.txt @@ -0,0 +1,121 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 692 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0070_20260119_163648_740364_customer_id_722_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0070_20260119_163648_740364_customer_id_722_._plan_trace.txt new file mode 100644 index 00000000..333d39d3 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0070_20260119_163648_740364_customer_id_722_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "limit": 1 + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0071_20260119_163653_414936_customer_id_722_consumer_corporate_home_office._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0071_20260119_163653_414936_customer_id_722_consumer_corporate_home_office._plan_trace.txt new file mode 100644 index 00000000..cdc14dd3 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0071_20260119_163653_414936_customer_id_722_consumer_corporate_home_office._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "limit": 1 + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0072_20260119_163658_005036_customers.signup_date_customer_id_722_YYYY-MM-DD._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0072_20260119_163658_005036_customers.signup_date_customer_id_722_YYYY-MM-DD._plan_trace.txt new file mode 100644 index 00000000..addb94b7 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0072_20260119_163658_005036_customers.signup_date_customer_id_722_YYYY-MM-DD._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0073_20260119_163707_431102_customer_id_722_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0073_20260119_163707_431102_customer_id_722_._plan_trace.txt new file mode 100644 index 00000000..b8feae96 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0073_20260119_163707_431102_customer_id_722_._plan_trace.txt @@ -0,0 +1,97 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + } + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "COUNT(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + } + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0074_20260119_163710_235823_customer_id_722_sum_orders.order_total_2_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0074_20260119_163710_235823_customer_id_722_sum_orders.order_total_2_._plan_trace.txt new file mode 100644 index 00000000..ddd5c027 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0074_20260119_163710_235823_customer_id_722_sum_orders.order_total_2_._plan_trace.txt @@ -0,0 +1,118 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ], + "select": [ + { + "expr": "total_spent", + "alias": "total_spent" + } + ] + }, + "max_tokens": 50 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ], + "select": [ + { + "expr": "total_spent", + "alias": "total_spent" + } + ] + }, + "max_tokens": 50 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "aggregations": [ + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ], + "select": [ + { + "expr": "total_spent", + "alias": "total_spent" + } + ] + }, + "max_tokens": 50 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0075_20260119_163715_021803_customer_id_722_YYYY-MM-DD._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0075_20260119_163715_021803_customer_id_722_YYYY-MM-DD._plan_trace.txt new file mode 100644 index 00000000..69dd4f21 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0075_20260119_163715_021803_customer_id_722_YYYY-MM-DD._plan_trace.txt @@ -0,0 +1,121 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "orders.order_date", + "alias": "last_order_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 722 + }, + "aggregations": [ + { + "field": "order_date", + "agg": "max", + "alias": "last_order_date" + } + ], + "limit": 1 + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0076_20260119_163719_274457_customer_id_725_._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0076_20260119_163719_274457_customer_id_725_._plan_trace.txt new file mode 100644 index 00000000..d16cd35c --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0076_20260119_163719_274457_customer_id_725_._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 725 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 725 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "customer_city" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 725 + }, + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0077_20260119_163722_195616_customer_id_725_consumer_corporate_home_office._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0077_20260119_163722_195616_customer_id_725_consumer_corporate_home_office._plan_trace.txt new file mode 100644 index 00000000..40f8d735 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0077_20260119_163722_195616_customer_id_725_consumer_corporate_home_office._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 725 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 725 + }, + "limit": 1 + }, + "max_tokens": null + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "segment", + "alias": "customer_segment" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 725 + }, + "limit": 1 + }, + "max_tokens": null +} + diff --git a/tests/fixtures/regressions_fixed/fetchgraph_plans/0078_20260119_163726_540394_customers.signup_date_customer_id_725_YYYY-MM-DD._plan_trace.txt b/tests/fixtures/regressions_fixed/fetchgraph_plans/0078_20260119_163726_540394_customers.signup_date_customer_id_725_YYYY-MM-DD._plan_trace.txt new file mode 100644 index 00000000..138c7f30 --- /dev/null +++ b/tests/fixtures/regressions_fixed/fetchgraph_plans/0078_20260119_163726_540394_customers.signup_date_customer_id_725_YYYY-MM-DD._plan_trace.txt @@ -0,0 +1,100 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 725 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} + +{ + "stage": "after_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 725 + }, + "limit": 1 + }, + "max_tokens": 100 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [], + "normalization_notes": [] + } +} + +{ + "stage": "fetch_request", + "provider": "demo_qa", + "provider_class": "PandasRelationalDataProvider", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 725 + }, + "limit": 1 + }, + "max_tokens": 100 +} + diff --git a/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_003_plan_trace.txt b/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_003_plan_trace.txt new file mode 100644 index 00000000..d565b440 --- /dev/null +++ b/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_003_plan_trace.txt @@ -0,0 +1,35 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "entity": "products", + "aggregations": [ + { + "field": "product_id", + "agg": "count", + "alias": "total_products" + } + ], + "group_by": [], + "filters": null + }, + "max_tokens": 100 + } + ], + "adr_queries": [], + "constraints": [], + "entities": [], + "dtos": [], + "normalization_notes": [ + "{\"provider\": \"demo_qa\", \"selectors_validate_before\": \"error\", \"selectors_validate_after\": \"error\", \"selectors_normalization_decision\": \"use_normalized_unvalidated\", \"selectors_before\": {\"op\": \"aggregate\", \"entity\": \"products\", \"aggregations\": [{\"field\": \"product_id\", \"agg\": \"count\", \"alias\": \"total_products\"}]}, \"selectors_after\": {\"op\": \"query\", \"entity\": \"products\", \"aggregations\": [{\"field\": \"product_id\", \"agg\": \"count\", \"alias\": \"total_products\"}], \"group_by\": [], \"filters\": null}}" + ] + } +} diff --git a/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_005_plan_trace.txt b/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_005_plan_trace.txt new file mode 100644 index 00000000..d9e5a796 --- /dev/null +++ b/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_005_plan_trace.txt @@ -0,0 +1,49 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "customers.customer_id", + "alias": "customer_id" + } + ], + "relations": [ + "orders_to_customers" + ], + "aggregations": [ + { + "field": "customer_id", + "agg": "count_distinct", + "alias": "unique_customers" + } + ], + "filters": { + "type": "comparison", + "entity": "orders", + "field": "order_id", + "op": "is_not_null" + }, + "group_by": [] + }, + "max_tokens": 1000 + } + ], + "adr_queries": [], + "constraints": [], + "entities": [], + "dtos": [], + "normalization_notes": [ + "{\"provider\": \"demo_qa\", \"selectors_validate_before\": \"error\", \"selectors_validate_after\": \"error\", \"selectors_normalization_decision\": \"use_normalized_unvalidated\", \"selectors_before\": {\"op\": \"query\", \"root_entity\": \"customers\", \"select\": [{\"expr\": \"customers.customer_id\", \"alias\": \"customer_id\"}], \"relations\": [\"orders_to_customers\"], \"aggregations\": [{\"field\": \"customer_id\", \"agg\": \"count_distinct\", \"alias\": \"unique_customers\"}], \"filters\": {\"type\": \"comparison\", \"entity\": \"orders\", \"field\": \"order_id\", \"op\": \"is_not_null\"}}, \"selectors_after\": {\"op\": \"query\", \"root_entity\": \"customers\", \"select\": [{\"expr\": \"customers.customer_id\", \"alias\": \"customer_id\"}], \"relations\": [\"orders_to_customers\"], \"aggregations\": [{\"field\": \"customer_id\", \"agg\": \"count_distinct\", \"alias\": \"unique_customers\"}], \"filters\": {\"type\": \"comparison\", \"entity\": \"orders\", \"field\": \"order_id\", \"op\": \"is_not_null\"}, \"group_by\": []}}" + ] + } +} diff --git a/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_035_plan_trace.txt b/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_035_plan_trace.txt new file mode 100644 index 00000000..ac3ab166 --- /dev/null +++ b/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_035_plan_trace.txt @@ -0,0 +1,38 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "aggregations": [ + { + "field": "order_id", + "agg": "count" + } + ], + "filters": { + "type": "comparison", + "field": "order_date", + "op": "between", + "value": [ + "2022-03-01", + "2022-03-31" + ] + } + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} diff --git a/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_036_plan_trace.txt b/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_036_plan_trace.txt new file mode 100644 index 00000000..ac3ab166 --- /dev/null +++ b/tests/fixtures/regressions_known_bad/fetchgraph_plans/agg_036_plan_trace.txt @@ -0,0 +1,38 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "aggregations": [ + { + "field": "order_id", + "agg": "count" + } + ], + "filters": { + "type": "comparison", + "field": "order_date", + "op": "between", + "value": [ + "2022-03-01", + "2022-03-31" + ] + } + }, + "max_tokens": 2000 + } + ], + "adr_queries": null, + "constraints": null, + "entities": [], + "dtos": [] + } +} diff --git a/tests/fixtures/regressions_known_bad/fetchgraph_plans/geo_001_plan_trace.txt b/tests/fixtures/regressions_known_bad/fetchgraph_plans/geo_001_plan_trace.txt new file mode 100644 index 00000000..55373c32 --- /dev/null +++ b/tests/fixtures/regressions_known_bad/fetchgraph_plans/geo_001_plan_trace.txt @@ -0,0 +1,55 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "count(order_id)", + "alias": "order_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "customers", + "field": "city", + "op": "=", + "value": "San Antonio" + }, + { + "type": "comparison", + "field": "order_date", + "op": "starts_with", + "value": "2022-03" + } + ] + }, + "relations": [ + "orders_to_customers" + ], + "case_sensitivity": false + }, + "max_tokens": 500 + } + ], + "adr_queries": [], + "constraints": [], + "entities": [], + "dtos": [], + "normalization_notes": [ + "{\"provider\": \"demo_qa\", \"selectors_validate_before\": \"ok\", \"selectors_validate_after\": \"ok\", \"selectors_normalization_decision\": \"keep_original_valid\"}" + ] + } +} diff --git a/tests/fixtures/regressions_known_bad/fetchgraph_plans/items_002_plan_trace.txt b/tests/fixtures/regressions_known_bad/fetchgraph_plans/items_002_plan_trace.txt new file mode 100644 index 00000000..711aae8c --- /dev/null +++ b/tests/fixtures/regressions_known_bad/fetchgraph_plans/items_002_plan_trace.txt @@ -0,0 +1,54 @@ + + +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "group_by": [ + { + "field": "order_id", + "alias": "order_id" + } + ], + "aggregations": [ + { + "field": "order_item_id", + "agg": "count", + "alias": "item_count" + } + ], + "filters": { + "type": "logical", + "op": "and", + "clauses": [ + { + "type": "comparison", + "entity": "order_items", + "field": "order_id", + "op": "is_not_null" + } + ] + }, + "case_sensitivity": false + }, + "max_tokens": 2000 + } + ], + "adr_queries": [], + "constraints": [], + "entities": [], + "dtos": [], + "normalization_notes": [ + "{\"provider\": \"demo_qa\", \"selectors_validate_before\": \"error\", \"selectors_validate_after\": \"error\", \"selectors_normalization_decision\": \"keep_original_still_invalid\", \"selectors_before\": {\"op\": \"query\", \"root_entity\": \"order_items\", \"group_by\": [{\"field\": \"order_id\", \"alias\": \"order_id\"}], \"aggregations\": [{\"field\": \"order_item_id\", \"agg\": \"count\", \"alias\": \"item_count\"}], \"filters\": {\"type\": \"logical\", \"op\": \"and\", \"clauses\": [{\"type\": \"comparison\", \"entity\": \"order_items\", \"field\": \"order_id\", \"op\": \"is_not_null\"}]}, \"case_sensitivity\": false}, \"selectors_after\": {\"op\": \"query\", \"root_entity\": \"order_items\", \"group_by\": [{\"field\": \"order_id\", \"alias\": \"order_id\"}], \"aggregations\": [{\"field\": \"order_item_id\", \"agg\": \"count\", \"alias\": \"item_count\"}], \"filters\": {\"type\": \"logical\", \"op\": \"and\", \"clauses\": [{\"type\": \"comparison\", \"entity\": \"order_items\", \"field\": \"order_id\", \"op\": \"is_not_null\"}]}, \"case_sensitivity\": false}}" + ] + } +} diff --git a/tests/fixtures/regressions_known_bad/fetchgraph_plans/qa_001_plan_trace.txt b/tests/fixtures/regressions_known_bad/fetchgraph_plans/qa_001_plan_trace.txt new file mode 100644 index 00000000..033a172e --- /dev/null +++ b/tests/fixtures/regressions_known_bad/fetchgraph_plans/qa_001_plan_trace.txt @@ -0,0 +1,134 @@ +{ + "stage": "before_normalize", + "plan": { + "required_context": [ + "demo_qa" + ], + "context_plan": [ + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "customers", + "select": [ + { + "expr": "city", + "alias": "city" + }, + { + "expr": "segment", + "alias": "segment" + }, + { + "expr": "signup_date", + "alias": "signup_date" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 42 + }, + "relations": [ + "orders_to_customers" + ], + "group_by": [ + { + "field": "customer_id", + "alias": "customer_id" + } + ], + "aggregations": [ + { + "field": "order_id", + "agg": "count", + "alias": "order_count" + }, + { + "field": "order_total", + "agg": "sum", + "alias": "total_spent" + } + ], + "limit": 1 + }, + "max_tokens": null + }, + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "orders", + "select": [ + { + "expr": "order_date", + "alias": "last_order_date" + }, + { + "expr": "order_status", + "alias": "last_order_status" + }, + { + "expr": "order_channel", + "alias": "last_order_channel" + } + ], + "filters": { + "type": "comparison", + "field": "customer_id", + "op": "=", + "value": 42 + }, + "limit": 1, + "order_by": [ + { + "field": "order_date", + "direction": "desc" + } + ] + }, + "max_tokens": null + }, + { + "provider": "demo_qa", + "mode": "slice", + "selectors": { + "op": "query", + "root_entity": "order_items", + "select": [ + { + "expr": "line_total", + "alias": "line_total" + } + ], + "filters": { + "type": "comparison", + "field": "order_id", + "op": "in", + "value": "(SELECT order_id FROM orders WHERE customer_id = 42)" + }, + "limit": 5, + "order_by": [ + { + "field": "line_total", + "direction": "desc" + } + ] + }, + "max_tokens": null + } + ], + "adr_queries": [], + "constraints": [], + "entities": [], + "dtos": [], + "normalization_notes": [ + "{\"provider\": \"demo_qa\", \"selectors_validate_before\": \"ok\", \"selectors_validate_after\": \"ok\", \"selectors_normalization_decision\": \"keep_original_valid\"}", + "{\"provider\": \"demo_qa\", \"selectors_validate_before\": \"ok\", \"selectors_validate_after\": \"ok\", \"selectors_normalization_decision\": \"keep_original_valid\"}", + "{\"provider\": \"demo_qa\", \"selectors_validate_before\": \"ok\", \"selectors_validate_after\": \"ok\", \"selectors_normalization_decision\": \"keep_original_valid\"}" + ] + } +} diff --git a/tests/test_context_merge.py b/tests/test_context_merge.py new file mode 100644 index 00000000..4535a364 --- /dev/null +++ b/tests/test_context_merge.py @@ -0,0 +1,73 @@ +from fetchgraph.core.context import BaseGraphAgent, ContextPacker +from fetchgraph.core.models import BaselineSpec, ContextFetchSpec, Plan + + +def _make_agent(baseline): + packer = ContextPacker(max_tokens=10, summarizer_llm=lambda text: text) + return BaseGraphAgent( + llm_plan=None, + llm_synth=lambda feature_name, ctx, plan: "", + domain_parser=lambda raw: raw, + saver=lambda name, obj: None, + providers={}, + verifiers=[], + packer=packer, + baseline=baseline, + ) + + +def _get_spec(specs, provider): + return next(spec for spec in specs if spec.provider == provider) + + +def test_merge_baseline_preserved_when_context_plan_missing(): + baseline_spec = ContextFetchSpec( + provider="X", selectors={"a": 1}, mode="filter" + ) + agent = _make_agent([BaselineSpec(spec=baseline_spec)]) + plan = Plan(required_context=["X"]) + + merged = agent._merge_baseline_with_plan(plan) + + merged_spec = _get_spec(merged, "X") + assert merged_spec.model_dump() == baseline_spec.model_dump() + + +def test_merge_baseline_preserved_when_context_plan_empty(): + baseline_spec = ContextFetchSpec( + provider="X", selectors={"a": 1}, mode="filter" + ) + agent = _make_agent([BaselineSpec(spec=baseline_spec)]) + plan = Plan(required_context=["X"], context_plan=[]) + + merged = agent._merge_baseline_with_plan(plan) + + merged_spec = _get_spec(merged, "X") + assert merged_spec.model_dump() == baseline_spec.model_dump() + + +def test_merge_required_context_materializes_without_baseline(): + agent = _make_agent(baseline=[]) + plan = Plan(required_context=["X"]) + + merged = agent._merge_baseline_with_plan(plan) + + merged_spec = _get_spec(merged, "X") + assert merged_spec.provider == "X" + assert merged_spec.mode == "full" + assert merged_spec.selectors in ({}, None) + assert getattr(merged_spec, "max_tokens", None) is None + + +def test_required_context_materializes_even_when_context_plan_non_empty(): + agent = _make_agent(baseline=[]) + plan = Plan( + required_context=["X"], + context_plan=[ContextFetchSpec(provider="A", mode="full")], + ) + + merged = agent._merge_baseline_with_plan(plan) + providers = {spec.provider for spec in merged} + + assert "A" in providers + assert "X" in providers diff --git a/tests/test_relational_normalizer_regression.py b/tests/test_relational_normalizer_regression.py new file mode 100644 index 00000000..cec371ee --- /dev/null +++ b/tests/test_relational_normalizer_regression.py @@ -0,0 +1,328 @@ +from __future__ import annotations + +import copy +import json +import re +import zipfile +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Dict, Iterable, List, Optional, Set + +import pytest +from pydantic import TypeAdapter, ValidationError + +from fetchgraph.core.models import ContextFetchSpec, ProviderInfo +from fetchgraph.planning.normalize import ( + PlanNormalizer, + PlanNormalizerOptions, +) +from fetchgraph.planning.normalize.plan_normalizer import SelectorNormalizationRule +from fetchgraph.relational.models import RelationalRequest +from fetchgraph.relational.normalize import normalize_relational_selectors + +# ----------------------------- +# Plan-trace parsing +# ----------------------------- + +_JSON_SPLIT_RE = re.compile(r"\n\s*\n", re.MULTILINE) + + +def _iter_json_objects_from_trace_text(text: str) -> Iterable[Dict[str, Any]]: + parts = [p.strip() for p in _JSON_SPLIT_RE.split(text) if p.strip()] + for part in parts: + try: + obj = json.loads(part) + except json.JSONDecodeError: + continue + if isinstance(obj, dict): + yield obj + + +def _find_fixtures_dir() -> Optional[Path]: + """ + Ищем папку `fixtures` вверх по дереву от текущего test-файла. + Это устойчиво к вложенности tests/... + """ + here = Path(__file__).resolve() + for parent in here.parents: + cand = parent / "fixtures" + if cand.exists(): + return cand + return None + + +@dataclass(frozen=True) +class TraceCase: + trace_name: str + spec_idx: int + provider: str + mode: str + selectors: Dict[str, Any] + bucket: str + + @property + def case_id(self) -> str: + # Важно: не использовать '::' — VSCode/pytest UI строят дерево по этому разделителю. + return f"{self.bucket} | {self.trace_name} | spec[{self.spec_idx}] | {self.provider}" + + +def _load_trace_cases_from_fixtures() -> List[TraceCase]: + """ + Ищет по бакетам: + - fixtures/regressions_fixed/fetchgraph_plans.zip + - fixtures/regressions_fixed/fetchgraph_plans/*.txt + - fixtures/regressions_known_bad/fetchgraph_plans.zip + - fixtures/regressions_known_bad/fetchgraph_plans/*.txt + + Достаёт спецификации из stage=before_normalize (plan.context_plan[*]). + """ + fixtures_dir = _find_fixtures_dir() + if fixtures_dir is None: + pytest.skip("No fixtures dir found (expected .../fixtures).", allow_module_level=True) + return [] + + cases: List[TraceCase] = [] + buckets = ["regressions_fixed", "regressions_known_bad"] + for bucket in buckets: + zip_path = fixtures_dir / bucket / "fetchgraph_plans.zip" + dir_path = fixtures_dir / bucket / "fetchgraph_plans" + + if zip_path.exists(): + with zipfile.ZipFile(zip_path) as zf: + for name in sorted(zf.namelist()): + if not name.endswith("_plan_trace.txt"): + continue + text = zf.read(name).decode("utf-8", errors="replace") + cases.extend(_extract_before_specs(trace_name=name, text=text, bucket=bucket)) + continue + + if dir_path.exists(): + for p in sorted(dir_path.glob("*_plan_trace.txt")): + text = p.read_text(encoding="utf-8", errors="replace") + cases.extend(_extract_before_specs(trace_name=p.name, text=text, bucket=bucket)) + + legacy_zip = fixtures_dir / "fetchgraph_plans.zip" + legacy_dir = fixtures_dir / "fetchgraph_plans" + if legacy_zip.exists(): + with zipfile.ZipFile(legacy_zip) as zf: + for name in sorted(zf.namelist()): + if not name.endswith("_plan_trace.txt"): + continue + text = zf.read(name).decode("utf-8", errors="replace") + cases.extend(_extract_before_specs(trace_name=name, text=text, bucket="regressions_fixed")) + if legacy_dir.exists(): + for p in sorted(legacy_dir.glob("*_plan_trace.txt")): + text = p.read_text(encoding="utf-8", errors="replace") + cases.extend(_extract_before_specs(trace_name=p.name, text=text, bucket="regressions_fixed")) + + if not cases: + pytest.skip( + "No plan fixtures found. Put fetchgraph_plans.zip into fixtures/regressions_fixed " + "or fixtures/regressions_known_bad, or unpack it to " + "fixtures/regressions_fixed/fetchgraph_plans or fixtures/regressions_known_bad/fetchgraph_plans.", + allow_module_level=True, + ) + return cases + + +def _extract_before_specs(trace_name: str, text: str, *, bucket: str) -> List[TraceCase]: + before_objs = [ + obj for obj in _iter_json_objects_from_trace_text(text) + if obj.get("stage") == "before_normalize" + ] + out: List[TraceCase] = [] + for obj in before_objs: + plan = obj.get("plan") or {} + context_plan = plan.get("context_plan") or [] + if not isinstance(context_plan, list): + continue + + for idx, item in enumerate(context_plan): + if not isinstance(item, dict): + continue + provider = item.get("provider") + mode = item.get("mode") or "full" + selectors = item.get("selectors") + if not isinstance(provider, str) or not isinstance(selectors, dict): + continue + out.append( + TraceCase( + trace_name=trace_name, + spec_idx=idx, + provider=provider, + mode=str(mode), + selectors=selectors, + bucket=bucket, + ) + ) + return out + + +# ----------------------------- +# Normalizer builder (for tests) +# ----------------------------- + + +def _build_plan_normalizer(providers: Set[str]) -> PlanNormalizer: + """ + Строим PlanNormalizer, который умеет нормализовать selectors для заданных providers + по тому же контракту, что и в проде: validate -> normalize -> validate. + """ + provider_catalog: Dict[str, ProviderInfo] = { + name: ProviderInfo(name=name, capabilities=[]) for name in sorted(providers) + } + + relational_rule = SelectorNormalizationRule( + validator=TypeAdapter(RelationalRequest), + normalize_selectors=normalize_relational_selectors, + ) + + normalizer_registry: Dict[str, SelectorNormalizationRule] = { + name: relational_rule for name in sorted(providers) + } + + # В тесте schema-фильтрацию лучше выключить: это отдельная ответственность + # (и она может зависеть от selectors_schema в ProviderInfo, которого тут нет). + opts = PlanNormalizerOptions(filter_selectors_by_schema=False) + + return PlanNormalizer( + provider_catalog, + normalizer_registry=normalizer_registry, + options=opts, + ) + + +def _validate(adapter: TypeAdapter[Any], selectors: Any) -> bool: + try: + adapter.validate_python(selectors) + except ValidationError: + return False + return True + + +def _parse_note(note: str) -> Dict[str, Any]: + # notes в PlanNormalizer — это json строка + try: + obj = json.loads(note) + except Exception: + return {"raw": note} + return obj if isinstance(obj, dict) else {"raw": note} + + +# ----------------------------- +# Tests (contract-driven) +# ----------------------------- + +CASES = _load_trace_cases_from_fixtures() + +# 1) Контрактный тест запускаем ТОЛЬКО на regressions_fixed +CASES_FIXED = [c for c in CASES if c.bucket == "regressions_fixed"] + +# 2) Для общего набора — автоматически проставляем marks по bucket +CASES_ALL = [ + pytest.param( + c, + id=c.case_id, + marks=(pytest.mark.known_bad,) if c.bucket == "regressions_known_bad" else (), + ) + for c in CASES +] + +NORMALIZER = _build_plan_normalizer({c.provider for c in CASES}) if CASES else None + + +@pytest.mark.parametrize("case", CASES_FIXED, ids=lambda c: c.case_id) +def test_plan_normalizer_contract_never_regresses_valid_inputs(case: TraceCase) -> None: + """ + Контракт PlanNormalizer.normalize_specs(): + - если selectors валидны ДО -> после normalize_specs + они должны остаться валидными и НЕ измениться. + """ + assert NORMALIZER is not None + + rule = NORMALIZER.normalizer_registry.get(case.provider) + assert rule is not None, f"No normalizer rule registered for provider={case.provider!r}" + + orig_selectors = copy.deepcopy(case.selectors) + spec = ContextFetchSpec(provider=case.provider, mode=case.mode, selectors=copy.deepcopy(case.selectors)) + + before_ok = _validate(rule.validator, spec.selectors) + + notes: List[str] = [] + out_specs = NORMALIZER.normalize_specs([spec], notes=notes) + assert len(out_specs) == 1 + out = out_specs[0] + + after_ok = _validate(rule.validator, out.selectors) + + assert not (before_ok and not after_ok), ( + f"{case.case_id}: regression: selectors were valid before normalization " + f"but invalid after.\n" + f"Note: {_parse_note(notes[-1]) if notes else 'no_notes'}\n" + f"Selectors(before): {json.dumps(spec.selectors, ensure_ascii=False)[:2000]}\n" + f"Selectors(after): {json.dumps(out.selectors, ensure_ascii=False)[:2000]}" + ) + + if before_ok: + assert out.selectors == spec.selectors, ( + f"{case.case_id}: valid selectors must not be changed by normalize_specs.\n" + f"Note: {_parse_note(notes[-1]) if notes else 'no_notes'}\n" + f"Selectors(before): {json.dumps(spec.selectors, ensure_ascii=False)[:2000]}\n" + f"Selectors(after): {json.dumps(out.selectors, ensure_ascii=False)[:2000]}" + ) + + assert spec.selectors == orig_selectors, ( + f"{case.case_id}: normalize_specs must not mutate input selectors in-place." + ) + + +@pytest.mark.parametrize("case", CASES_ALL) +def test_regression_fixtures_invalid_inputs_are_fixed_by_plan_normalizer(case: TraceCase) -> None: + """ + Если ДО selectors невалидны -> ПОСЛЕ normalize_specs они должны стать валидными. + + Важно: known_bad здесь будут (пока) красными — и это ок. + В CI они исключаются через -m "not known_bad". + """ + assert NORMALIZER is not None + + rule = NORMALIZER.normalizer_registry.get(case.provider) + assert rule is not None, f"No normalizer rule registered for provider={case.provider!r}" + + spec = ContextFetchSpec(provider=case.provider, mode=case.mode, selectors=copy.deepcopy(case.selectors)) + + before_ok = _validate(rule.validator, spec.selectors) + if before_ok: + return + + notes: List[str] = [] + out_specs = NORMALIZER.normalize_specs([spec], notes=notes) + out = out_specs[0] + + after_ok = _validate(rule.validator, out.selectors) + if after_ok: + return + + err_before: Optional[list] = None + err_after: Optional[list] = None + + try: + rule.validator.validate_python(spec.selectors) + except ValidationError as e: + err_before = e.errors() + + try: + rule.validator.validate_python(out.selectors) + except ValidationError as e: + err_after = e.errors() + + pytest.fail( + f"{case.case_id}: expected PlanNormalizer to fix invalid selectors (error -> ok), " + f"but still invalid after normalization.\n" + f"Note: {_parse_note(notes[-1]) if notes else 'no_notes'}\n" + f"Errors(before): {err_before}\n" + f"Errors(after): {err_after}\n" + f"Selectors(before): {json.dumps(spec.selectors, ensure_ascii=False)[:2000]}\n" + f"Selectors(after): {json.dumps(out.selectors, ensure_ascii=False)[:2000]}" + ) +