date: 2026-10-16
title: 'Spice v2.4.0-rc.2 (Oct 15, 2026)'
type: blog
authors: [jeadie]
tags: [release, ai, iceberg, cayenne, caching, snapshots, opentelemetry, observability]
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:
These notes cover changes since v2.4.0-rc.1 (opens in a new tab). Review Breaking Changes (opens in a new tab) before upgrading; upgrades from earlier versions also require the rc.1 migration guidance (opens in a new tab).
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 (opens in a new tab). 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}
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';
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 (opens in a new tab) 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
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
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 (opens in a new tab).
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
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
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.state prefix no longer causes an ERROR log 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 (opens in a new tab).
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
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 (opens in a new tab) and the runtime YAML documentation (opens in a new tab).
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: auto can 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_complete kept 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_columns or cayenne_compression_strategy, applies to the existing acceleration. A change to primary_key or partition_by rebuilds the acceleration from the source only under specific conditions. See Cayenne Configuration Updates (opens in a new tab).
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
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-id and stored in runtime.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 (opens in a new tab), Exporting logs (opens in a new tab), and runtime.query.log_errors (opens in a new tab).
Fixes and Improvements
AI APIs and Models
- Responses API:
/v1/responses executes Spice tools and honors tool_recursion_limit when streaming. It returns Spice tool calls as mcp_call items in output, allowing clients that manage their own conversation history to replay them.
- Model controls:
/v1/nsql accepts reasoning_effort, and rerank() 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_id is available as a model parameter.
- OpenAI: Models with an unknown service tier can load and serve requests.
- Luna:
gpt-6-luna and its snapshots support chat, /v1/nsql, and native decisions.
Acceleration
- Caching point lookups: Lookups on a
refresh_mode: caching dataset 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, or cayenne_shard_key_columns applies 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_detection from none to auto, or the data location rebuilds the acceleration from the source. The runtime rebuilds only a dataset with refresh_mode: full, mode: file or file_update, and write_mode: write_through. The source must not be sink:, 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
spice upgrade v2.4.0-rc.2
Docker
docker pull spiceai/spiceai:2.4.0-rc.2
docker pull spiceai/spiceai:2.4.0-rc.2
See Docker Hub (opens in a new tab) for available tags.
Helm
helm repo update
helm upgrade spiceai spiceai/spiceai --version 2.4.0-rc.2
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 (opens in a new tab).
Contributors
Changelog
See the full changelog from v2.4.0-rc.1 to v2.4.0-rc.2 (opens in a new tab).
- feat(connector-huggingface): Hugging Face datasets data connector (
hf://datasets/...) by @lukekim (opens in a new tab) in #14877 (opens in a new tab)
- fix(iceberg): Iceberg REST clients read the real table or get an error, never an empty one by @lukekim (opens in a new tab) in #14588 (opens in a new tab)
- fix(federation): ask the executor for the SELECT 1 placeholder of an empty projection by @krinart (opens in a new tab) in #14851 (opens in a new tab)
- fix(cayenne): float statistics must not leave NaN out of pruning or metadata answers (fixes #14719) by @claudespice (opens in a new tab) in #14792 (opens in a new tab)
- fix: Update tpch benchmark snapshots for accelerated/s3[parquet]-duckdb[file]-2gib.yaml by @github-actions (opens in a new tab) in #14850 (opens in a new tab)
- Update openapi.json by @github-actions (opens in a new tab) in #14858 (opens in a new tab)
- test: strengthen assertions and enforce sign-off coverage by @lukekim (opens in a new tab) in #14740 (opens in a new tab)
- Reapply "fix(sqlite, duckdb): keep a decimal AVG, and on SQLite a decimal SUM, out of the federated plan (fixes #14492)" by @krinart (opens in a new tab) in #14888 (opens in a new tab)
- fix(caching): a GET and a POST to one HTTP path no longer share a cache entry (fixes #14768) by @claudespice (opens in a new tab) in #14884 (opens in a new tab)
- fix(anthropic): drop empty text blocks from assistant messages by @Jeadie (opens in a new tab) in #14834 (opens in a new tab)
- fix(cayenne): ask the table whether it takes a versioned append, instead of predicting it by @lukekim (opens in a new tab) in #14882 (opens in a new tab)
- test(sqlite): guard the Date32 literal cast through the SQLite acceleration's own scan (fixes #14491) by @grokspice (opens in a new tab) in #14703 (opens in a new tab)
- fix(cayenne): read each file once when a hash join narrows an indexed table's scan by @lukekim (opens in a new tab) in #14934 (opens in a new tab)
- fix(sharepoint): list drive items when the listing contains a folder (fixes #2797) by @phillipleblanc (opens in a new tab) in #14946 (opens in a new tab)
- fix(runtime): log each failing dataset's load failure (fixes #14918) by @phillipleblanc (opens in a new tab) in #14939 (opens in a new tab)
- fix(deps): move the DataFusion pin past spiceai/datafusion#256, so FlightSQL Substrait plans read string columns (fixes #14935) by @lukekim (opens in a new tab) in #14944 (opens in a new tab)
- fix(cayenne): publish a keyed partition's append as a protected overlay (fixes #14947) by @lukekim (opens in a new tab) in #14955 (opens in a new tab)
- fix(acceleration): a failed acceleration build no longer keeps the dataset down until restart (fixes #14917) by @phillipleblanc (opens in a new tab) in #14942 (opens in a new tab)
- fix(postgres): reject a changes dataset without a primary key when it loads by @phillipleblanc (opens in a new tab) in #14960 (opens in a new tab)
- feat(spicepod): publish pull request reviews by @lukekim (opens in a new tab) in #14964 (opens in a new tab)
- fix(ci): bound the REPL expect-script waits on silence, not total response time (fixes #13711) by @grokspice (opens in a new tab) in #14963 (opens in a new tab)
- fix(cluster): treat secrets the scheduler declines as not found on executors by @phillipleblanc (opens in a new tab) in #14957 (opens in a new tab)
- fix(flight): return query and data errors as InvalidArgument, not Internal by @phillipleblanc (opens in a new tab) in #14956 (opens in a new tab)
- fix(duckdb,sqlite): correct pushdown for string_agg ORDER BY, concat NULLs, and unsupported fns by @lukekim (opens in a new tab) in #14798 (opens in a new tab)
- fix(ci): provision DuckLake for the ducklake[catalog] schema test, which has never passed by @grokspice (opens in a new tab) in #14952 (opens in a new tab)
- fix(llms): stream Anthropic responses that open with a thinking block (fixes #14909) by @krinart (opens in a new tab) in #14920 (opens in a new tab)
- fix(arrow): serve lookups from enabled indexes; a repeated key disables the index with a warning by @sgrebnov (opens in a new tab) in #14968 (opens in a new tab)
- feat(nsql): accept reasoning_effort on POST /v1/nsql by @lukekim (opens in a new tab) in #14852 (opens in a new tab)
- fix(listing): scan file_extension '*' tables through ListingTable, so Glue joins broadcast again (fixes #14890) by @krinart (opens in a new tab) in #14972 (opens in a new tab)
- fix(llms): load and serve an OpenAI model when a reply names an unknown service tier (fixes #14916) by @krinart (opens in a new tab) in #14927 (opens in a new tab)
- feat(cayenne): always persist secondary index runs by @sgrebnov (opens in a new tab) in #14979 (opens in a new tab)
- fix(cache): expire results-cache entries in insertion order instead of walking every LRU list by @bjchambers (opens in a new tab) in #14919 (opens in a new tab)
- feat: decisions in SQL (ai_if, ai_probability, ai_classify, ai_score, ai_decide) and an OpenAI-compatible /v1/decisions by @lukekim (opens in a new tab) in #14838 (opens in a new tab)
- fix(rrf): keep named arguments on nested search calls by @phillipleblanc (opens in a new tab) in #14975 (opens in a new tab)
- fix(rate-control): hold instances that set different limits for one origin to the lowest (fixes #14913) by @krinart (opens in a new tab) in #14932 (opens in a new tab)
- fix(vortex): keep temporal casts Vortex can't evaluate out of the scan by @sgrebnov (opens in a new tab) in #14985 (opens in a new tab)
- fix(acceleration): recommend mode: file for CDC on_conflict migrations to Cayenne by @bjchambers (opens in a new tab) in #14928 (opens in a new tab)
- test(huggingface): unblock the merge queue: read imdb's parquet conversion through
@~parquet and fail fast on a vanished Hub pin by @grokspice (opens in a new tab) in #14998 (opens in a new tab)
- test(cayenne): link the integration tests into one test binary by @bjchambers (opens in a new tab) in #14976 (opens in a new tab)
- test(vortex): compile the integration tests into a binary the sign-off gate runs by @bjchambers (opens in a new tab) in #14987 (opens in a new tab)
- fix(http): reject a request_path that URL parsing would rewrite by @bjchambers (opens in a new tab) in #14965 (opens in a new tab)
- fix(clickhouse): load LowCardinality, DateTime64, Array, Map, Tuple, Enum, 128-bit integer and IP columns by @phillipleblanc (opens in a new tab) in #14953 (opens in a new tab)
- Add anthropic_workspace_id param for Anthropic models by @Jeadie (opens in a new tab) in #14829 (opens in a new tab)
- fix(acceleration): keep retention-evicted rows out of the on_zero_results source fallback by @lukekim (opens in a new tab) in #14783 (opens in a new tab)
- test: run federated source tests on every supported LTS release line by @lukekim (opens in a new tab) in #14936 (opens in a new tab)
- fix(drasi): forward CDC creates and snapshots as upserts by @ewgenius (opens in a new tab) in #14791 (opens in a new tab)
- fix(datafusion-optimizer-rules): answer only plain partition columns from the listing by @lukekim (opens in a new tab) in #14806 (opens in a new tab)
- fix(connector-huggingface): retry Hub API responses that break off part way, and harden the live-Hub check by @lukekim (opens in a new tab) in #15009 (opens in a new tab)
- Improve types methods in
runtime-rate-control by @Jeadie (opens in a new tab) in #14573 (opens in a new tab)
- fix(models):
/v1/responses runs Spice tools and honors tool_recursion_limit when streaming (fixes #14905, #14631) by @krinart (opens in a new tab) in #14930 (opens in a new tab)
- Update openapi.json by @github-actions (opens in a new tab) in #14908 (opens in a new tab)
- test(cayenne): run the heap-measuring tests in one
isolated test binary by @bjchambers (opens in a new tab) in #15010 (opens in a new tab)
- test(vortex): run vortex-datafusion's integration tests in the sign-off gate by @bjchambers (opens in a new tab) in #15001 (opens in a new tab)
- fix(cayenne): refuse acceleration data stored under a different partition_by by @phillipleblanc (opens in a new tab) in #15019 (opens in a new tab)
- Update openapi.json by @github-actions (opens in a new tab) in #15018 (opens in a new tab)
- fix(ci): keep the OpenAPI regeneration PR current instead of skipping while one is open by @phillipleblanc (opens in a new tab) in #15023 (opens in a new tab)
- 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 (opens in a new tab) in #14993 (opens in a new tab)
- fix(cayenne): load write-back without on_conflict, and refuse pk_conflict_detection: none where it loses data (fixes #14886, #14889) by @bjchambers (opens in a new tab) in #14891 (opens in a new tab)
- chore: Update Turso crate to 0.8.2 by @spiceemma (opens in a new tab) in #15022 (opens in a new tab)
- feat(cayenne): runtime-wide adaptive_tuning and target_* settings by @peasee (opens in a new tab) in #14844 (opens in a new tab)
- ci: apply whole-binary nextest overrides to the module test sets they select by @bjchambers (opens in a new tab) in #15011 (opens in a new tab)
- fix(snapshots): give each snapshot publish its own object name, so publishes in the same second stop overwriting each other by @phillipleblanc (opens in a new tab) in #15028 (opens in a new tab)
- test(data_components): compile the integration tests into one test binary by @bjchambers (opens in a new tab) in #14991 (opens in a new tab)
- fix(glue): load Iceberg tables from S3 buckets with dots in the name by @phillipleblanc (opens in a new tab) in #15053 (opens in a new tab)
- fix(runtime): give each runtime.state feature its own folder by @phillipleblanc (opens in a new tab) in #15036 (opens in a new tab)
- test(data_components): make the HTTP provider snapshots independent of the machine by @bjchambers (opens in a new tab) in #15000 (opens in a new tab)
- fix(json): reject incomplete arrays and avoid repeated parsing by @phillipleblanc (opens in a new tab) in #15054 (opens in a new tab)
- test(runtime): drive the cdc_cayenne tests through Cayenne's change sink by @bjchambers (opens in a new tab) in #15003 (opens in a new tab)
- ci(object_store_occ): run the WAL E2E suite on self-hosted runners against disk, MinIO, RustFS and spiceio by @lukekim (opens in a new tab) in #15031 (opens in a new tab)
- test(llms): compile the credential-free tests into the integration binary by @bjchambers (opens in a new tab) in #14990 (opens in a new tab)
- fix(cayenne): keep secondary indexes complete across acceleration snapshots by @sgrebnov (opens in a new tab) in #15068 (opens in a new tab)
- ci(setup-minio): name the missing secret instead of failing in mc's argument parser by @grokspice (opens in a new tab) in #15073 (opens in a new tab)
- ci: run Substrait Mode B on the Linux runners that can reach the trunk spiced builds by @grokspice (opens in a new tab) in #15074 (opens in a new tab)
- feat(rerank): use evaluation models (TypeSafe) in rerank(), with per-query strategy by @Jeadie (opens in a new tab) in #14782 (opens in a new tab)
- build(deps): bump the github-actions-dependencies group across 5 directories with 7 updates by @dependabot (opens in a new tab) in #15027 (opens in a new tab)
- fix(cayenne): reclaim the snapshot directories a snapshot reader's reload supersedes by @sgrebnov (opens in a new tab) in #15069 (opens in a new tab)
- feat(iceberg): read a table from a pinned metadata file without a catalog by @sgrebnov (opens in a new tab) in #15081 (opens in a new tab)
- Fixes for MCP server by @Jeadie (opens in a new tab) in #15041 (opens in a new tab)
- fix(search): vector_search returns its top k rows by score on chunked and multi-vector columns (fixes #14819) by @claudespice (opens in a new tab) in #15056 (opens in a new tab)
- fix(postgres): keep applying CDC changes after a source column type change, and never store a rounded value (refs #14718) by @claudespice (opens in a new tab) in #15037 (opens in a new tab)
- perf(iceberg): decode Iceberg scans at the session batch_size by @bjchambers (opens in a new tab) in #15072 (opens in a new tab)
- fix(rate-control): admit waiting requests in arrival order at the charge in force (fixes #14912) by @krinart (opens in a new tab) in #14931 (opens in a new tab)
- fix(rate-control): compare shared-origin settings as they resolve (fixes #14914) by @krinart (opens in a new tab) in #14937 (opens in a new tab)
- fix(decisions): Fixes for /v1/decisions by @Jeadie (opens in a new tab) in #15040 (opens in a new tab)
- perf(cayenne): bulk-load a keyed table without per-row routing or a whole-table fold by @bjchambers (opens in a new tab) in #15076 (opens in a new tab)
- fix(cayenne): list a new snapshot's files once, when it is published by @bjchambers (opens in a new tab) in #15077 (opens in a new tab)
- 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 (opens in a new tab) in #15005 (opens in a new tab)
- fix(duckdb): unparse string literals with backslash-quote exactly by @lukekim (opens in a new tab) in #15083 (opens in a new tab)
- ci(e2e): don't run rust-cache on the macOS build, whose save deletes cargo from sibling runners by @grokspice (opens in a new tab) in #15100 (opens in a new tab)
- feat(testoperator): record per-query search metrics by @Jeadie (opens in a new tab) in #15090 (opens in a new tab)
- fix(vortex): keep casts Vortex cannot evaluate out of the scan by @phillipleblanc (opens in a new tab) in #15096 (opens in a new tab)
- feat(index): operation-aware CDC index maintenance via IndexChangeSet by @Jeadie (opens in a new tab) in #14340 (opens in a new tab)
- ci: run merge-queue Mode A TPC-H and LLM integration tests on spiceai-macos-large by @lukekim (opens in a new tab) in #15116 (opens in a new tab)
- docs(cayenne): the per-file fold merges no source files, but may roll by @bjchambers (opens in a new tab) in #15101 (opens in a new tab)
- build(deps): bump async-openai to the fork's merge of upstream main by @krinart (opens in a new tab) in #14980 (opens in a new tab)
- feat(iceberg): read a table root without a catalog, finding its current metadata on every query by @sgrebnov (opens in a new tab) in #15095 (opens in a new tab)
- fix(runtime): fail recovery of an unsaved running query by @phillipleblanc (opens in a new tab) in #15092 (opens in a new tab)
- perf(cayenne): build a keyed table's primary-key filter during its first load by @phillipleblanc (opens in a new tab) in #15099 (opens in a new tab)
- test(cayenne): guard per-file statistics sharing for listings outside a scan view by @bjchambers (opens in a new tab) in #15103 (opens in a new tab)
- feat(cache): age SQL results on TTL instead of invalidating them on refresh by @bjchambers (opens in a new tab) in #15033 (opens in a new tab)
- fix(deps): estimate selective IN lists and OR-of-equalities from NDV by @bjchambers (opens in a new tab) in #14140 (opens in a new tab)
- Change codeql runner from spiceai-macos to spiceai-macos-large by @lukekim (opens in a new tab) in #15120 (opens in a new tab)
- fix(flightsql): prepared-statement GetFlightInfo schema matches the stream when parameters are bound by @lukekim (opens in a new tab) in #15106 (opens in a new tab)
- fix(telemetry): report the configured CPU count as host.cpu.count by @lukekim (opens in a new tab) in #15108 (opens in a new tab)
- fix(runtime-table): prepare every partition of a partitioned Cayenne table after a refresh by @bjchambers (opens in a new tab) in #15111 (opens in a new tab)
- fix: Update Search integration test snapshots by @github-actions (opens in a new tab) in #15050 (opens in a new tab)
- test(iceberg): read the Glue fixture unpinned and check the picked metadata file by @sgrebnov (opens in a new tab) in #15115 (opens in a new tab)
- test(cayenne): differential and plan coverage for secondary indexes on partitioned accelerations by @bjchambers (opens in a new tab) in #15113 (opens in a new tab)
- test: answer results-cache misses from the acceleration while the source is down by @bjchambers (opens in a new tab) in #15112 (opens in a new tab)
- ci(lint): fail on test files no target compiles, and document the integration test layout by @bjchambers (opens in a new tab) in #15109 (opens in a new tab)
- feat(snapshots): store snapshots under runtime.state, built by the shared state-location builder by @sgrebnov (opens in a new tab) in #15117 (opens in a new tab)
- fix(federation): match NULL rows in pushed-down INTERSECT and EXCEPT (fixes #14941) by @sgrebnov (opens in a new tab) in #15110 (opens in a new tab)
- fix(models): allowed_tools shape, provider error statuses, decision response model (fixes #14910) by @krinart (opens in a new tab) in #14977 (opens in a new tab)
- feat(cayenne): let deletion_mode auto pick position deletes for small primary-key tables by @lukekim (opens in a new tab) in #15042 (opens in a new tab)
- fix(iceberg): keep nested child namespaces when loading an Iceberg catalog by @lukekim (opens in a new tab) in #15105 (opens in a new tab)
- fix(flight): authenticate before binding sessions, and bound TLS handshakes by @phillipleblanc (opens in a new tab) in #15128 (opens in a new tab)
- fix(test): wait for pkd_ctl to load before reading its bootstrap row in the write-back pk_conflict test by @grokspice (opens in a new tab) in #15102 (opens in a new tab)
- fix(models): return Spice tool calls in
/v1/responses output so clients can replay them by @krinart (opens in a new tab) in #15126 (opens in a new tab)
- test(mysql): skip the SQL results cache in the binlog replication end-to-end tests by @grokspice (opens in a new tab) in #15141 (opens in a new tab)
- feat(runtime): check
runtime.state at startup, and record its state format by @phillipleblanc (opens in a new tab) in #15138 (opens in a new tab)
- feat(acceleration): apply changed acceleration settings on restart by @lukekim (opens in a new tab) in #15094 (opens in a new tab)
- fix(models): enable Luna chat and NSQL support by @krinart (opens in a new tab) in #15166 (opens in a new tab)
- fix(acceleration): read every accelerator partition in a caching point lookup by @phillipleblanc (opens in a new tab) in #15177 (opens in a new tab)
- fix(cayenne): run snapshot-directory sweeps when a snapshot releases its file-deletion hold by @sgrebnov (opens in a new tab) in #15179 (opens in a new tab)
- feat(telemetry): export runtime logs over OTLP and log failed queries by level by @lukekim (opens in a new tab) in #15176 (opens in a new tab)