Spice v2.4.0-rc.2 (Oct 15, 2026)
Spice v2.4.0-rc.2 is now available! ๐ฅ
Spice v2.4.0-rc.2 is the second release candidate of v2.4.0 for early testing and feedback. It introduces a new OpenAI-compatible POST /v1/decisions API backed by an OpenAI decision model, TypeSafe Jev, or any other LLM in the Spicepod that can answer decisions. Five new SQL functions bring the same AI classification, scoring, and decisions into SQL.
This release also adds Iceberg reads without a catalog and improves acceleration snapshots. Cayenne gains runtime-wide adaptive tuning and applies acceleration configuration changes on restart.
Highlights in this release:
- AI Decisions API and decisions in SQL: An OpenAI-compatible
/v1/decisionsAPI, plus five SQL functions for filtering, classifying, and scoring data with models. - Iceberg without a catalog: Read a table directly from its root directory or pin a metadata file to read a fixed version.
- Shared runtime state: Startup validation and a common location for cluster state, rate control, cache warmup, and acceleration snapshots.
- SQL results cache: Cache entries expire by TTL and remain available across data refreshes.
- Cayenne acceleration: Improvements to primary-key loading, secondary indexes, and configuration updates.
- OpenTelemetry log export: Send runtime logs to any OTLP endpoint as structured log records, and choose which failed queries are logged.
These notes cover changes since v2.4.0-rc.1. Review Breaking Changes before upgrading; upgrades from earlier versions also require the rc.1 migration guidance.
What's New in v2.4.0-rc.2โ
AI Decisions API and decisions in SQLโ
Spice now supports POST /v1/decisions, which is compatible with the OpenAI Decisions API. A decision request asks typed questions about an input. Each answer comes back with its probabilities and a confidence.
Any model in the Spicepod can answer a decision request:
| Model | Example from | Probabilities |
|---|---|---|
| OpenAI decision model | openai:gpt-6-luna | The estimates of the model. |
| TypeSafe decision model | typesafe:jev | Calibrated by the model. |
| Any other LLM | openai:gpt-4o-mini, anthropic:claude-haiku-4-5 | The estimates of the chat model. |
OpenAI decision models use the native OpenAI Decisions API. gpt-6-luna also supports chat and /v1/nsql. TypeSafe Jev returns calibrated probabilities and answers decisions only. Other LLMs answer through chat completions and return their own uncalibrated estimates.
models:
- from: openai:gpt-6-luna
name: luna
params:
openai_api_key: ${secrets:OPENAI_API_KEY}
- from: typesafe:jev
name: jev
params:
typesafe_api_key: ${secrets:TYPESAFE_API_KEY}
Five new SQL functions make the same decisions available in queries:
| Function | Result |
|---|---|
ai_if(input, condition) | BOOLEAN: true when the probability of "yes" exceeds 0.5. |
ai_probability(input, condition) | DOUBLE: a probability from 0 to 1. |
ai_classify(input, labels) | VARCHAR: one of the supplied labels. |
ai_score(input, instructions, levels) | DOUBLE: a probability-weighted score. |
ai_decide(input, questions) | STRUCT: answers, probabilities, and confidence for a set of questions. |
SELECT
id,
ai_classify(body, ['billing', 'technical', 'account'], model => 'support_model' ) AS team,
ai_probability(body, 'The customer is requesting a refund', model => 'support_model') AS refund_probability
FROM tickets
WHERE status = 'open';
See AI functions for more examples.
Iceberg Without a Catalogโ
Read an Iceberg table directly from object storage or the local filesystem, without configuring a catalog. Set from to the table root using file://, s3://, s3a://, gs://, or gcs://:
datasets:
- from: iceberg:s3://my-bucket/warehouse/db/taxis
name: taxis
params:
iceberg_s3_region: us-east-1
Spice resolves the metadata file on each query and refresh. It supports metadata/version-hint.text as well as a fixed version (a path relative to the table root or a full URL):
datasets:
- from: iceberg:s3://my-bucket/warehouse/db/taxis
name: taxis
params:
iceberg_s3_region: us-east-1
iceberg_metadata_path: /metadata/00003-8f2c.metadata.json
Fixed tables are read-only. The earlier metadata_path parameter remains supported with a deprecation warning; see Breaking Changes.
Shared Runtime Stateโ
runtime.state provides a shared, object-store location for cluster state, rate control, SQL results-cache warmup, and acceleration snapshots. Each feature uses its own subdirectory within the provided location.
Acceleration snapshots now default to the snapshots/ subdirectory when runtime.state is configured.
runtime:
state:
location: s3://my-bucket/spice/
datasets:
- from: postgres:orders
name: orders
acceleration:
enabled: true
engine: cayenne
mode: file
snapshots: enabled
A dataset can override the snapshot location, its settings, and the bootstrap behavior on its own acceleration:
datasets:
- from: postgres:events
name: events
acceleration:
snapshots: enabled
snapshots_location: s3://archive-bucket/snapshots/
snapshots_params:
s3_region: eu-west-1
snapshots_bootstrap_on_failure_behavior: fallback
Other changes to shared state:
- Snapshot queues: An SQS queue that covers the whole
runtime.stateprefix no longer causes anERRORlog for each scheduler heartbeat. The snapshot reader now deletes messages for the other state folders without a log.
SQL Results Cacheโ
The SQL results cache now expires entries by TTL, independent of acceleration refreshes, CDC batches, and retention passes no longer invalidate cached results.
Review item_ttl and stale_while_revalidate_ttl when upgrading: a successful refresh no longer makes cached results reflect the refreshed data immediately. See Breaking Changes.
Cayenne Accelerationโ
Adaptive tuning is configured once for the runtime. Enable it with runtime.adaptive_tuning and set targets under runtime.params:
runtime:
adaptive_tuning: enabled
params:
target_freshness: 30s
Supported targets are target_replication_lag, target_freshness, target_query_latency, target_convergence_window, and target_qph. Adaptive tuning defaults to disabled. See Breaking Changes and the runtime YAML documentation.
Other Cayenne improvements include:
- Primary-key loading: Keyed tables build their primary-key filter during the initial load and bulk-load without per-row routing or a whole-table fold.
- Position deletes:
cayenne_deletion_mode: autocan select position deletes for small primary-key tables on local storage on Linux systems with at least eight physical cores. - Secondary indexes: Index runs are persisted, indexes remain complete across acceleration snapshots, and CDC maintains indexes for each operation type. Hash joins read each file once when narrowing a scan through an index.
- Partition handling: Cayenne rejects stored data with an incompatible
partition_by, protects keyed appends to partitioned tables during publication, and prepares every partition after a refresh. - Storage and query correctness: Cayenne reclaims snapshot directories superseded by a reload, corrects pruning for NaN values, and fixes deletion-index bounds and reload fencing.
- Snapshot storage growth: A writer with
snapshots_trigger: refresh_completekept one more copy of the table for each refresh. Each snapshot held file deletions, so Cayenne skipped each cleanup pass. Cayenne now runs the cleanup when a snapshot releases its hold. In a 10-minute test with a refresh every 60 seconds, each dataset kept 1 snapshot directory instead of 10. - Configuration changes on restart: A change to write settings only, such as
cayenne_sort_columnsorcayenne_compression_strategy, applies to the existing acceleration. A change toprimary_keyorpartition_byrebuilds the acceleration from the source only under specific conditions. See Cayenne Configuration Updates.
OpenTelemetry Log Exportโ
Spice can now send its logs to an OpenTelemetry Collector, or any OTLP endpoint, as structured OTLP log records. Logs use the same otel_exporter that already sends metrics. A new runtime.query.log_errors setting chooses which failed queries are logged.
runtime:
telemetry:
otel_exporter:
endpoint: otel-collector:4317
signals: [metrics, logs] # new; default [metrics]
query:
log_errors: execution # new; none (default) | execution | all
- Structured records: Each log line becomes an OTLP log record with its severity, the message as the body, typed fields as attributes, and the logging module as the instrumentation scope. Records share the resource attributes of exported metrics.
- Trace correlation: A record logged during a query carries the query's trace ID, the same ID returned in
spice-trace-idand stored inruntime.task_history. - Delivery: Records are batched on a dedicated export runtime, separate from query and HTTP traffic, and flushed at shutdown so the final error and
Goodbye!reach the endpoint. For OTLP/HTTP endpoints, logs are sent to<base>/v1/logs. - Cluster executors: Executors export their logs with the scheduler's telemetry settings, including headers resolved from the scheduler's secrets.
runtime.query.log_errors controls which failed queries are logged:
| Value | What is logged |
|---|---|
none (default) | Existing behavior: a query refused for memory at WARN, and every other failure at DEBUG |
execution | Also queries that failed while running, at WARN |
all | Also queries rejected before running (syntax and planning errors), at INFO |
Each record reads Query failed: <error>, with error_code and datasets fields and the query's trace ID. The SQL text is never logged.
Unknown-column errors are now reported with the correct error_code instead of InternalError, in logs, runtime.task_history, and the query_failures metric.
See OpenTelemetry Logs Export, Exporting logs, and runtime.query.log_errors.
Fixes and Improvementsโ
AI APIs and Modelsโ
- Responses API:
/v1/responsesexecutes Spice tools and honorstool_recursion_limitwhen streaming. It returns Spice tool calls asmcp_callitems inoutput, allowing clients that manage their own conversation history to replay them. - Model controls:
/v1/nsqlacceptsreasoning_effort, andrerank()uses evaluation models with a strategy selected for each query. - Anthropic: Streaming handles responses that begin with a thinking block, empty text blocks are dropped, and
anthropic_workspace_idis available as a model parameter. - OpenAI: Models with an unknown service tier can load and serve requests.
- Luna:
gpt-6-lunaand its snapshots support chat,/v1/nsql, and native decisions.
Accelerationโ
- Caching point lookups: Lookups on a
refresh_mode: cachingdataset failed with HTTP 400. This occurred when Cayenne accelerated the dataset, the primary key covered the request columns, and the table held two protected snapshots. The point-lookup plan did not combine the partitions of the Cayenne scan. Lookups now return the cached row or fetch it from the source.
Connectorsโ
- MySQL timestamps: Timestamp literals in queries that the runtime sends to MySQL now keep their fractional seconds.
Dependency Updatesโ
| Dependency | Update |
|---|---|
| Turso | v0.8.2 |
Breaking Changesโ
Shared State Directory Layout and Startup Checksโ
State written at the runtime.state root by rc.1 is no longer read from that location. Move existing state objects into the appropriate subdirectories before upgrading to retain them:
| State | Subdirectory |
|---|---|
| Cluster scheduler | cluster/ |
| Rate control | rate-control/ |
| SQL results-cache warmup | results-cache/ |
Azure locations (abfs:// and abfss://) need one more step. In rc.1, the runtime ignored the path in an Azure URL and wrote state at the container root. For example, with abfs://container/spice/, rc.1 wrote cluster.json at the container root. This release writes spice/cluster/cluster.json. Move Azure state from the container root into the configured path and then into the feature subdirectory.
An explicit runtime.scheduler.state_location retains its earlier layout. Without migration, Spice starts without the state previously stored at the shared root.
The configured store must accept writes and conditional writes. Spice does not become ready until startup validation succeeds and refuses stores with a newer state format. Check storage permissions and compatibility before upgrading.
SQL Results Cache Freshnessโ
A refresh no longer invalidates SQL results-cache entries. Queries can return data from before the latest refresh until item_ttl expires, plus stale_while_revalidate_ttl when configured. Reduce item_ttl if results need to follow source refreshes more closely.
Cayenne Tuning Configurationโ
Replace the Cayenne tuning parameters with runtime settings that apply across datasets and catalogs:
| Previous parameter | Replacement |
|---|---|
cayenne_tuning: adaptive | runtime.adaptive_tuning: enabled |
cayenne_tuning: auto | runtime.adaptive_tuning: disabled |
cayenne_goal_replication_lag | runtime.params.target_replication_lag |
cayenne_goal_freshness | runtime.params.target_freshness |
cayenne_goal_query_latency | runtime.params.target_query_latency |
cayenne_goal_convergence_window | runtime.params.target_convergence_window |
cayenne_goal_qph | runtime.params.target_qph |
runtime.adaptive_tuning accepts only enabled or disabled. Other values, including true, fail the Spicepod load.
Pinned Iceberg Tablesโ
Replace the deprecated metadata_path parameter with iceberg_metadata_path. The two settings resolve paths differently. metadata_path uses its value as given. iceberg_metadata_path resolves a value without a URL scheme relative to the table root in from. Convert an absolute local path to a full file:// URL or to a path relative to the table root.
Datasets pinned to a .json metadata file are read-only and fail to load with access: read_write. Remove that setting from pinned datasets before upgrading.
Cayenne Configuration Updatesโ
A restart now applies changed settings to an existing Cayenne acceleration. The result depends on the setting and the dataset:
- Write settings only: A change to only
cayenne_sort_columns,cayenne_cluster_by,cayenne_compression_strategy,cayenne_delta_encoding, orcayenne_shard_key_columnsapplies to the existing acceleration. Stored rows keep their layout until a refresh or compaction rewrites them. - Identity settings: A change to
primary_key,partition_by,cayenne_pk_conflict_detectionfromnonetoauto, or the data location rebuilds the acceleration from the source. The runtime rebuilds only a dataset withrefresh_mode: full,mode: fileorfile_update, andwrite_mode: write_through. The source must not besink:, and must be readable with the schema of the dataset. - All other datasets: The acceleration keeps all of its stored settings. This includes write settings that changed in the same restart. The runtime logs a warning that names the change and the fix.
While the runtime cannot read the source, a dataset that qualifies for a rebuild keeps its existing acceleration. A partition_by change or a conflict-detection change cannot use the stored rows, so it fails the dataset instead. Revert the setting, or restart when the source is readable.
A restart alone does not migrate a dataset that does not meet these conditions. Read the startup warning for the dataset before you delete stored data. Allow time for a rebuild when the conditions apply.
Upgradingโ
Once release artifacts are available, select v2.4.0-rc.2 explicitly with the CLI, Docker tag, or Helm chart version.
CLIโ
spice upgrade v2.4.0-rc.2
Dockerโ
docker pull spiceai/spiceai:2.4.0-rc.2
See Docker Hub for available tags.
Helmโ
helm repo update
helm upgrade spiceai spiceai/spiceai --version 2.4.0-rc.2
Homebrew and AWS Marketplaceโ
Homebrew and AWS Marketplace follow their published versions. To select this release candidate, use an explicit version through the CLI or Docker.
Spice is also available in the AWS Marketplace.
Contributorsโ
Changelogโ
See the full changelog from v2.4.0-rc.1 to v2.4.0-rc.2.
- feat(connector-huggingface): Hugging Face datasets data connector (
hf://datasets/...) by @lukekim in #14877 - fix(iceberg): Iceberg REST clients read the real table or get an error, never an empty one by @lukekim in #14588
- fix(federation): ask the executor for the SELECT 1 placeholder of an empty projection by @krinart in #14851
- fix(cayenne): float statistics must not leave NaN out of pruning or metadata answers (fixes #14719) by @claudespice in #14792
- fix: Update tpch benchmark snapshots for accelerated/s3[parquet]-duckdb[file]-2gib.yaml by @github-actions in #14850
- Update openapi.json by @github-actions in #14858
- test: strengthen assertions and enforce sign-off coverage by @lukekim in #14740
- Reapply "fix(sqlite, duckdb): keep a decimal AVG, and on SQLite a decimal SUM, out of the federated plan (fixes #14492)" by @krinart in #14888
- fix(caching): a GET and a POST to one HTTP path no longer share a cache entry (fixes #14768) by @claudespice in #14884
- fix(anthropic): drop empty text blocks from assistant messages by @Jeadie in #14834
- fix(cayenne): ask the table whether it takes a versioned append, instead of predicting it by @lukekim in #14882
- test(sqlite): guard the Date32 literal cast through the SQLite acceleration's own scan (fixes #14491) by @grokspice in #14703
- fix(cayenne): read each file once when a hash join narrows an indexed table's scan by @lukekim in #14934
- fix(sharepoint): list drive items when the listing contains a folder (fixes #2797) by @phillipleblanc in #14946
- fix(runtime): log each failing dataset's load failure (fixes #14918) by @phillipleblanc in #14939
- fix(deps): move the DataFusion pin past spiceai/datafusion#256, so FlightSQL Substrait plans read string columns (fixes #14935) by @lukekim in #14944
- fix(cayenne): publish a keyed partition's append as a protected overlay (fixes #14947) by @lukekim in #14955
- fix(acceleration): a failed acceleration build no longer keeps the dataset down until restart (fixes #14917) by @phillipleblanc in #14942
- fix(postgres): reject a changes dataset without a primary key when it loads by @phillipleblanc in #14960
- feat(spicepod): publish pull request reviews by @lukekim in #14964
- fix(ci): bound the REPL expect-script waits on silence, not total response time (fixes #13711) by @grokspice in #14963
- fix(cluster): treat secrets the scheduler declines as not found on executors by @phillipleblanc in #14957
- fix(flight): return query and data errors as InvalidArgument, not Internal by @phillipleblanc in #14956
- fix(duckdb,sqlite): correct pushdown for string_agg ORDER BY, concat NULLs, and unsupported fns by @lukekim in #14798
- fix(ci): provision DuckLake for the ducklake[catalog] schema test, which has never passed by @grokspice in #14952
- fix(llms): stream Anthropic responses that open with a thinking block (fixes #14909) by @krinart in #14920
- fix(arrow): serve lookups from enabled indexes; a repeated key disables the index with a warning by @sgrebnov in #14968
- feat(nsql): accept reasoning_effort on POST /v1/nsql by @lukekim in #14852
- fix(listing): scan file_extension '*' tables through ListingTable, so Glue joins broadcast again (fixes #14890) by @krinart in #14972
- fix(llms): load and serve an OpenAI model when a reply names an unknown service tier (fixes #14916) by @krinart in #14927
- feat(cayenne): always persist secondary index runs by @sgrebnov in #14979
- fix(cache): expire results-cache entries in insertion order instead of walking every LRU list by @bjchambers in #14919
- feat: decisions in SQL (ai_if, ai_probability, ai_classify, ai_score, ai_decide) and an OpenAI-compatible /v1/decisions by @lukekim in #14838
- fix(rrf): keep named arguments on nested search calls by @phillipleblanc in #14975
- fix(rate-control): hold instances that set different limits for one origin to the lowest (fixes #14913) by @krinart in #14932
- fix(vortex): keep temporal casts Vortex can't evaluate out of the scan by @sgrebnov in #14985
- fix(acceleration): recommend mode: file for CDC on_conflict migrations to Cayenne by @bjchambers in #14928
- test(huggingface): unblock the merge queue: read imdb's parquet conversion through
@~parquetand fail fast on a vanished Hub pin by @grokspice in #14998 - test(cayenne): link the integration tests into one test binary by @bjchambers in #14976
- test(vortex): compile the integration tests into a binary the sign-off gate runs by @bjchambers in #14987
- fix(http): reject a request_path that URL parsing would rewrite by @bjchambers in #14965
- fix(clickhouse): load LowCardinality, DateTime64, Array, Map, Tuple, Enum, 128-bit integer and IP columns by @phillipleblanc in #14953
- Add anthropic_workspace_id param for Anthropic models by @Jeadie in #14829
- fix(acceleration): keep retention-evicted rows out of the on_zero_results source fallback by @lukekim in #14783
- test: run federated source tests on every supported LTS release line by @lukekim in #14936
- fix(drasi): forward CDC creates and snapshots as upserts by @ewgenius in #14791
- fix(datafusion-optimizer-rules): answer only plain partition columns from the listing by @lukekim in #14806
- fix(connector-huggingface): retry Hub API responses that break off part way, and harden the live-Hub check by @lukekim in #15009
- Improve types methods in
runtime-rate-controlby @Jeadie in #14573 - fix(models):
/v1/responsesruns Spice tools and honorstool_recursion_limitwhen streaming (fixes #14905, #14631) by @krinart in #14930 - Update openapi.json by @github-actions in #14908
- test(cayenne): run the heap-measuring tests in one
isolatedtest binary by @bjchambers in #15010 - test(vortex): run vortex-datafusion's integration tests in the sign-off gate by @bjchambers in #15001
- fix(cayenne): refuse acceleration data stored under a different partition_by by @phillipleblanc in #15019
- Update openapi.json by @github-actions in #15018
- fix(ci): keep the OpenAPI regeneration PR current instead of skipping while one is open by @phillipleblanc in #15023
- fix: Cayenne deletion-index bounds and reload fencing, scan-statistics single-flight, UDF filter pushdown, Server-Timing, results-cache determinism, and view loading by @lukekim in #14993
- fix(cayenne): load write-back without on_conflict, and refuse pk_conflict_detection: none where it loses data (fixes #14886, #14889) by @bjchambers in #14891
- chore: Update Turso crate to 0.8.2 by @spiceemma in #15022
- feat(cayenne): runtime-wide adaptive_tuning and target_* settings by @peasee in #14844
- ci: apply whole-binary nextest overrides to the module test sets they select by @bjchambers in #15011
- fix(snapshots): give each snapshot publish its own object name, so publishes in the same second stop overwriting each other by @phillipleblanc in #15028
- test(data_components): compile the integration tests into one test binary by @bjchambers in #14991
- fix(glue): load Iceberg tables from S3 buckets with dots in the name by @phillipleblanc in #15053
- fix(runtime): give each runtime.state feature its own folder by @phillipleblanc in #15036
- test(data_components): make the HTTP provider snapshots independent of the machine by @bjchambers in #15000
- fix(json): reject incomplete arrays and avoid repeated parsing by @phillipleblanc in #15054
- test(runtime): drive the cdc_cayenne tests through Cayenne's change sink by @bjchambers in #15003
- ci(object_store_occ): run the WAL E2E suite on self-hosted runners against disk, MinIO, RustFS and spiceio by @lukekim in #15031
- test(llms): compile the credential-free tests into the integration binary by @bjchambers in #14990
- fix(cayenne): keep secondary indexes complete across acceleration snapshots by @sgrebnov in #15068
- ci(setup-minio): name the missing secret instead of failing in mc's argument parser by @grokspice in #15073
- ci: run Substrait Mode B on the Linux runners that can reach the trunk spiced builds by @grokspice in #15074
- feat(rerank): use evaluation models (TypeSafe) in rerank(), with per-query strategy by @Jeadie in #14782
- build(deps): bump the github-actions-dependencies group across 5 directories with 7 updates by @dependabot in #15027
- fix(cayenne): reclaim the snapshot directories a snapshot reader's reload supersedes by @sgrebnov in #15069
- feat(iceberg): read a table from a pinned metadata file without a catalog by @sgrebnov in #15081
- Fixes for MCP server by @Jeadie in #15041
- fix(search): vector_search returns its top k rows by score on chunked and multi-vector columns (fixes #14819) by @claudespice in #15056
- fix(postgres): keep applying CDC changes after a source column type change, and never store a rounded value (refs #14718) by @claudespice in #15037
- perf(iceberg): decode Iceberg scans at the session batch_size by @bjchambers in #15072
- fix(rate-control): admit waiting requests in arrival order at the charge in force (fixes #14912) by @krinart in #14931
- fix(rate-control): compare shared-origin settings as they resolve (fixes #14914) by @krinart in #14937
- fix(decisions): Fixes for /v1/decisions by @Jeadie in #15040
- perf(cayenne): bulk-load a keyed table without per-row routing or a whole-table fold by @bjchambers in #15076
- fix(cayenne): list a new snapshot's files once, when it is published by @bjchambers in #15077
- test(runtime,spiced): compile integration tests into declared binaries, run the ones no CI job ran, and remove the uncalled supersede_initial_load by @bjchambers in #15005
- fix(duckdb): unparse string literals with backslash-quote exactly by @lukekim in #15083
- ci(e2e): don't run rust-cache on the macOS build, whose save deletes cargo from sibling runners by @grokspice in #15100
- feat(testoperator): record per-query search metrics by @Jeadie in #15090
- fix(vortex): keep casts Vortex cannot evaluate out of the scan by @phillipleblanc in #15096
- feat(index): operation-aware CDC index maintenance via IndexChangeSet by @Jeadie in #14340
- ci: run merge-queue Mode A TPC-H and LLM integration tests on spiceai-macos-large by @lukekim in #15116
- docs(cayenne): the per-file fold merges no source files, but may roll by @bjchambers in #15101
- build(deps): bump async-openai to the fork's merge of upstream main by @krinart in #14980
- feat(iceberg): read a table root without a catalog, finding its current metadata on every query by @sgrebnov in #15095
- fix(runtime): fail recovery of an unsaved running query by @phillipleblanc in #15092
- perf(cayenne): build a keyed table's primary-key filter during its first load by @phillipleblanc in #15099
- test(cayenne): guard per-file statistics sharing for listings outside a scan view by @bjchambers in #15103
- feat(cache): age SQL results on TTL instead of invalidating them on refresh by @bjchambers in #15033
- fix(deps): estimate selective IN lists and OR-of-equalities from NDV by @bjchambers in #14140
- Change codeql runner from spiceai-macos to spiceai-macos-large by @lukekim in #15120
- fix(flightsql): prepared-statement GetFlightInfo schema matches the stream when parameters are bound by @lukekim in #15106
- fix(telemetry): report the configured CPU count as host.cpu.count by @lukekim in #15108
- fix(runtime-table): prepare every partition of a partitioned Cayenne table after a refresh by @bjchambers in #15111
- fix: Update Search integration test snapshots by @github-actions in #15050
- test(iceberg): read the Glue fixture unpinned and check the picked metadata file by @sgrebnov in #15115
- test(cayenne): differential and plan coverage for secondary indexes on partitioned accelerations by @bjchambers in #15113
- test: answer results-cache misses from the acceleration while the source is down by @bjchambers in #15112
- ci(lint): fail on test files no target compiles, and document the integration test layout by @bjchambers in #15109
- feat(snapshots): store snapshots under runtime.state, built by the shared state-location builder by @sgrebnov in #15117
- fix(federation): match NULL rows in pushed-down INTERSECT and EXCEPT (fixes #14941) by @sgrebnov in #15110
- fix(models): allowed_tools shape, provider error statuses, decision response model (fixes #14910) by @krinart in #14977
- feat(cayenne): let deletion_mode auto pick position deletes for small primary-key tables by @lukekim in #15042
- fix(iceberg): keep nested child namespaces when loading an Iceberg catalog by @lukekim in #15105
- fix(flight): authenticate before binding sessions, and bound TLS handshakes by @phillipleblanc in #15128
- fix(test): wait for pkd_ctl to load before reading its bootstrap row in the write-back pk_conflict test by @grokspice in #15102
- fix(models): return Spice tool calls in
/v1/responsesoutput so clients can replay them by @krinart in #15126 - test(mysql): skip the SQL results cache in the binlog replication end-to-end tests by @grokspice in #15141
- feat(runtime): check
runtime.stateat startup, and record its state format by @phillipleblanc in #15138 - feat(acceleration): apply changed acceleration settings on restart by @lukekim in #15094
- fix(models): enable Luna chat and NSQL support by @krinart in #15166
- fix(acceleration): read every accelerator partition in a caching point lookup by @phillipleblanc in #15177
- fix(cayenne): run snapshot-directory sweeps when a snapshot releases its file-deletion hold by @sgrebnov in #15179
- feat(telemetry): export runtime logs over OTLP and log failed queries by level by @lukekim in #15176

