diff --git a/app/api/admin.py b/app/api/admin.py index 0514f51..947a712 100644 --- a/app/api/admin.py +++ b/app/api/admin.py @@ -242,6 +242,16 @@ _KNOWN_FIELDS: dict[str, dict[str, dict]] = { "or sync rejected. 0 disables the gate. Default 10737418240 = 10 GiB." ), }, + "bq_max_scan_bytes": { + "kind": "int", + "default": 5368709120, + "hint": ( + "Cost guardrail for `da query --remote` against query_mode='remote' " + "BQ rows (dry-run check on the underlying SELECT before execute). " + "Bytes processed; exceeds → 400 remote_scan_too_large with a " + "`da fetch` suggestion. 0 disables the gate. Default 5368709120 = 5 GiB." + ), + }, }, }, "keboola": { @@ -795,6 +805,7 @@ class ServerConfigUpdateRequest(BaseModel): _BQ_OPTIONAL_FIELD_DEFAULTS: Dict[str, Any] = { "billing_project": "", "max_bytes_per_materialize": 10737418240, + "bq_max_scan_bytes": 5368709120, } diff --git a/app/api/query.py b/app/api/query.py index 7c56016..ce80abd 100644 --- a/app/api/query.py +++ b/app/api/query.py @@ -47,9 +47,10 @@ BQ_PATH = re.compile( def _default_remote_query_cap_bytes() -> int: """5 GiB default cap on /api/query BQ-touching scans. Configurable via - `api.query.bq_max_scan_bytes` in /admin/server-config. + `data_source.bigquery.bq_max_scan_bytes` in /admin/server-config — + sits next to `max_bytes_per_materialize` for visual symmetry. """ - raw = get_value("api", "query", "bq_max_scan_bytes", default=5_368_709_120) + raw = get_value("data_source", "bigquery", "bq_max_scan_bytes", default=5_368_709_120) try: return int(raw) if raw is not None else 5_368_709_120 except (TypeError, ValueError):