)]}'
{
  "log": [
    {
      "commit": "333e2636afdbea275082c164bf2b969a81519c01",
      "tree": "e94642d64f69fd8d5a4888ed0f95415a6a413328",
      "parents": [
        "6f9ea315c91cba3307346b2f13fcf8f185a581d5"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Wed Nov 11 21:27:24 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Nov 11 21:27:24 2026 +0000"
      },
      "message": "docs: refresh the README and generate benchmark results from JSON (#2814)\n\n* docs: refresh the README and generate benchmark results from JSON\n\nAdd performance charts, a feature list and a new architecture diagram to\nthe README, and bring its project status up to date.\n\nStore the published benchmark results as JSON in\nbenchmarks/cluster/published, and generate the results table in the docs\nand the README charts from them with publish.py.\n\n* docs: refresh the Ballista staged and pipelined results\n\n* docs: Comet 1.1.0 is released, not rc2\n\n* docs: apply prettier formatting to the benchmark versions table\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: sim \u003csim@example.com\u003e\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "6f9ea315c91cba3307346b2f13fcf8f185a581d5",
      "tree": "2df8c66cb06bcf2b6347e825421367b8d520767a",
      "parents": [
        "8ccb86396857be9de3cecd13145fefc8959d1c73"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Wed Nov 11 17:05:56 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Nov 11 17:05:56 2026 +0000"
      },
      "message": "fix: plan a range RepartitionExec as a shuffle stage instead of dropping it (#2722)\n\n* fix: plan a range RepartitionExec as a shuffle stage instead of dropping it\n\nThe static planner kept only hash repartitions as stage boundaries and\ndropped every other RepartitionExec. That is harmless for round-robin,\nwhich only spreads rows, but a range repartition is part of what a plan\nmeans. A plan that range-partitions and then sorts each partition (a\ndistributed global sort) came back as partitions that were each sorted\nbut not range-disjoint, with no error.\n\nA RepartitionExec with Partitioning::Range is now a stage boundary. The\nproducer stage ends in a SortShuffleWriterExec that routes rows with\nDataFusion\u0027s own RangeExpr (the function RepartitionExec applies), so\nthe consumer\u0027s partition i reads exactly range i. The writer shares\neverything after routing with the hash shuffle: buffering, spilling, the\nconsolidated file and its index. The range travels in a new field of\nSortShuffleWriterExecNode; hash stages keep using the old one.\n\nRestricting a range-partitioned ShuffleReaderExec to a task\u0027s partitions\nnow slices the split points along with them, instead of failing. A slice\nthat does not ascend (a retried partition queued ahead of a later one)\nor is empty has no range partitioning to report, so it reports\nUnknownPartitioning rather than failing the task.\n\nA range repartition that must preserve its input order is rejected with\nan error: a shuffle cannot merge sorted inputs, and planning it anyway\nwould return partitions that are range-disjoint but no longer sorted.\n\nRangeShuffleWriterExec and RangeShuffleReaderExec are not used. They\nneed an ordered producer, while the repartition here is followed by the\nsort.\n\nCloses #2680\n\n* docs: note range repartition planning in the 56.0.0 upgrade guide\n\nA range RepartitionExec in a submitted physical plan is now planned as a\nshuffle instead of being dropped, one that must preserve its order is\nrefused, and SortShuffleWriterExecNode gains a field.\n\n* fix: number SortShuffleWriterExecNode.partitioning 11\n\n#2723 adds partition_id_routing to the same message as field 10, and two\nfields cannot share a number. 11 leaves 10 to it, and putting the field\nnext to output_partitioning keeps it clear of the fields that PR appends\nat the end of the message.\n\n* refactor: simplify range shuffle routing and trim its tests and comments\n\n- RowRouter takes the partitioning by value and no longer carries a partition\n  count; the hash and range paths share one bucket reset.\n- Reword two comments that overstated things. RangeExpr shares\n  BatchPartitioner\u0027s routing function (it is not \"the function RepartitionExec\n  applies\"), and a restricted reader\u0027s partitioning is read by partitioned\n  hash-join dynamic filters, which Ballista disables by default.\n- Drop overlapping tests and duplicated helpers, reuse roundtrip_plan in the\n  serde tests, and shorten comments and the upgrade-guide entries.\n\n* test: globally sort a submitted range repartition on a standalone cluster\n\n* fix(test): bind a standalone executor\u0027s gRPC port on its Flight address family\n\nThe standalone scheduler binds localhost:0, which can resolve to ::1,\nwhile a push-staged standalone executor bound its gRPC listener on\n127.0.0.1:0. The two address families can be handed the same port\nnumber, and the scheduler then dials the executor\u0027s registered\nlocalhost:\u003cport\u003e and reaches itself, failing launches with Unimplemented.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: sim \u003csim@example.com\u003e\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "8ccb86396857be9de3cecd13145fefc8959d1c73",
      "tree": "adab94933e9bbbbf0577e3c3f1fec19a33e79bc0",
      "parents": [
        "d98720804369917151052e1c280a1dae711817fb"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Wed Nov 11 17:00:27 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Nov 11 17:00:27 2026 +0000"
      },
      "message": "chore(ci): bump taiki-e/install-action from 2.90.2 to 2.90.3 (#2846)\n\nBumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.90.2 to 2.90.3.\n- [Release notes](https://github.com/taiki-e/install-action/releases)\n- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/taiki-e/install-action/compare/3a3daafd3b7f23b8f65d9f5ba2db203fb59b79e2...cfdb7ed4ccc7c7dce37759eae89dc5674b469b39)\n\n---\nupdated-dependencies:\n- dependency-name: taiki-e/install-action\n  dependency-version: 2.90.3\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "d98720804369917151052e1c280a1dae711817fb",
      "tree": "b0a294f4f378ab9831d57619d505499bc498552a",
      "parents": [
        "6ecc5c30784e2ca0607a52f1b095173c37f1c26c"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 10 21:46:16 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 21:46:16 2026 +0000"
      },
      "message": "docs: present Ballista as one engine for ETL and interactive queries (#2834)\n\n* docs: present Ballista as one engine for ETL and interactive queries\n\nWith pipelined execution merged, one cluster can run long ETL jobs staged\nand low-latency analytical queries pipelined, chosen per session. Say so in\nthe README: the Features bullet notes that the two modes share a cluster, and\na new section explains the lakehouse use case and the capacity a shared pool\ncan save.\n\nThe section also records what is missing: pipelined execution is\nexperimental, and the scheduler has no job priority, so an interactive query\ncan wait for vcores held by batch jobs.\n\n* docs: describe workload categories instead of naming reference engines\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: sim \u003csim@example.com\u003e\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "6ecc5c30784e2ca0607a52f1b095173c37f1c26c",
      "tree": "d88b4f8e158cb0665ba1020ffad50c7deb4c70c5",
      "parents": [
        "a48c2326776d3dbf397ad6cef306fd5a46a6ef24"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 10 21:22:08 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 21:22:08 2026 +0000"
      },
      "message": "feat: let custom ExecutionPlan nodes restrict themselves to a task\u0027s partitions (#2721)\n\n* fix(scheduler): import ExecutionPlan in the execution_graph tests\n\n#2633 added a test to this module that names ExecutionPlan, and #2613 then\nmoved FailingPlanRewriteExec out of the module and dropped the imports it\nhad needed, ExecutionPlan among them. Each passed CI against its own base.\nTogether they leave the scheduler\u0027s test target uncompilable, so cargo check,\nClippy and the test jobs have failed on main since #2613 landed.\n\n* feat: let custom ExecutionPlan nodes restrict themselves to a task\u0027s partitions\n\nWhen a stage is split between tasks, the scheduler restricts each task\u0027s\nplan to the partitions that task runs. It could only restrict the leaves it\nknew and the two PartitionSliceable operators on a hand-kept list. Any other\nnode holding data per partition was left as it was, so a task that ran\npartitions 4 and 5 of it executed its partitions 0 and 1, and the stage\nreturned some partitions twice and others not at all, with no error.\n\n- PartitionSliceable::restrict_to_partitions takes any number of children,\n  leaves included. It replaces slice_to_partitions, which took one.\n- SchedulerConfig::partition_sliceable_resolver finds the PartitionSliceable\n  of nodes Ballista does not list. It is asked after the built-in list.\n- A leaf that nothing can restrict now fails the task unless the task runs\n  all of its partitions in order, instead of running and duplicating output.\n  The scheduler also rejects a restriction that returns the wrong number of\n  partitions.\n\n* test: look through CooperativeExec for the restricted leaf in the resolver test\n\n(cherry picked from commit 2efa802ffd6f454211d516b660a3f9db648bab65)\n\n* refactor: make PartitionSliceableResolver a trait and clarify what is guarded\n\nThe resolver is now a trait, like the other extension points on\nSchedulerConfig, so methods can be added later without another breaking\nchange. Fix the missing \"can\" in the unrestrictable-leaf error and\ncompare the whole message in its test. The upgrade guide and the\nextending-components guide now say that only leaves are checked, and\nthat whether a stage is split depends on cluster load and retries.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: sim \u003csim@example.com\u003e\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "a48c2326776d3dbf397ad6cef306fd5a46a6ef24",
      "tree": "57143461ed011bc14bb9089865fac849d40ccbc4",
      "parents": [
        "9f770a909dd622d582921e56b736adb4cff8ddc3"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 10 20:05:40 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 20:05:40 2026 +0000"
      },
      "message": "fix: raise the executor\u0027s open file limit to the hard limit at startup (#2794)\n\nA task holds a file per shuffle partition it reads or writes plus its\nspill files, so stages with a few hundred partitions need thousands of\ndescriptors. With the common 1024 soft limit, TPC-H at 128+ partitions\nfails with \"Too many open files\". The JVM raises its soft limit at\nstartup, so Spark executors are unaffected; do the same."
    },
    {
      "commit": "9f770a909dd622d582921e56b736adb4cff8ddc3",
      "tree": "2162962cf36e80b193a657c9b92a2159fecccfc1",
      "parents": [
        "b0f4e94b1437c20c6fb06ee8ad6cfc8c2b67736a"
      ],
      "author": {
        "name": "NoahKusaba",
        "email": "97474796+NoahKusaba@users.noreply.github.com",
        "time": "Tue Nov 10 19:22:42 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 19:22:42 2026 +0000"
      },
      "message": "fix(dev): let the Docker build scripts run when CI is unset (#2835)\n\nBoth scripts run under `set -u`, so `${CI}` aborted with an unbound\nvariable error on any machine without CI set, which broke\ndev/integration-tests.sh locally. Default it to empty."
    },
    {
      "commit": "b0f4e94b1437c20c6fb06ee8ad6cfc8c2b67736a",
      "tree": "155bd2c5c5b6031034d7220f786208ad28d52487",
      "parents": [
        "4aa53675c17d18e0bb3fb7791d1196cf519432d1"
      ],
      "author": {
        "name": "NoahKusaba",
        "email": "97474796+NoahKusaba@users.noreply.github.com",
        "time": "Tue Nov 10 19:21:41 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 19:21:41 2026 +0000"
      },
      "message": "chore(scheduler): remove the no-op disable-stage-plan-cache feature (#2836)\n\nThe scheduler stopped caching encoded stage plans in 55.0.0 (#2038) and\nnow encodes each task\u0027s plan separately, so nothing reads this feature.\nRemove it, drop it from the two README feature tables, and note the\nremoval in the 56.0.0 upgrade guide."
    },
    {
      "commit": "4aa53675c17d18e0bb3fb7791d1196cf519432d1",
      "tree": "41759364f9ccb9412f5f3014872e2df47fd3b946",
      "parents": [
        "9ed1caed1a3ccfd93ffc46966fe1463e573c0b41"
      ],
      "author": {
        "name": "Marko Milenković",
        "email": "milenkovicm@users.noreply.github.com",
        "time": "Tue Nov 10 15:52:38 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 15:52:38 2026 +0000"
      },
      "message": "feat: hide ballista session contexts implementations behind common interface (#2832)\n\n* hide two ballista clients behind common interface\n\n* add config option to configure client\n\n* address comments\n\n* remove test\n\n* update certify uv deps"
    },
    {
      "commit": "9ed1caed1a3ccfd93ffc46966fe1463e573c0b41",
      "tree": "def5666a95792689ac6034b82537250a9d63731f",
      "parents": [
        "1b348f72be7969713f3cf2407ac4a9c6219ac498"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 10 15:26:16 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 15:26:16 2026 +0000"
      },
      "message": "fix: keep volatile semi joins in place and test results with the rule on and off (#2793)\n\nCo-authored-by: sim \u003csim@example.com\u003e"
    },
    {
      "commit": "1b348f72be7969713f3cf2407ac4a9c6219ac498",
      "tree": "bbb573e4c183f6ef9dedd8c77bcd58ea1f2ea011",
      "parents": [
        "3ba366d1df9ba9a12f4eedf6bc8f9b1fb3fbd3d0"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Tue Nov 10 14:08:05 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 14:08:05 2026 +0000"
      },
      "message": "chore(deps): bump uuid from 1.29.0 to 1.29.1 (#2830)\n\nBumps [uuid](https://github.com/uuid-rs/uuid) from 1.29.0 to 1.29.1.\n- [Release notes](https://github.com/uuid-rs/uuid/releases)\n- [Commits](https://github.com/uuid-rs/uuid/compare/v1.29.0...v1.29.1)\n\n---\nupdated-dependencies:\n- dependency-name: uuid\n  dependency-version: 1.29.1\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "3ba366d1df9ba9a12f4eedf6bc8f9b1fb3fbd3d0",
      "tree": "bc041140c5ed6c1ed30d36bf70be4b27c6e1d852",
      "parents": [
        "09a52ad11c755ceb77d71bd5d9f5a030bd46c2ec"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 10 12:51:49 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 12:51:49 2026 +0000"
      },
      "message": "fix: let executor spills use the work dir\u0027s free space by default (#2797)\n\n* fix: let executor spills use the work dir\u0027s free space by default\n\nDataFusion caps spill files at 100 GB per runtime. At TPC-H SF1000 on\ntwo executors, q5 and q18 spill more than that and fail, although the\nexecutor\u0027s work dir is a 1 TB volume. When --max-temp-directory-size is\nnot set, use the space free on the work dir\u0027s filesystem at startup,\nnever less than DataFusion\u0027s default.\n\n* refactor(executor): read work dir free space via sysinfo\n\nReplace the unsafe libc statvfs call with sysinfo\u0027s disk list, matching\nthe work dir to its disk by device id on unix, and reword the\n--max-temp-directory-size docs to say the default is the larger of the\nfree space and DataFusion\u0027s 100 GB.\n\n---------\n\nCo-authored-by: sim \u003csim@example.com\u003e"
    },
    {
      "commit": "09a52ad11c755ceb77d71bd5d9f5a030bd46c2ec",
      "tree": "395b6f0a71e14fb11dbaee21489f098b64461fae",
      "parents": [
        "5bd230eec202f667169c6bd3a32b92933ed011cf"
      ],
      "author": {
        "name": "Bodor Laszlo",
        "email": "bodorlaszlo0202@gmail.com",
        "time": "Tue Nov 10 12:51:42 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 12:51:42 2026 +0000"
      },
      "message": "fix(scheduler): don\u0027t drop a task\u0027s status when its metrics can\u0027t be merged (#2828)\n\n* fix(scheduler): don\u0027t drop a task\u0027s status when its metrics can\u0027t be merged\n\nA stage\u0027s tasks don\u0027t always report the same number of operator metric\nsets. Restricting a task\u0027s plan to its partitions replaces an empty\nUnionExec child\u0027s EmptyExec or PlaceholderRowExec with a 0-partition\nDataSourceExec, which reports metrics where the EmptyExec reported none.\nIn TPC-DS q23b with AQE, stage 30 got tasks with 7 and with 8 metric\nsets.\n\nupdate_task_metrics returns an error on such a mismatch, and the AQE,\nstatic and pipelined graphs propagated it with `?`, which dropped the\nrest of the task-status update. The stage never completed and the job\nhung until cancelled.\n\nMetrics only feed the plan display and the REST API, so log the error\nand keep the task\u0027s status instead.\n\n* PR comments"
    },
    {
      "commit": "5bd230eec202f667169c6bd3a32b92933ed011cf",
      "tree": "e62518e191cbfc571ee7b0d4cd7dea2ff35ccb09",
      "parents": [
        "153c5f96d34b3e4b398d0fdcd1acc47d5d346850"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 10 12:37:29 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 12:37:29 2026 +0000"
      },
      "message": "perf: share each broadcast read between the tasks on an executor (#2807)\n\n* perf: share each broadcast read between the tasks on an executor\n\nThe build side of a broadcast hash join is a broadcast ShuffleReaderExec\nthat reads every partition of the upstream stage. Each task runs its own\nplan, so every task on an executor fetched and decoded the same build\nside: at 128 partitions a 16-task broadcast stage made 16,384 fetch\nrequests for one 318K-row table.\n\nAdd an executor-wide BroadcastReadCache. The first task to run a\nbroadcast read fetches it; tasks that ask meanwhile wait for that fetch,\nand later ones reuse the decoded batches. Entries are keyed by job,\nstage and the exact locations read, expire after 30 s unused, are not\nkept above 1 GiB, and are dropped with the job\u0027s data. A failed fetch is\nnot cached, so each task reports its own fetch error as before.\n\nControlled by ballista.shuffle.cache_broadcast_reads (default true).\n\n* fix: record broadcast cache hit rows and stamp last use after the fetch\n\n* test: build the broadcast key test location with an ExecutorEndpoint\n\n---------\n\nCo-authored-by: sim \u003csim@example.com\u003e"
    },
    {
      "commit": "153c5f96d34b3e4b398d0fdcd1acc47d5d346850",
      "tree": "aaada8098a81872393256d3e7a07343c36e5b4a8",
      "parents": [
        "714e23c3a454b88883b83207f208bd443e4742e6"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 10 11:45:45 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 11:45:45 2026 +0000"
      },
      "message": "perf: semi-join small filtered dimensions below the joins in between (#2799)\n\n* perf: push semi and anti joins below inner joins\n\nDataFusion decorrelates IN/EXISTS/NOT EXISTS subqueries into semi and\nanti joins placed above the FROM clause\u0027s join tree, so the subquery\nfilters the joined result. Add a logical rule, like Spark\u0027s\nPushDownLeftSemiAntiJoin, that moves them below passthrough projections,\ninner joins and the preserved side of outer joins, onto the input that\nholds their keys. TPC-H q18 then filters orders down to the qualifying\norders before joining lineitem.\n\nThe rule stops at two places where the move is sound but slower:\n\n- A Filter. The semi join should see the filter\u0027s output: TPC-H q4\u0027s\n  EXISTS probes 5.7M filtered orders instead of all 150M (3.3 s to\n  9.6 s at SF100 when it did not).\n- A join whose other input is filtered. That join can remove most rows\n  itself, so a semi join below it probes rows it would have dropped.\n  TPC-H q21\u0027s EXISTS and NOT EXISTS moved onto all 379M l1 rows at\n  SF100, doubling its run time (32 s to 65 s).\n\nControlled by ballista.optimizer.semi_join_pushdown (default true).\n\n* perf: semi-join small filtered dimensions below the joins in between\n\nFor an inner join against a small dimension filtered by \u003d, IN or LIKE on\nliterals (a nation, region or part type), also semi-join the dimension\nwith the table the join key comes from, below the joins in between, so\nthe filter removes rows before they are joined and shuffled. This is\nthe effect of Spark\u0027s runtime filters. In TPC-H q7 supplier and customer\nare reduced to the two filtered nations before joining lineitem.\n\nLogical plans carry no statistics, so the scheduler runs the rule before\nphysical planning: candidates are found by shape, planned on their own\nto read their row estimate, and used only under\nballista.optimizer.broadcast_join_threshold_rows. A semi join that lands\non a tiny input (under 100K estimated rows, such as nation reduced by\nregion in q2/q5/q8) only adds a join, so it is removed again.\n\nUnlike SemiJoinPushdown, the reduction also sinks below joins with a\nfiltered input: the semi join is the selective side there.\n\nControlled by ballista.optimizer.semi_join_reduction (default true)."
    },
    {
      "commit": "714e23c3a454b88883b83207f208bd443e4742e6",
      "tree": "998ecc42f465216ab5dd3866f77db0d4d7edc9f3",
      "parents": [
        "7b6d7d3a6159177c2f5bac8f33a74c445da641d1"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Tue Nov 10 09:02:00 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 09:02:00 2026 +0000"
      },
      "message": "chore(deps): bump uuid from 1.29.0 to 1.29.1 in /python (#2831)\n\nBumps [uuid](https://github.com/uuid-rs/uuid) from 1.29.0 to 1.29.1.\n- [Release notes](https://github.com/uuid-rs/uuid/releases)\n- [Commits](https://github.com/uuid-rs/uuid/compare/v1.29.0...v1.29.1)\n\n---\nupdated-dependencies:\n- dependency-name: uuid\n  dependency-version: 1.29.1\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "7b6d7d3a6159177c2f5bac8f33a74c445da641d1",
      "tree": "3da25537ce86b804619df1d710968aac517ca868",
      "parents": [
        "13d8742043df5bec5a704d00d87c2389d2c4b12a"
      ],
      "author": {
        "name": "Ville Brofeldt",
        "email": "33317356+villebro@users.noreply.github.com",
        "time": "Tue Nov 10 00:16:28 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 00:16:28 2026 +0000"
      },
      "message": "test: share fixtures in the executor, history, result-service, flight-sql, cli and chaos tests (#2821)\n\n* test(executor): keep the work dir of the cancellation tests alive\n\nThe tests passed the path of a TempDir that was dropped at the end of the\nstatement, so the executor ran against a directory that no longer existed.\n\n* test(chaos): share the client wiring of the process and k8s runs\n\nFixture::connect writes the adaptive planner setting, registers the chaos\nUDFs and the fixture tables, and Fixture::local_sql runs a query in local\nDataFusion. ChaosRun and K8sRun both used hand-copied versions of them.\n\n* test(executor): share the executor and runtime producer fixtures\n\nexecutor::test_util provides fresh_runtime_producer and test_executor.\nThe tests of executor, execution_loop, runtime_cache and executor_process\nbuilt the same default-RuntimeEnv producer closure by hand, and the\nexecutor tests repeated the ExecutorRegistration, default config producer\nand Executor::new_basic setup. concurrent_tasks stays a parameter of\ntest_executor because the pipelined sizing test uses 4 and the others 2.\n\nNo test is added or removed.\n\n* test(history): share the event records of the writer, reader and schema tests\n\nhistory::test_util provides job_start, job_index and job_end. event,\nwriter and reader each built their own JobEnd; the writer repeated the\nsame JobStart literal three times and carried one JobEnd inline that\nduplicated its succeeded_job_end helper. The shared JobEnd has a job\npayload naming a ProjectionExec (asserted by the reader tests) and a\nconfig with the single entry k \u003d v, which the schema round-trip test\nused. No assertion read the other values that differed between the\ncopies (queued, started and completed times, index start and end times,\nconfig).\n\nThe golden-v1 tests and testdata/schema-v1.eventlog are untouched. No\ntest is added or removed.\n\n* test(result-service): share the FetchPartition action of the unit tests\n\nThe metered backend tests and the lib tests built the same\nAction::FetchPartition (job \"job\", stage 1, partition 0, executor:50051).\nresult_service::test_util::fetch_partition_action replaces both. No test\nasserts those values.\n\nThe FetchPartition in the flight-sql service tests has values that its\nassertions read and is not shared. No test is added or removed.\n\n* test(flight-sql): reuse the executor metadata of the fake scheduler backend\n\nThe fake backend built the same ExecutorMetadata twice in execute: once\nas a variable for the pipelined partitions and once inline for the\nfetch-based partitions. The second site now clones the variable. The\nassertions on the host executor-host and port 50051 are unchanged. No\ntest is added or removed.\n\n* test(cli): share the executor, job and stages popup fixtures of the tui tests\n\ntui::domain::test_util provides make_executor, make_job, make_stage and\nmake_popup. app and the executors, jobs and stages tests each built the\nsame Executor (including a ten-line OsInfo), the same Job, and a\nJobStagesPopup over stages.\n\nThe executor of the app tests now carries two memory metrics with value\n0 instead of an empty list; none of the app tests read the metrics. The\npopup of the app tests is make_popup(0), which is the same popup over no\nstages as before. The remaining local make_job and make_executor in the\napp tests only fix the arguments that the app tests do not vary.\n\nNo test is added or removed.\n\n* test(cli): document the shared tui test helpers\n\n* docs: describe the shared crates test fixtures\n\n* test: make job_index private and document make_stage\n\n* chore: re-run CI"
    },
    {
      "commit": "13d8742043df5bec5a704d00d87c2389d2c4b12a",
      "tree": "71e107968ffd07cf0ade95c2da3ad66935ae4669",
      "parents": [
        "f0da3a20cbbc85c9be7dddb0be6d265fea218da9"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 10 00:16:04 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 10 00:16:04 2026 +0000"
      },
      "message": "fix(python): use a non-default codec in the shuffle compression setter test (#2829)\n\nCo-authored-by: sim \u003csim@example.com\u003e"
    },
    {
      "commit": "f0da3a20cbbc85c9be7dddb0be6d265fea218da9",
      "tree": "6cafb1e55c2bce161505f77a9eaa431815239ae6",
      "parents": [
        "1c675a216de0bd5dcef2eebf49b8a39b51e73c40"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Mon Nov 09 21:35:48 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 09 21:35:48 2026 +0000"
      },
      "message": "perf: deduplicate executor metadata in partition locations (#2813)\n\n* perf: deduplicate executor metadata in partition locations\n\nEvery PartitionLocation held its own copy of the executor\u0027s full\nExecutorMetadata, although readers only use its id, host and port. A\nstage reading many partitions from a few executors repeated the same\nstrings once per location, in scheduler and executor memory and in the\ntask plans sent over gRPC.\n\nLocations now hold a shared Arc\u003cExecutorEndpoint\u003e with just those three\nfields. Shuffle reader plan nodes list each executor once and their\nlocations refer to it by position, which changes the scheduler-executor\nwire format, so BALLISTA_PROTOCOL_VERSION goes to 4. Job statuses still\ncarry the executor on each location, so clients are unchanged.\n\n* refactor: share pipelined executor endpoints and tidy their tests\n\nPipelined placement now creates one endpoint per executor rather than\none per producer task. The executor table uses a faster hasher, since it\nis looked up once per location, and the codec tests reuse the shared\nfixtures and compare endpoints directly. The upgrade guide now says how\nto migrate code that used the old field type.\n\n---------\n\nCo-authored-by: sim \u003csim@example.com\u003e"
    },
    {
      "commit": "1c675a216de0bd5dcef2eebf49b8a39b51e73c40",
      "tree": "c14e8bfbd56cdc93ad8b7bfb8078c71502afdafa",
      "parents": [
        "10fd9325b98b9ad8c5f73c99d11cfd6887c9d530"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Mon Nov 09 20:51:37 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 09 20:51:37 2026 +0000"
      },
      "message": "fix(client): report an unreadable first block of a shuffle fetch as a fetch failure (#2812)\n\nA block-transport fetch whose connection broke before the first block arrived surfaced as a plain IpcError. Only GrpcActionError becomes FetchFailed, so the task failed the job instead of re-running the map stage that produced the input.\n\nCo-authored-by: sim \u003csim@example.com\u003e"
    },
    {
      "commit": "10fd9325b98b9ad8c5f73c99d11cfd6887c9d530",
      "tree": "eaccff8264deb95041845c634ca0af08c98f7c9f",
      "parents": [
        "2580b60f64873f8ed722276d8d84ee3c0328a151"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Mon Nov 09 14:27:21 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 09 14:27:21 2026 +0000"
      },
      "message": "fix(ci): quote the labeler trigger\u0027s echo so YAML keeps the whole command (#2822)\n\nAn unquoted ` #` starts a YAML comment, so the run step was truncated to\n`echo \"Labels for pull request` and failed with an unterminated quote.\n\nCo-authored-by: sim \u003csim@example.com\u003e"
    },
    {
      "commit": "2580b60f64873f8ed722276d8d84ee3c0328a151",
      "tree": "d6d451048581971bb7c9d1eb8898659909ef02a4",
      "parents": [
        "7fbf57d45723b4bdf6f7cc2c93de97018d7c9b44"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Mon Nov 09 09:08:28 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 09 09:08:28 2026 +0000"
      },
      "message": "chore(ci): bump the github-codeql group with 2 updates (#2823)\n\nBumps the github-codeql group with 2 updates: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).\n\n\nUpdates `github/codeql-action/init` from 4.39.2 to 4.39.3\n- [Release notes](https://github.com/github/codeql-action/releases)\n- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/github/codeql-action/compare/1fc58d04a4d4374f921bdac573c3811c240f9c26...33d7b85da1a04171e211befe2c739303b9a4c066)\n\nUpdates `github/codeql-action/analyze` from 4.39.2 to 4.39.3\n- [Release notes](https://github.com/github/codeql-action/releases)\n- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/github/codeql-action/compare/1fc58d04a4d4374f921bdac573c3811c240f9c26...33d7b85da1a04171e211befe2c739303b9a4c066)\n\n---\nupdated-dependencies:\n- dependency-name: github/codeql-action/init\n  dependency-version: 4.39.3\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n  dependency-group: github-codeql\n- dependency-name: github/codeql-action/analyze\n  dependency-version: 4.39.3\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n  dependency-group: github-codeql\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "7fbf57d45723b4bdf6f7cc2c93de97018d7c9b44",
      "tree": "bcee98fa9064a6119e32c6fbd1d41cc02f047cae",
      "parents": [
        "781b4e51cfb6b1afddf584d07583d5d7a17a1957"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Mon Nov 09 09:08:00 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 09 09:08:00 2026 +0000"
      },
      "message": "chore(ci): bump taiki-e/install-action from 2.90.0 to 2.90.2 (#2824)\n\nBumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.90.0 to 2.90.2.\n- [Release notes](https://github.com/taiki-e/install-action/releases)\n- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/taiki-e/install-action/compare/b80e2bb2635f28eb98b9fce1e2f0887e1535c6b2...3a3daafd3b7f23b8f65d9f5ba2db203fb59b79e2)\n\n---\nupdated-dependencies:\n- dependency-name: taiki-e/install-action\n  dependency-version: 2.90.2\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "781b4e51cfb6b1afddf584d07583d5d7a17a1957",
      "tree": "f5175841757fb62a78c77beda743d9840f53b4f9",
      "parents": [
        "04455a1640fc06913aab5202e76648e612cd492d"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Mon Nov 09 09:07:22 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 09 09:07:22 2026 +0000"
      },
      "message": "chore(deps): bump blake3 from 1.8.5 to 1.8.7 (#2825)\n\nBumps [blake3](https://github.com/BLAKE3-team/BLAKE3) from 1.8.5 to 1.8.7.\n- [Release notes](https://github.com/BLAKE3-team/BLAKE3/releases)\n- [Commits](https://github.com/BLAKE3-team/BLAKE3/compare/1.8.5...1.8.7)\n\n---\nupdated-dependencies:\n- dependency-name: blake3\n  dependency-version: 1.8.7\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "04455a1640fc06913aab5202e76648e612cd492d",
      "tree": "591bb21d35ae42fa713ba4ab417ab7d978b2a34c",
      "parents": [
        "5ea37812eace1dd0f0ff76fd3b3e6db3fba59059"
      ],
      "author": {
        "name": "Ville Brofeldt",
        "email": "33317356+villebro@users.noreply.github.com",
        "time": "Sun Nov 08 20:59:15 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 20:59:15 2026 +0000"
      },
      "message": "test(scheduler): share plan, graph and server fixtures in the scheduler tests (#2819)\n\n* test(core): add TPCH_TABLES next to tpch_schema\n\nThe scheduler test utilities and the tpch benchmark each listed the same\neight table names.\n\n* test(scheduler): share plan and partition location fixtures\n\nBuild the execution graphs in scheduler test_utils from one\ngraph_from_logical helper, and expose the id/gmv aggregation logical plan\nthat seven test modules wrote out by hand. Add mock_partition_location to\nthe aqe tests for the blank partition locations they repeated, and use\nTPCH_TABLES from ballista-core in the scheduler test utils and the tpch\nbenchmark.\n\n* test(scheduler): share scheduler server and job status assertions\n\nAdd test_scheduler_server helpers for the twelve tests that built and\ninitialised a scheduler server by hand, check job status through one\nassert_status in JobStateTest instead of four copies, and drop an unused\nvector from mock_failed_task.\n\n* test(scheduler): build the scheduler test harness once\n\n`SchedulerTest::new` and `new_with_launcher` shared most of their body.\nBoth now go through one `build`, and the executor registration is the\n`register_virtual_executor` helper that takes an `ExecutorManager`, so\nthe four inline copies in state/mod.rs call it too.\n\n- `new_with_launcher` pins the static planner like `new`. Its only\n  caller, `deterministic_launch_rejection_fails_job`, turns the adaptive\n  planner back on so it keeps running under the default planner.\n- `SchedulerTest::run` takes the status receiver on the first call only,\n  so one harness can run several jobs.\n- `RejectOne` in state/mod.rs is replaced by\n  `RejectingTaskLauncher::only(job)`; the two uses that rejected a job\n  that never exists use `BlackholeTaskLauncher`.\n- `static_session_config` builds the static-planner session config.\n\nNo test is added or removed.\n\n* test(scheduler): share assertion, status and plan fixtures of the server tests\n\nThe tests of the scheduler server, and the tests elsewhere that build\ntask statuses, share these fixtures from test_utils:\n\n- `assert_event` and `assert_no_event` replace the five per-event\n  assertion helpers, and `assert_job_failed`, `assert_job_successful` and\n  `assert_subscriber_saw` replace the status and subscriber checks that\n  were written out in each test. The old helpers passed their format\n  string as an argument (`assert!(found, \"{}\", \"...{job_id}\")`), so the\n  job id was never interpolated; the new messages interpolate it and name\n  the case.\n- `successful_task_status`, `execution_failure`, `fetch_partition_failure`\n  and `failed_statuses` build task statuses, and `failing_task_runner`\n  builds a runner that fails every task. They back the default task\n  runner, `mock_completed_task` and the failing runners.\n- `ExplodingTableProvider` and `PanickingTableProvider` become the two\n  variants of `ExplodingTableProvider`.\n\nThe scheduler server tests start their schedulers through\n`push_scheduler` and `pull_scheduler`, submit physical plans through\n`submit_physical_plan`, and check runs with `assert_completed_run` and\n`assert_failed_run`.\n\nNo test is added or removed.\n\n* test(scheduler): share graph, task and plan fixtures\n\nFixtures that were copied across the scheduler\u0027s tests move to\ntest_utils:\n\n- `fetch_partition_failure` and `execution_failure` replace the 12\n  field-for-field `FailedTask` literals and two `ExecutionError` literals\n  in execution_graph.rs; `failing_task_runner` replaces the hand-written\n  failing runner in pipelined_graph.rs.\n- `drain_tasks` and `drain_tasks_with_executor` replace the copies in\n  execution_graph.rs, cluster/test_util and task_manager.rs.\n- `join_aggregate_sort_logical_plan` is the join, aggregate and sort plan\n  that `test_join_plan` and the task manager test built separately.\n- `graph_from_physical` and `pipelined_graph_from_physical` replace the\n  graph constructor calls with the same job, session and scheduler\n  arguments in pipelined_graph.rs, task_manager.rs and execution_graph.rs.\n- `PassThroughExec` replaces `FailingPlanRewriteExec`. It takes the name\n  it displays and whether `with_new_children` fails, so a plan that needs\n  an opaque operator under a different name can use it too;\n  `fail_plan_rewrites` keeps working for its callers.\n- `SchedulerTest::await_free_vcores` and `await_job_status` replace the\n  hand-rolled `await_condition` loops in pipelined_graph.rs.\n\n`test_job_planning_failure` only read the job id of the graph it was\ngiven, so it takes a `\u0026JobId` and test_in_memory_job_planning_failure\ncalls it once instead of building three graphs. memory.rs builds its job\nstate and its `id123` executor metadata through two helpers.\n\nNo test is added or removed.\n\n* test(scheduler): share executor registration and scheduler server fixtures\n\n- `executor_registration` replaces the five `ExecutorRegistration`\n  literals and `exec_meta_with_version` in grpc.rs; the same helper backs\n  the registration in query_stage_scheduler.rs.\n- `test_scheduler_server_uninit` replaces the scheduler server\n  construction in handlers.rs, openapi.rs and grpc.rs, health.rs and\n  query_stage_scheduler.rs build their servers through\n  `test_scheduler_server`, which builds on it, and\n  `test_scheduler_server_with_metrics` goes away with its last caller.\n- `assert_registered` replaces the executor assertions repeated six times\n  in grpc.rs, and `scheduler_for_protocol_test` was the same as\n  `test_scheduler`.\n- query_stage_scheduler.rs builds its task statuses with\n  `successful_task_status`, its session configuration with\n  `static_session_config`, and waits for job states with\n  `SchedulerTest::await_job_status`.\n\nNo test is added or removed.\n\n* test(scheduler): plan broadcast test queries through one helper\n\nThe broadcast tests in planner.rs repeated the steps from SQL to query\nstages: optimize, create the physical plan, plan the stages. They call\n`stages_for_sql` instead.\n\nThe failing runners of the cache linker tests use `failing_task_runner`,\n`execution_failure`, `fetch_partition_failure` and `failed_statuses`.\n\nNo test is added or removed.\n\n* test(scheduler): wait for the history refresh with await_condition\n\nThe history refresh test waits for the refresh task to index the new job\nwith `await_condition` instead of its own polling loop.\n\nNo test is added or removed.\n\n* test(scheduler): share the planner constructors and coalesce fixtures of the aqe tests\n\nAdd AdaptivePlanner::from_physical_sql and from_logical_sql to the aqe test\nmodule and use them where a test planned a query and built a planner by hand.\nThe physical path still skips the preparation rules and the logical path still\nruns them. Move coalesce_context, register_partitioned_table and\npartitions_with_byte_sizes next to the other aqe fixtures, build the\ncoalesce-tuned context of the physical submission tests from coalesce_context,\nand build contexts with SessionContext::new_with_config instead of a\nSessionStateBuilder chain that does the same.\n\n* test(scheduler): record embedder rules with one shared fixture\n\nThe adaptive_rules and physical_submission tests each defined the same Seen,\nRecording and Embedder trio. Define one in the aqe test module that records\nthe preparation rule\u0027s input flags and the replan rule\u0027s measured rows, and\noptionally holds back stages that have not run. Both test files use it; their\nassertions are unchanged.\n\n* test(scheduler): build statistics-only leaves with shared helpers\n\nAdd statistics_exec and unknown_statistics_exec to the aqe test module and use\nthem, together with the declared-statistics constructors of the stats table\nfixture, wherever a test built a DataFusion StatisticsExec by hand: the\nchaos_exec, distributed_exchange, propagate_empty, dynamic_join and\njoin_selection rule tests and the plan_to_stages test. The leaves are the same\nStatisticsExec with the same statistics, so plan text is unchanged. The\ndynamic_join tests use the shared MB constant.\n\n* test(scheduler): scan the alter_stages fixtures with StatsExec\n\nMockPartitionedScan declared the same plan properties and statistics as the\nStatsExec of the stats table fixture: unknown partitioning, incremental\nemission, bounded, no children, and the whole declared statistics for every\npartition. Add StatsExec::new, build the small and big scans from it, and\ndelete MockPartitionedScan. The big and small statistics come from\nsized_statistics, and the big_col schema is built once.\n\nSeventeen plan snapshot lines in alter_stages change from\n\u0027MockPartitionedScan: num_partitions\u003d2, statistics\u003d[...]\u0027 to\n\u0027StatsExec: partitions\u003d2, rows\u003dExact(..), bytes\u003dExact(..)\u0027. The per-column\nstatistics text that MockPartitionedScan printed is no longer shown; the tests\ndo not read it. create_big_and_small_statistic_scan is dropped; its small\nscan was never used.\n\n* test(scheduler): use the shared pass-through exec and join plan in the aqe tests\n\nOpaqueExec and the join, aggregate and sort logical plan of the adaptive\ngraph tests had the same shape as FailingPlanRewriteExec and the plan\nbuilt by the static graph tests.\n\n* test(scheduler): narrow the visibility and document two test helpers\n\n* docs: describe the shared scheduler test fixtures\n\n* docs: give general rules for where test fixtures go\n\nReplace the list of each crate\u0027s shared fixtures with the rules for where a\nfixture goes, which do not need updating when a helper is added or renamed.\n\n* test(scheduler): name ExplodingTableProvider in its panic message\n\n* test(scheduler): keep the join knobs out of the physical submission context\n\nphysical_context built on coalesce_context, which also turns hash joins off.\nThe coalesce knobs are now coalesce_config, which coalesce_context extends\nwith the join knobs. physical_context and the sort-merge join coalesce test\nbuild on coalesce_config, so physical_context is again the config it had\nbefore the fixtures were shared, and a join test added there plans as it\nwould by default."
    },
    {
      "commit": "5ea37812eace1dd0f0ff76fd3b3e6db3fba59059",
      "tree": "890b946e7754cad78d330b91e85496b615ba78dc",
      "parents": [
        "23c3372fd2084d030d44b96998d85696628556b1"
      ],
      "author": {
        "name": "goingforstudying-ctrl",
        "email": "goingforstudying@gmail.com",
        "time": "Sun Nov 08 20:58:54 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 20:58:54 2026 +0000"
      },
      "message": "Bound the executor pool\u0027s shared connections (#2779)\n\n* fix(executor): bound the shared side of the client pool\n\nThe shared connection slots never shrank: discard cleared the\nconnection but left its slot in the map until an eviction pass, live\nconnections had no idle timeout at all, and a connect that raced an\neviction pass landed in a detached slot later callers couldn\u0027t see.\n\nDiscard now drops the slot eagerly through a hook on SharedClient,\nbut only when the slot still holds that exact connection. Eviction\nretires shared connections that haven\u0027t been handed out within\nidle_timeout (in-flight streams keep their channel; only the pool\nlets go). shared() re-attaches its slot when eviction removed it\nmid-connect, deferring to another slot that already reconnected.\n\n* Test pipelined streams across shared pool eviction\n\nVerify a real pipelined Flight stream reaches EOF after the pool drops its last client handle. Release the discard-hook mutex before calling the Send-only hook and clarify pool ownership, expiry, and detached-slot lifetimes.\n\n* Keep shared reconnects on one pool slot\n\nRemove the eager discard hook and its public API so retry bursts share the existing connection lock. Reconcile cached handouts after eviction, pair live connections with required handout timestamps, and document long-running stream overlap.\n\nCover discarded-slot eviction, serialized reconnects and detached waiters. Use a longer idle timeout with explicitly aged stale entries."
    },
    {
      "commit": "23c3372fd2084d030d44b96998d85696628556b1",
      "tree": "a926188480f3779acfc6ac7bf477cd7d3755c1cd",
      "parents": [
        "fd8b371a059c8ca7f18bd4a3014f328e3839e977"
      ],
      "author": {
        "name": "Mason Kong",
        "email": "349702077+codekongdev@users.noreply.github.com",
        "time": "Sun Nov 08 20:58:53 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 20:58:53 2026 +0000"
      },
      "message": "ci: label pull requests from workflow_run instead of pull_request_target (#2778)\n\nGitHub blocks the pull_request_target trigger by default on public\nrepositories from December 2, 2026, and ASF infra is disabling it for ASF\nrepositories. The Labeler workflow (dev_pr.yml) runs on that trigger.\n\nSplit it in two:\n\n- dev_pr_trigger.yml runs on pull_request with no permissions and does\n  nothing. Its completion starts the labeler.\n- dev_pr.yml runs on workflow_run from the default branch with\n  pull-requests: write. It looks up the open pull requests whose head\n  repository, branch and commit match the triggering run, and passes\n  them to actions/labeler through its pr-number input. Nothing from the\n  pull request is checked out or run, and no artifact is read.\n\nCloses #2773.\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "fd8b371a059c8ca7f18bd4a3014f328e3839e977",
      "tree": "f7b5f6bc5a7e2cf157144aab0f763a93f806cca8",
      "parents": [
        "fd94ccff6e5eabb350e2b68154283a6bda460877"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Sun Nov 08 17:35:38 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 17:35:38 2026 +0000"
      },
      "message": "perf: default the shuffle compression codec to zstd (#2805)\n\n* test: round-trip sort shuffle output from several spilling inputs\n\nThe existing multi-input test never spilled, so nothing checked that each\noutput partition\u0027s range stitches every input\u0027s spill and in-memory bytes\ntogether in order. Run it again with a tiny buffer budget so every input\nspills several times and keeps an in-memory remainder.\n\n* perf: close sort shuffle spill writers after each spill event\n\nThe spill manager kept one IPC writer open per spilled output partition\nuntil the task finished, each holding a file descriptor and its own\ncompression context outside the memory pool. With hundreds of output\npartitions that is hundreds of open files per input partition and, with\nzstd, hundreds of megabytes of compressor state. Write each spill event as\none complete stream appended to the partition\u0027s file and close it; readers\nalready cross concatenated streams.\n\n* refactor: share IPC stream encoding between spill and final write\n\nAddress review feedback: spill and the in-memory encode now call one\nwrite_ipc_stream helper, SpillManager builds its IpcWriteOptions once,\nderives spill paths from partition_counters instead of a duplicate map,\nand the single-batch spill() wrapper is removed (tests call\nspill_batches).\n\n* perf: default the shuffle compression codec to zstd\n\nzstd writes shuffle data at roughly half the size of lz4 (about 8 bytes\nper row against 16 for TPC-H lineitem\u0027s shuffled columns) for little\nextra CPU. Shuffles that cross the network get correspondingly faster,\nand smaller files also cut local disk and page-cache traffic. lz4 stays\navailable through ballista.shuffle.compression.codec.\n\n* perf: use zstd level 1 for shuffle compression\n\nArrow defaults zstd to level 3. Level 1 keeps nearly all of the size\nreduction over lz4 for noticeably less CPU: writing 60M TPC-H lineitem\nrows into 200 sort shuffle partitions produced 2.55 GB at level 1 and\n2.50 GB at level 3 (lz4: 4.29 GB), with level 1 writing 7-10% faster.\nThe pipelined Flight serve path now builds its options through\ncreate_write_options so it uses the same level.\n\n---------\n\nCo-authored-by: sim \u003csim@example.com\u003e"
    },
    {
      "commit": "fd94ccff6e5eabb350e2b68154283a6bda460877",
      "tree": "2437787d526a8876791d0f5ad19005753986b2cf",
      "parents": [
        "e4a99666771c7fb84f1ae9566105740cd1d33104"
      ],
      "author": {
        "name": "Samuel James",
        "email": "samuel7james@gmail.com",
        "time": "Sun Nov 08 15:44:18 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 15:44:18 2026 +0000"
      },
      "message": "fix(scheduler): fail to start when event_log_dir is not writable (#2787)\n\n* fix(scheduler): fail to start when event_log_dir is not writable\n\nThe event-log writer creates the directory on its own task and only logs\na warning when that fails, so the scheduler ran without event logs. Add\nballista_history::writer::check_log_dir, which creates the directory and\na file in it, and call it from SchedulerServer::init so the scheduler\nreturns an error naming the directory instead.\n\n* fix(history): give each event_log_dir write check its own probe file\n\nThe probe was named by pid only, and schedulers in containers all run\nas pid 1, so two starting against one shared directory could remove each\nother\u0027s probe. Name it by pid, time and a counter, and create it with\ncreate_new. Add a concurrent test and an upgrade note for the new\nSchedulerServer::init error."
    },
    {
      "commit": "e4a99666771c7fb84f1ae9566105740cd1d33104",
      "tree": "2d439b91a887a739dd1f16b53b72cb575d36deb2",
      "parents": [
        "d49c848e519afddd7fb6f7525303a3f033f94c3e"
      ],
      "author": {
        "name": "ZIHAN DAI",
        "email": "99155080+PDGGK@users.noreply.github.com",
        "time": "Sun Nov 08 15:43:10 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 15:43:10 2026 +0000"
      },
      "message": "fix(scheduler): free intermediate shuffle files when an adaptive job succeeds (#2753)\n\nThe immediate reclaim of intermediate shuffle data on job success picks\nstages with `intermediate_stage_ids()`, whose default implementation treats\na stage with no `output_links` as final. The adaptive graph creates every\nstage without output links, so under AQE no stage was reported as\nintermediate and the shuffle files stayed on the executors until the\ndelayed whole-job cleanup.\n\nOverride `intermediate_stage_ids()` for `AdaptiveExecutionGraph`: a stage\nis final when the job\u0027s `output_locations` point at it, and every other\nstage is intermediate. Nothing is reported until `output_locations` is\nset, so a final stage is never returned.\n\nCloses #1996."
    },
    {
      "commit": "d49c848e519afddd7fb6f7525303a3f033f94c3e",
      "tree": "5f77045d0ab59baec9425435a25c6011b7be09be",
      "parents": [
        "070ae9157559ce57f3a5166b99fd0ddf1c4ca65f"
      ],
      "author": {
        "name": "Samuel James",
        "email": "samuel7james@gmail.com",
        "time": "Sun Nov 08 15:42:52 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 15:42:52 2026 +0000"
      },
      "message": "fix(executor): bound each scheduler connect attempt by the deadline (#2715)\n\nThe retry loop only checked scheduler_connect_timeout_seconds between\nattempts, so a single endpoint.connect() to a host that drops packets\ncould run for the full gRPC connect timeout (20s by default) past it.\nWrap each attempt in tokio::time::timeout_at with the same deadline."
    },
    {
      "commit": "070ae9157559ce57f3a5166b99fd0ddf1c4ca65f",
      "tree": "c3145265eb8b2991cf71078b1748180f5e76b388",
      "parents": [
        "d94a2792e7a8637121423d7dbeab42075a563819"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Sun Nov 08 15:15:31 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 15:15:31 2026 +0000"
      },
      "message": "docs: add AGENTS.md and a pr-review agent skill (#2789)\n\nAdd a concise AGENTS.md that points agents at the user guide and\ncontributor guide, and add a pr-review skill under .ai/skills that does\na correctness and test review plus the Ballista persona, public API and\nbenchmark checks."
    },
    {
      "commit": "d94a2792e7a8637121423d7dbeab42075a563819",
      "tree": "071aece2f1496d7c6fc22508697e6f6aca156b6d",
      "parents": [
        "76584d0e651707a5784f7db90ba37319e0d2ab26"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Sun Nov 08 15:00:18 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 15:00:18 2026 +0000"
      },
      "message": "docs: refresh the README and the architecture diagram (#2815)\n\n* docs: refresh the README and the architecture diagram\n\nAdd a feature list and bring the project status up to date, describe\nBallista as an alternative to Spark as well as a way to distribute\nDataFusion applications, and replace the architecture diagram with one\nthat shows the current clients, interfaces and data paths.\n\n* docs: drop excalidraw from the architecture diagram filename\n\nThe diagram is a hand-written SVG with no embedded Excalidraw scene, so\nthe .excalidraw.svg extension is misleading.\n\n---------\n\nCo-authored-by: sim \u003csim@example.com\u003e"
    },
    {
      "commit": "76584d0e651707a5784f7db90ba37319e0d2ab26",
      "tree": "8f71c78a3d667af93dfb42a6ca6e0f2414bbcce2",
      "parents": [
        "616ce8cf38f47f3068d180b53b2612815ed05d46"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Sun Nov 08 10:36:39 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 10:36:39 2026 +0000"
      },
      "message": "fix: keep aggregates above undecided joins partial and final (#2806)\n\nAn undecided AQE join (DynamicJoinSelectionExec) reported the\npartitioning of the join it was planned as. A CollectLeft join passes\nits right input\u0027s partitioning through, so a join planned with a\none-partition table such as nation on the right reported one partition,\nalthough the join it resolves into may build nation and output the\nother side\u0027s partitions. Meanwhile DataFusion\u0027s CombinePartialFinal-\nAggregate saw an aggregate over one partition and merged it into a\nSingle aggregate, which later replans cannot split. Once the join\nresolved, the aggregate\u0027s input was coalesced and exchanged below it,\nso every task of the consuming stage read and aggregated the whole\ninput: TPC-H q11\u0027s scalar sum read all 32M rows in each of 16 tasks at\nSF1000 with 256 partitions.\n\nReport at least as many partitions as the widest input until the join\nis decided.\n\nCo-authored-by: sim \u003csim@example.com\u003e"
    },
    {
      "commit": "616ce8cf38f47f3068d180b53b2612815ed05d46",
      "tree": "81b084ee5185d9236b42577ce5561a844707bd36",
      "parents": [
        "781f4ee97c193986dcd44a209fde98e82219ac7d"
      ],
      "author": {
        "name": "Ville Brofeldt",
        "email": "33317356+villebro@users.noreply.github.com",
        "time": "Sun Nov 08 09:37:00 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 09:37:00 2026 +0000"
      },
      "message": "test(core): share execution plan test fixtures (#2800)\n\n* test(core): share execution plan test fixtures\n\nCollect the test inputs that several execution plan modules each defined\nfor themselves: the two-by-two shuffle writer input, the per-partition\nresult driver (now generic over the writer), the one-column schema and\npartitioned source, the key/payload batch, a single-vcore test executor,\nand the range operators\u0027 schemas, batches, sort expressions and cuts.\n\n* test(core): build in-memory test plans with MemorySourceConfig::try_new_exec\n\n`MemorySourceConfig::try_new_exec` is `DataSourceExec::from_data_source`\nover `MemorySourceConfig::try_new`, the same plan the tests built by\nhand with `Arc::new(DataSourceExec::new(Arc::new(..)))`. Replace the\nplain wraps in the core unit tests and drop the `DataSourceExec`\nimports they no longer need.\n\nSites that call `try_with_sort_information` keep the explicit wrap.\n\n* test(core): share the Int32 `a` schema and batch fixtures\n\nAdd `int32_schema` and `int32_batch` to the execution plan test\nutilities and use them in place of the identical private copies in the\nspill, buffer, multi stream reader, pipelined registry, distributed\nquery, shuffle reader and unresolved shuffle tests, and for the schema\nof two serde tests. `test_util` is `pub(crate)` under `cfg(test)` so the\nserde tests can reach it.\n\nThe shuffle reader `int_batch` keeps its 1024 rows per value and builds\non `int32_batch`. The nullable and differently named Int32 schemas stay\nwhere they are.\n\n* test(core): share the Arrow IPC stream writers of the tests\n\nAdd `ipc_stream_bytes` and `write_ipc_stream` to the execution plan test\nutilities and use them where tests wrote an IPC stream by hand: the\nclient block stream tests, the range shuffle reader (which had its own\n`write_ipc_stream`), the shuffle reader local file writer, the ipc file\nformat detection test and the multi stream reader `append_stream`, which\nnow appends the bytes of one stream and returns their length.\n\n* test(core): share drain_concurrent between the range repartition tests\n\nThe ordered and unordered range repartition tests each had a\n`drain_concurrent` with the same skeleton: execute every output\npartition, collect each stream on its own task and join them in order.\nThey differed only in how a batch is turned into values. It is now one\ngeneric helper in `range_repartition_common::test_util` taking the\nextractor, together with the note on why the partitions have to be\ndrained concurrently. The two modules keep their extractors\n(`extract_rows`, `extract_ids`, `extract_keys`).\n\n* test(core): reuse drive_partition_results in the shuffle writer tests\n\n* test(core): build partition locations with test_location\n\nAdd `test_location(job, stage, partition)` to the execution plan test\nutilities: a location on `test_executor()` with default stats, no file\nid and the hash shuffle layout. Tests override what they assert on with\nstruct update syntax. It replaces the hand-written `PartitionLocation`\nliterals of the shuffle reader, range shuffle reader, range shuffle\nwriter and runtime stats tests.\n\nThe range shuffle tests keep `map_partition_id: partition` and, for the\nwriter, `file_id: Some(0)`. The literals in `get_test_partition_locations`\nstay: the executor id keys the per-address semaphore of the remote read\ntests and the host is the target of their connections.\n\nThe shuffle reader\u0027s four-location loop that three tests and the fetch\nerror mapping test repeated is now `four_partitions(stats)`, and the\nthree statistics tests build their reader with one helper.\n\n* test(core): narrow test_executor to its module and fix a doc sentence\n\n* docs: describe the shared core test fixtures\n\n* test(core): move the shared v schema and cuts out of the range test utilities\n\nrange_repartition_common::test_util also served the range filter and\nruntime stats tests through v_schema and cuts. Both now live in\nexecution_plans::test_util, and the two single-column v schemas are named\nafter their type: float64_v_schema and int64_v_schema (was one_col_schema).\nsession stays with the range repartition helpers, since only those tests use\nit.\n\n* test(core): document that drive_partition_results panics when a task panics"
    },
    {
      "commit": "781f4ee97c193986dcd44a209fde98e82219ac7d",
      "tree": "144f16ae336b1a48ba7a2051a6e0dd7535e9ed97",
      "parents": [
        "bf90879ad15146645c01a53711ffb3ff5acf8eac"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Sun Nov 08 09:03:17 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 08 09:03:17 2026 +0000"
      },
      "message": "fix: reschedule tasks that do not fit in a poll response (#2795)\n\nUnder pull scheduling the scheduler binds tasks, marking them running,\nbefore tonic encodes the PollWorkResult. When the response exceeds the\ngRPC encoding limit (many tasks with large plans, such as broadcast\nreaders listing every upstream location at 128 partitions) the executor\ngets an error, the tasks are never run, and the job hangs.\n\nSend only the tasks that fit and report the rest as killed, which\nre-queues their partitions without counting a failure. A single task\nlarger than the limit fails its job with an error naming the setting to\nraise."
    },
    {
      "commit": "bf90879ad15146645c01a53711ffb3ff5acf8eac",
      "tree": "71019cf28016f62952a6934bb9254733b8c04b22",
      "parents": [
        "810724f6ef30d31c5e58f9961d64e47b7d6467d9"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Sat Nov 07 17:32:55 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Nov 07 17:32:55 2026 +0000"
      },
      "message": "perf: disable Nagle\u0027s algorithm on scheduler connections (#2798)\n\nThe scheduler serves gRPC through axum, which, unlike tonic\u0027s own\nserver, leaves Nagle\u0027s algorithm on for accepted connections. A poll\nresponse is several small HTTP/2 frames, so the later ones wait for the\nexecutor\u0027s delayed ACK: about 40 ms per poll on Linux. Under pull\nscheduling that is added to every task launch, so a stage of N waves\npays N x 40 ms; TPC-H q2 at 128 partitions spent about 2 s of its 5.6 s\nwaiting. Set TCP_NODELAY on every accepted connection.\n\nThe standalone scheduler serves tonic from a pre-bound listener, which\nignores the builder\u0027s tcp_nodelay, so set it there too."
    },
    {
      "commit": "810724f6ef30d31c5e58f9961d64e47b7d6467d9",
      "tree": "c22b217e05090afe7ca96f13aad8fd42cbaef903",
      "parents": [
        "2ad5f37f55e1c020ef153b4251396cb21285bbeb"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Sat Nov 07 17:32:33 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Nov 07 17:32:33 2026 +0000"
      },
      "message": "fix: count buffers shared by sliced batches once in shuffle buffering (#2796)\n\nAggregates emit their output as one large array sliced into batch-size\npieces. The sort shuffle writer summed get_array_memory_size per\nbuffered batch, which counts the whole shared buffer for every slice,\nso after the first slice the 256 MiB per-task budget looked exceeded\nand the writer spilled on almost every batch: TPC-H q18\u0027s partial\naggregate stage spilled 1,145 times per input partition at SF100.\n\nUse DataFusion\u0027s RecordBatchMemoryCounter, which counts each buffer\nonce across batches, in the sort shuffle buffer. The counter is reset\nwhen the buffer is drained."
    },
    {
      "commit": "2ad5f37f55e1c020ef153b4251396cb21285bbeb",
      "tree": "26d43ef7600b6c79a213bffad21d59c57f0b04de",
      "parents": [
        "2597c57a0083956e12b29a593c6b345fa5aa648b"
      ],
      "author": {
        "name": "Ville Brofeldt",
        "email": "33317356+villebro@users.noreply.github.com",
        "time": "Sat Nov 07 16:43:57 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Nov 07 16:43:57 2026 +0000"
      },
      "message": "test(client): share integration test fixtures in tests/common (#2791)\n\n* test(client): share integration test fixtures in tests/common\n\nMove the orders/customers table writer and registration, the ballista\nsession state builder, the result formatting helpers, the SET helper and\nthe identical assert_result_eq into tests/common, and use them from the\npipelined, standalone_push_staged, reuse_exchange, coalesce, null_aware,\nparallel_window, sort_shuffle and context_basic tests. Resolve test data\nfrom the crate\u0027s own testdata directory instead of a copied\nDataFusion-style lookup, and keep a single rstest fixture for it.\n\n* test(client): add shared fixtures to tests/common and use them for orders\n\nAdds to tests/common the helpers the following commits adopt:\nregister_alltypes, alltypes_context and alltypes_parquet, the expected\nresults of the queries repeated over alltypes_plain.parquet,\ncheck_matches, write_parquet_file and orders_customers_dir.\n\nThe customers table is written as the directory customers/ of one file,\nlike orders, so both are registered through register_csv_tables.\nThe orders queries of pipelined.rs move to ORDERS_QUERIES; the\nstandalone push-staged tests run the first three, which they repeated.\n\nNo test is added, removed or renamed.\n\n* test(client): remove the unused single_nan.parquet\n\nNo file in the repository refers to it.\n\n* test(client): register alltypes and set options through the shared helpers\n\ncontext_checks, context_setup, context_unsupported and sort_shuffle\nregister alltypes_plain.parquet with register_alltypes instead of\nspelling out the path, and drop the test_data parameter where nothing\nelse used it. The repeated `id \u003e 4`, group-by and self-join queries and\ntheir results in context_checks and context_setup are constants in\ncommon. Raw `SET` statements in context_checks and context_cache go\nthrough set_option.\n\ncontext_setup builds its session states with state_with_config, and the\ntwo should_execute_sql_set_configs tests (remote and standalone) share\nthe state and the assertion. DataFusion\u0027s with_default_features does not\nread the config, so the builder order is not significant.\n\nNo test is added, removed or renamed.\n\n* test(client): remove duplicated setup from context_basic\n\ncreate_test_context becomes alltypes_context in common, the union test\nuses assert_result_eq for both results, and the two tests that write\ntimestamps.csv and create csv_with_timestamps (test_ballista_show_tables,\ntest_show_tables_not_with_information_schema) share\ncreate_timestamps_table.\n\nNo test is added, removed or renamed.\n\n* test(client): share the mismatch check of coalesce and null_aware\n\nBoth tests compared a query result with an expected table and collected\nthe difference with the same match; they call check_matches, which keeps\nthe label format and the trimmed comparison.\n\nNo test is added, removed or renamed.\n\n* test(client): write parquet fixtures through write_parquet_file\n\nprefix_window and partition_pruning write their input files with the\nshared helper. register_input and register_nullable_key_input in\nprefix_window differ only by schema, batches and table name, and now\nshare register_parts.\n\nThe raw SET in partition_pruning stays: set_option would panic on a\nfailed SET where the unpruned_scan_fails_on_poisoned_partition test\ncounts the error as the expected failure.\n\nNo test is added, removed or renamed.\n\n* test(client): loop over the tables of bug_1296\n\nThe four register_csv calls of bug_1296_basic differ by table name.\n\n* docs: describe the shared client test fixtures\n\n* test(client): escape single quotes in set_option values\n\nset_option wraps the value in single quotes, so a value containing one built\ninvalid SQL. It now doubles any single quote, the SQL escape for a quote in a\nstring literal.\n\n* test(client): note that standalone_push_staged runs the first three orders queries"
    },
    {
      "commit": "2597c57a0083956e12b29a593c6b345fa5aa648b",
      "tree": "269ae1a6da5c40a6f7bb438461385c23a2379ec0",
      "parents": [
        "9fedc4d0dff6dbb452bf90fc6b43edc80e5d50c9"
      ],
      "author": {
        "name": "Ville Brofeldt",
        "email": "33317356+villebro@users.noreply.github.com",
        "time": "Fri Nov 06 20:15:12 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Nov 06 20:15:12 2026 +0000"
      },
      "message": "fix(test): keep the join sides of the coalesce passthrough test as separate stages (#2790)\n\n* fix(test): read different columns on the two sides of the coalesce passthrough test\n\nshould_resolve_every_declared_partition_of_coalesced_passthrough_stage selects\ncount(*) from a join of t1 and t2. Projection pushdown leaves both scans reading\nonly the join key, and the tables hold the same data, so the two exchanges are\nthe same subplan. Since exchange reuse became enabled by default, the planner\nruns them as one shared stage and only one leaf stage is runnable, where the\ntest expects two.\n\nThe other join tests in the file select t1.a and t2.b, so their scans read\ndifferent columns and stay separate stages. The query now selects a column from\neach side too. The test is still a global aggregate over a join, with the same\nassertions, under the default configuration.\n\n* test(scheduler): cover coalescing the readers of a shared stage\n\nWith exchange reuse on, a query that reads the same data on both sides of a\njoin runs one stage for the two scans. Add a test that finalises that stage and\nchecks coalescing attaches the same coalesce plan to both readers and that the\njoin stage reads the coalesced partition count."
    },
    {
      "commit": "9fedc4d0dff6dbb452bf90fc6b43edc80e5d50c9",
      "tree": "d50fa3fcac564814dc12a82c3bc270f59acecff2",
      "parents": [
        "e97e2d8630027102f29ea93cd6ae55cf7901e7fd"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Fri Nov 06 16:16:41 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Nov 06 16:16:41 2026 +0000"
      },
      "message": "feat: run a repeated subplan\u0027s stage once under AQE (#2765)\n\n* feat: run a repeated subplan\u0027s stage once under AQE\n\nWhen a query reads the same subplan more than once, such as a common\ntable expression joined to itself or TPC-H q15\u0027s revenue view, the\nadaptive planner placed one exchange per copy and ran the subplan once\nper reader.\n\nAdd ReuseExchangeRule, the last rule of the AQE replan chain. It keys\neach exchange by the protobuf encoding of its subtree under the job\u0027s\nphysical extension codec, with nested exchanges encoded by what they\nwrite rather than by stage id, and makes every duplicate a reader of\none stage: the duplicate shares the stage id, shuffle partitions,\ncolumn statistics and range routing of the canonical exchange, and\nkeeps its own coalesce and skew-join decisions. The canonical exchange\nis one already resolved, else one already running, else the first met;\nan exchange running a stage of its own is never re-pointed. Volatile\nsubtrees and range-shuffled subtrees are never shared.\n\nidentify_runnable_stages now launches each stage id once, since every\nreader of a shared stage is found.\n\nThe rule is on by default and controlled by\nballista.planner.adaptive.reuse_exchange.\n\n* perf: key only exchanges a cheap fingerprint can\u0027t tell apart\n\nEncoding every exchange\u0027s subtree on every AQE replan costs the most\non plans that repeat nothing. Hash each subtree\u0027s one-line display,\nwith nested exchanges reduced to what they write, and encode only the\nexchanges whose hash repeats or whose stage handle is shared.\n\n* refactor: simplify exchange reuse and key each exchange once\n\nIntern keys and look them up by plan id and stage handle in the\nrewrite pass instead of encoding every candidate twice, fingerprint\nthe plan in one walk, match single-consumer operators by type rather\nthan by name, and dedupe runnable readers of a shared stage before\nthe stage loop.\n\n* fix: replan when exchange reuse resolves an exchange mid-chain\n\nReuseExchangeRule runs last in the replan chain. When it points a\npending exchange at a stage that has already finished, the exchange is\nresolved after the rules that react to a resolved exchange, such as\njoin selection, have run. The plan can then look runnable with a join\nstill undecided above that exchange, and the stage fails to serialize\nits DynamicJoinSelectionExec (TPC-DS q25, q64, q74).\n\nThe rule now raises a flag when it does that, and the planner runs the\nchain again, as it does when a stage finishes.\n\n* refactor: reuse exchanges when a stage launches instead of in a rule\n\nMatch a repeated stage in identify_runnable_stages against a cache of\nlaunched stages, as Spark\u0027s AQE stageCache does, rather than in a\nreplan rule. Each stage is keyed once, on the plan that runs, with the\nstages it reads encoded by stage id, so readers can no longer diverge\nafter being matched. A repeat of a finished stage is resolved and the\nplan replanned before anything launches.\n\nThis removes the fingerprint pass, the read_finished_stage flag and\nits pass cap, the diverged-reader split and with_own_stage. Rename the\nconfig to ballista.planner.reuse_exchange.enabled to match the other\nAQE rule toggles.\n\n* refactor: simplify launch-time exchange reuse and keep key digests\n\nKeep a 256-bit blake3 digest of each stage\u0027s encoding instead of the\nencoding itself, which runs to the size of the stage plan for every\nlaunched stage of the job. Check the stage for exclusions and stub the\nstages it reads in one walk, dropping ExchangeExec::as_key_leaf. Key the\nexchanges launching together in one loop, return before any setup when\nreuse is off, and count the plan\u0027s exchanges only when a replan needs\nthe bound.\n\n* chore: update python Cargo.lock for blake3 dependency"
    },
    {
      "commit": "e97e2d8630027102f29ea93cd6ae55cf7901e7fd",
      "tree": "a37442cd5c45c14ebc52fa7ab69ea39318313336",
      "parents": [
        "29a01ac66a5d82f3ce0f99946742fd7f92eb2486"
      ],
      "author": {
        "name": "Marko Milenković",
        "email": "milenkovicm@users.noreply.github.com",
        "time": "Fri Nov 06 15:08:55 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Nov 06 15:08:55 2026 +0000"
      },
      "message": "update installation section (#2788)"
    },
    {
      "commit": "29a01ac66a5d82f3ce0f99946742fd7f92eb2486",
      "tree": "022c89ed97d9e2c7d624017082fc77864d77f461",
      "parents": [
        "1afb351a5261e1eac8c00a7446f05fd1cdd6bba2"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Fri Nov 06 15:02:48 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Nov 06 15:02:48 2026 +0000"
      },
      "message": "chore(ci): bump taiki-e/install-action from 2.89.1 to 2.90.0 (#2786)\n\nBumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.89.1 to 2.90.0.\n- [Release notes](https://github.com/taiki-e/install-action/releases)\n- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/taiki-e/install-action/compare/682ce6c3c696a4cd5168a05f98e51aa02b877941...b80e2bb2635f28eb98b9fce1e2f0887e1535c6b2)\n\n---\nupdated-dependencies:\n- dependency-name: taiki-e/install-action\n  dependency-version: 2.90.0\n  dependency-type: direct:production\n  update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "1afb351a5261e1eac8c00a7446f05fd1cdd6bba2",
      "tree": "6bc6b77137290c6d6f58604e606e4906846af696",
      "parents": [
        "b497530ff77a7d72259a616be1ab79139b0987af"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Fri Nov 06 15:02:27 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Nov 06 15:02:27 2026 +0000"
      },
      "message": "chore(ci): bump the github-codeql group with 2 updates (#2785)\n\nBumps the github-codeql group with 2 updates: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).\n\n\nUpdates `github/codeql-action/init` from 4.39.1 to 4.39.2\n- [Release notes](https://github.com/github/codeql-action/releases)\n- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/github/codeql-action/compare/9b3254085494b55a0f7c4c2b3d2d52cc712ce370...1fc58d04a4d4374f921bdac573c3811c240f9c26)\n\nUpdates `github/codeql-action/analyze` from 4.39.1 to 4.39.2\n- [Release notes](https://github.com/github/codeql-action/releases)\n- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/github/codeql-action/compare/9b3254085494b55a0f7c4c2b3d2d52cc712ce370...1fc58d04a4d4374f921bdac573c3811c240f9c26)\n\n---\nupdated-dependencies:\n- dependency-name: github/codeql-action/init\n  dependency-version: 4.39.2\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n  dependency-group: github-codeql\n- dependency-name: github/codeql-action/analyze\n  dependency-version: 4.39.2\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n  dependency-group: github-codeql\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "b497530ff77a7d72259a616be1ab79139b0987af",
      "tree": "0ce06b12a454bcde5ea4489d1b9e6a07d75fb441",
      "parents": [
        "d56a2adacd28a03bf3166b8eb18f22be7f058df1"
      ],
      "author": {
        "name": "Marko Milenković",
        "email": "milenkovicm@users.noreply.github.com",
        "time": "Thu Nov 05 22:04:15 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Nov 05 22:04:15 2026 +0000"
      },
      "message": "feat(python): Add Python gRPC client with `BallistaPythonSessionContext` (#2754)\n\n* add python client\n\n* fix race in _pipelined\n\n* dev/update_datafusion_proto.py now regenerates\nthe Python gRPC stubs every time it updates the\nvendored protos\n\n* add a test showing that a SET ballista.* on\nthe session actually reaches the scheduler"
    },
    {
      "commit": "d56a2adacd28a03bf3166b8eb18f22be7f058df1",
      "tree": "27f458717ed861118793735bfda42a7c601b40e3",
      "parents": [
        "5e13d8223d28dab673d3da4f22523cbc2b24b2ba"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Thu Nov 05 21:22:49 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Nov 05 21:22:49 2026 +0000"
      },
      "message": "feat(aqe): coalesce shuffle partitions down to a single partition (#2782)\n\n* fix(aqe): keep sorted shuffles and passthrough widths intact when coalescing\n\nTwo cases go wrong when `CoalescePartitionsRule` packs a shuffle into\nmore than one but fewer than all of its partitions:\n\n- A shuffle whose input is sorted is read with a k-way merge per\n  partition. A coalesced reader concatenates a group\u0027s files instead,\n  so the `SortPreservingMergeExec` above it merged unsorted streams and\n  `ORDER BY` results came back out of order. The rule now leaves a\n  stage with a sorted leaf alone.\n- A passthrough stage whose input was coalesced writes fewer partitions\n  than its boundary declares, and the next stage\u0027s reader was built\n  from only those. When that stage did not coalesce too, its tasks\n  indexed past the reader\u0027s location lists and panicked (TPC-H q17 at\n  SF100). The stage now resolves every partition its boundary declares.\n\n* feat(aqe): coalesce shuffle partitions down to a single partition\n\n`CoalescePartitionsRule` skipped the rewrite whenever the bin-pack\nproduced a single group, so a stage whose whole input fits in\n`ballista.planner.coalesce.target_partition_bytes` still ran one task\nper upstream partition, most of them reading next to nothing. That is\nwhere coalescing saves the most: final aggregates, small joins and the\nsorts below an `ORDER BY` merge. Spark\u0027s `CoalesceShufflePartitions`\ncoalesces all the way down to one partition as well.\n\nA single group needs no new plan shape. The existing `CoalescePlan`\nexpresses it, and a `CoalescePartitionsExec` or\n`SortPreservingMergeExec` over one partition passes it through."
    },
    {
      "commit": "5e13d8223d28dab673d3da4f22523cbc2b24b2ba",
      "tree": "8dbf0fce9b48a3a395bb6055563e4058d5b67487",
      "parents": [
        "74c092437f262a51800323e28f304c50d9312f17"
      ],
      "author": {
        "name": "Marko Milenković",
        "email": "milenkovicm@users.noreply.github.com",
        "time": "Thu Nov 05 20:09:01 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Nov 05 20:09:01 2026 +0000"
      },
      "message": "feat(python): python project cleanup and s3 support for python cluster  (#2748)\n\n* cleanup of python docs\n\n* add s3 support and tests\n\n* document python udf trust model\n\n* address few comments\n\n* expose work dir for executor\n\n* add deprecation for `analyze\u003dTrue` in `explain_visual(df, analyze\u003dTrue)`\n\n* address `ballista_default_optimizer_rule()` comment\n\n* change 0.0.0.0 to 127.0.0.1\n\n* update deprecation section"
    },
    {
      "commit": "74c092437f262a51800323e28f304c50d9312f17",
      "tree": "7da714106dc9eb8f3599d55fdf57a4526c22de27",
      "parents": [
        "24003e1b88d7a1a3e42b350096eefa03f9984929"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Thu Nov 05 14:32:46 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Nov 05 14:32:46 2026 +0000"
      },
      "message": "chore(ci): bump taiki-e/install-action from 2.89.0 to 2.89.1 (#2777)\n\nBumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.89.0 to 2.89.1.\n- [Release notes](https://github.com/taiki-e/install-action/releases)\n- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/taiki-e/install-action/compare/1919c4a95903d2c33e4a221102edca87309fc14b...682ce6c3c696a4cd5168a05f98e51aa02b877941)\n\n---\nupdated-dependencies:\n- dependency-name: taiki-e/install-action\n  dependency-version: 2.89.1\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "24003e1b88d7a1a3e42b350096eefa03f9984929",
      "tree": "f5328c1c430631e8db80de3b843fb69fd27eac14",
      "parents": [
        "1aad53ce9b1a25c18d4f143a07be2995740191fb"
      ],
      "author": {
        "name": "Marko Milenković",
        "email": "milenkovicm@users.noreply.github.com",
        "time": "Thu Nov 05 14:17:31 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Nov 05 14:17:31 2026 +0000"
      },
      "message": "make it possible to disable propagate empty (#2776)"
    },
    {
      "commit": "1aad53ce9b1a25c18d4f143a07be2995740191fb",
      "tree": "1ffb14718c035a42327678011321843b3962095c",
      "parents": [
        "d7ef7b8520941bc88274fc4db1ef243220e287a2"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Wed Nov 04 08:53:45 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Nov 04 08:53:45 2026 +0000"
      },
      "message": "chore(ci): bump taiki-e/install-action from 2.88.1 to 2.89.0 (#2772)\n\nBumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.88.1 to 2.89.0.\n- [Release notes](https://github.com/taiki-e/install-action/releases)\n- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/taiki-e/install-action/compare/68a389c788b2cd04016ce8c80ee23b80d2ab3d68...1919c4a95903d2c33e4a221102edca87309fc14b)\n\n---\nupdated-dependencies:\n- dependency-name: taiki-e/install-action\n  dependency-version: 2.89.0\n  dependency-type: direct:production\n  update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "d7ef7b8520941bc88274fc4db1ef243220e287a2",
      "tree": "254ca42640babeb061d7e15396629f57b05e7165",
      "parents": [
        "cf4358eae48d60a916e78157f9a11cddb80faed3"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Wed Nov 04 08:53:22 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Nov 04 08:53:22 2026 +0000"
      },
      "message": "chore(deps): bump tonic-prost from 0.14.7 to 0.14.9 in /python (#2771)\n\nBumps [tonic-prost](https://github.com/grpc/grpc-rust) from 0.14.7 to 0.14.9.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-prost-v0.14.7...tonic-prost-v0.14.9)\n\n---\nupdated-dependencies:\n- dependency-name: tonic-prost\n  dependency-version: 0.14.9\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "cf4358eae48d60a916e78157f9a11cddb80faed3",
      "tree": "d4ad45b08cae4e96761779962121ad8a9238928e",
      "parents": [
        "963fa087f276f509a557fa5fb07f68b8c4012d08"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Wed Nov 04 08:53:00 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Nov 04 08:53:00 2026 +0000"
      },
      "message": "chore(deps): bump pyo3-log from 0.13.4 to 0.13.5 in /python (#2770)\n\nBumps [pyo3-log](https://github.com/vorner/pyo3-log) from 0.13.4 to 0.13.5.\n- [Changelog](https://github.com/vorner/pyo3-log/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/vorner/pyo3-log/compare/v0.13.4...v0.13.5)\n\n---\nupdated-dependencies:\n- dependency-name: pyo3-log\n  dependency-version: 0.13.5\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "963fa087f276f509a557fa5fb07f68b8c4012d08",
      "tree": "67d09025e9e32724ec2afb94d5ab24e75b1e3952",
      "parents": [
        "70a074322a974a90e9e832827f9998daa332321d"
      ],
      "author": {
        "name": "Marko Milenković",
        "email": "milenkovicm@users.noreply.github.com",
        "time": "Tue Nov 03 22:39:40 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 22:39:40 2026 +0000"
      },
      "message": "remove unused sys making ruff to fail (#2769)"
    },
    {
      "commit": "70a074322a974a90e9e832827f9998daa332321d",
      "tree": "a44ee8377123e0ac26787098a87f47e51893e2fa",
      "parents": [
        "4ccca3b8eabf6eeba3fb91a82e4e9fd285dcdd88"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 03 20:04:18 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 20:04:18 2026 +0000"
      },
      "message": "docs: post benchmarking results produced with the cluster scripts (#2763)"
    },
    {
      "commit": "4ccca3b8eabf6eeba3fb91a82e4e9fd285dcdd88",
      "tree": "42d5bd9c09c03f1d141e8bae519cddeeb22e998b",
      "parents": [
        "96b5ba93463955c91baae703373961a876b30896"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 03 17:46:14 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 17:46:14 2026 +0000"
      },
      "message": "feat(bench): add DataFusion Distributed to the cluster comparison scripts (#2762)\n\n* feat(bench): add DataFusion Distributed to the cluster comparison scripts\n\n* chore(bench): remove a stray empty file"
    },
    {
      "commit": "96b5ba93463955c91baae703373961a876b30896",
      "tree": "fb18819f8a8f74ef67c8d79ab5de04f606d9ca53",
      "parents": [
        "d151e3275081f0506cb252d45e10553841c3ba9c"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 03 13:54:14 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 13:54:14 2026 +0000"
      },
      "message": "feat: run submitted physical plans through the adaptive planner (#2682)\n\n* feat: run submitted physical plans through the adaptive planner\n\nA physical plan submitted with `submit_physical_plan` or a `PhysicalPlan`\nquery always used the static planner, even with adaptive planning on.\nRoute it through `AdaptiveExecutionGraph` when\n`ballista.planner.adaptive.enabled` is set, keeping the static planner\notherwise.\n\n`AdaptivePlanner::try_new_from_physical` runs the plan-preparation rules\nover the submitted plan and hands it to the adaptive optimizer chain.\nBefore that, `PinSubmittedShufflesRule` turns the plan\u0027s hash\nrepartitions into exchanges: DataFusion\u0027s `EnforceDistribution` removes\nany repartition no operator requirement asks for, which would drop a\nshuffle the submitter placed under an extension operator.\n\n`CoalescePartitionsRule` now only coalesces a stage whose shuffles feed\noperators known to be indifferent to the partition count. An extension\noperator may depend on it, so such a stage is left alone.\n\n* feat: keep a submitted range repartition as a stage boundary\n\nPinSubmittedShufflesRule pinned only hash repartitions, so\nEnforceDistribution removed a client\u0027s range repartition and nothing put\nit back: a consumer that sorts each partition then no longer sorted the\nwhole result. It now pins a range repartition too, unless it must\npreserve the order of its input, which a shuffle cannot.\n\n(cherry picked from commit 6ef9fe84d3fa41837b6876b09fba7da46942df77)\n\n* test: check an embedder\u0027s adaptive rules run on a submitted physical plan\n\nA submitted physical plan goes through the adaptive planner, so the rules a\nscheduler embedder adds (SchedulerConfig::adaptive_rules) apply to it as they\ndo to a planned logical plan. The test checks that its preparation rules run\nonce, on the plan as submitted and ahead of the pin that turns the submitted\nrepartitions into stage boundaries, and that its replan rules run when the job\nis planned and again after each stage completes."
    },
    {
      "commit": "d151e3275081f0506cb252d45e10553841c3ba9c",
      "tree": "45b34a148832a2d231281fb7c399629c1a51d3e0",
      "parents": [
        "0b5f5998d3f12432d5a98477419ab4fa1bdd0bd1"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Tue Nov 03 10:33:58 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 10:33:58 2026 +0000"
      },
      "message": "chore(deps): bump tonic-prost from 0.14.6 to 0.14.9 in /python (#2738)\n\nBumps [tonic-prost](https://github.com/grpc/grpc-rust) from 0.14.6 to 0.14.9.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-prost-v0.14.6...tonic-prost-v0.14.9)\n\n---\nupdated-dependencies:\n- dependency-name: tonic-prost\n  dependency-version: 0.14.9\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "0b5f5998d3f12432d5a98477419ab4fa1bdd0bd1",
      "tree": "16b1206fab9010ed25ad051d415bd7b1ed7ea5c5",
      "parents": [
        "6a1e7e20588d33bf7b992a190f0bb23fee37a86c"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Tue Nov 03 10:33:38 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 10:33:38 2026 +0000"
      },
      "message": "chore(deps): bump tonic-prost from 0.14.7 to 0.14.9 (#2733)\n\nBumps [tonic-prost](https://github.com/grpc/grpc-rust) from 0.14.7 to 0.14.9.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-prost-v0.14.7...tonic-prost-v0.14.9)\n\n---\nupdated-dependencies:\n- dependency-name: tonic-prost\n  dependency-version: 0.14.9\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "6a1e7e20588d33bf7b992a190f0bb23fee37a86c",
      "tree": "1212ae8336fbfdf78e9dea09a2be582b852c6793",
      "parents": [
        "849690a1eee96e7b7374528d0a19eb9065e93e6a"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Tue Nov 03 10:29:48 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 10:29:48 2026 +0000"
      },
      "message": "chore(deps): bump tonic from 0.14.7 to 0.14.9 in /python (#2739)\n\nBumps [tonic](https://github.com/grpc/grpc-rust) from 0.14.7 to 0.14.9.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-v0.14.7...tonic-v0.14.9)\n\n---\nupdated-dependencies:\n- dependency-name: tonic\n  dependency-version: 0.14.9\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "849690a1eee96e7b7374528d0a19eb9065e93e6a",
      "tree": "0d9aae2d5e3d98f11dbf64879aeb81c3eea396b7",
      "parents": [
        "a976c4cca437bbaaf014765b49602e3061c4b8fb"
      ],
      "author": {
        "name": "ump45nose",
        "email": "52391318+ump45nose@users.noreply.github.com",
        "time": "Tue Nov 03 10:19:58 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 10:19:58 2026 +0000"
      },
      "message": "fix(chaos): never hand two processes of one cluster the same port (#2740)\n\n* fix(chaos): never hand two processes of one cluster the same port\n\nfree_ports kept the ports of a single call distinct, but dropped its\nlisteners before returning. The next executor\u0027s call could then be\nhanded a port the previous executor had not bound yet, so one of them\nfailed with AddrInUse and the cluster timed out waiting for executors\nto register.\n\nTrack every port the cluster hands out (scheduler, result service and\neach executor, including respawns) and skip those when reserving new\nones.\n\nCloses #2720.\n\n* docs(chaos): shorten reserve_ports doc comment"
    },
    {
      "commit": "a976c4cca437bbaaf014765b49602e3061c4b8fb",
      "tree": "c10451cc0f4dd0390074f7b7f4e940815253f621",
      "parents": [
        "91697caa38d935a7182944e660530508ccedbdfc"
      ],
      "author": {
        "name": "NoahKusaba",
        "email": "97474796+NoahKusaba@users.noreply.github.com",
        "time": "Tue Nov 03 10:18:59 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 10:18:59 2026 +0000"
      },
      "message": "feat: add ComposedLogicalExtensionCodec (#2752)\n\n* Add ComposedLogicalExtensionCodec\n\nThe logical counterpart of DataFusion\u0027s ComposedPhysicalExtensionCodec:\ntries each codec in turn, records the position of the one that encoded a\npayload, and decodes it only with the codec at that position, so a codec\nis never offered another codec\u0027s bytes.\n\nUnlike the physical one, a codec that succeeds without writing anything\ndoesn\u0027t claim the node, so a later codec can still encode a function,\nand a function no codec writes is still sent by name.\n\n* Report composed codec mismatches as configuration errors\n\n* Test that a later composed codec can encode a function\n\n* Keep zero-byte nodes with their composed codec, report every error\n\n* Add ComposedPhysicalExtensionCodec, note the move to datafusion-proto\n\n* Use DataFusion\u0027s ComposedPhysicalExtensionCodec and note its limits\n\n* Decode empty composed payloads like DataFusion, test with Ballista\u0027s codec\n\n* Route functions like DataFusion\u0027s ComposedPhysicalExtensionCodec"
    },
    {
      "commit": "91697caa38d935a7182944e660530508ccedbdfc",
      "tree": "b65997dfa1c7c9ce50e5639f6536fb65f701ad7b",
      "parents": [
        "c7a52670ee84ef761fd88df94f5cb072fd63711a"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Tue Nov 03 09:35:50 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 09:35:50 2026 +0000"
      },
      "message": "chore(deps): bump log from 0.4.34 to 0.4.35 in /python (#2750)\n\nBumps [log](https://github.com/rust-lang/log) from 0.4.34 to 0.4.35.\n- [Release notes](https://github.com/rust-lang/log/releases)\n- [Changelog](https://github.com/rust-lang/log/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/rust-lang/log/compare/0.4.34...v0.4.35)\n\n---\nupdated-dependencies:\n- dependency-name: log\n  dependency-version: 0.4.35\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "c7a52670ee84ef761fd88df94f5cb072fd63711a",
      "tree": "93f624c9648004fbabc42579523109434f53c2d4",
      "parents": [
        "c52958d8f646ca80efced41f3e44e9185b9c0627"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Tue Nov 03 09:35:41 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 09:35:41 2026 +0000"
      },
      "message": "chore(deps): bump log from 0.4.34 to 0.4.35 (#2751)\n\nBumps [log](https://github.com/rust-lang/log) from 0.4.34 to 0.4.35.\n- [Release notes](https://github.com/rust-lang/log/releases)\n- [Changelog](https://github.com/rust-lang/log/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/rust-lang/log/compare/0.4.34...v0.4.35)\n\n---\nupdated-dependencies:\n- dependency-name: log\n  dependency-version: 0.4.35\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "c52958d8f646ca80efced41f3e44e9185b9c0627",
      "tree": "e5e2c861ef31f99c2bcc3f11280079ef50c26d8c",
      "parents": [
        "964809d20d7a986a4b9de7c24794ef588e78549a"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Tue Nov 03 00:41:38 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Nov 03 00:41:38 2026 +0000"
      },
      "message": "feat: collect HyperLogLog distinct counts on shuffle writes for AQE (#2671)\n\n* feat: surface shuffle column statistics to the AQE planner\n\n#1916 collects per-column null counts on the executor and aggregates them\non the completed stage, but nothing read them: a resolved exchange still\nreported unknown column statistics.\n\n- Collect null counts on the passthrough and range shuffle writers too,\n  not only the sort writer, so every stage reports them.\n- When an AQE stage completes, aggregate its tasks\u0027 column statistics and\n  store them on the stage\u0027s ExchangeExec before the replan.\n- Report them from ExchangeExec::partition_statistics for the exchange as\n  a whole. Per-partition statistics stay unknown, since the counts are\n  stage totals.\n\nCloses #1960\n\n* refactor: count nulls outside the shared lock and tidy review nits\n\n* refactor: share null counting across shuffle writers and simplify stats plumbing\n\n- The sort shuffle writer counts nulls through ColumnNullCounts like the\n  passthrough and range writers, replacing its inline count and fold.\n- Each stream counts into its own vector and adds it to the task total\n  once, when dropped, instead of taking a shared lock per batch.\n- Column statistics are set in the same finalise_stage lookup that\n  resolves the exchange\u0027s partitions, rather than a separate lookup\n  before it; the partitions-only helper moves to the test module.\n- Tests reuse mock_partitions_with_size and a shared\n  null_count_statistics helper.\n\n* feat: collect HyperLogLog distinct counts on shuffle writes for AQE\n\nShuffle writers now sketch the distinct count of each hash-partitioning\nkey column with a precision-12 HyperLogLog (4 KiB per column per task)\nand report the registers in TaskColumnStats.sketches. The scheduler\nmerges every successful task\u0027s sketch per column and sets\nColumnStatistics::distinct_count to Inexact on the stage\u0027s output, which\nreaches the resolved exchange, so join cardinality estimates downstream\nof a shuffle no longer fall back to row counts. The count is left Absent\nif any successful task did not sketch the column.\n\nValues are hashed with DataFusion\u0027s HLL_RANDOM_STATE, as approx_distinct\ndoes. Collection can be turned off with\nballista.shuffle.collect_distinct_counts, which shuffle_bench exposes as\n--collect-distinct-counts.\n\nCloses #2665.\n\n* test: pass column statistics in skew join rule tests\n\n* feat: make the distinct-count sketch precision configurable\n\nReview follow-up. The HyperLogLog sketches that shuffle writers collect\nfor AQE had a fixed precision of 12, 4 KiB per key column per task. The\nscheduler keeps every successful task\u0027s sketches, so on a stage with\nmany thousands of tasks the size is worth being able to tune.\n\n- ballista.shuffle.collect_distinct_counts_precision (default 12) sets\n  the precision of the sketches a task makes. Values outside 4 to 16 are\n  clamped, as ballista.pipelined.queue_capacity does, so an out-of-range\n  value cannot fail a shuffle write.\n- A sketch\u0027s precision follows from its register count, so the wire\n  format is unchanged. HyperLogLog::from_bytes accepts every supported\n  size, and merge refuses a sketch of a different precision.\n- The scheduler merges a column\u0027s sketches only when every successful\n  task made one at the same precision, and otherwise leaves\n  distinct_count Absent, as it does when a task did not sketch the\n  column. Tasks of one job share a session config, so this guards\n  against a mismatch rather than expecting one.\n- shuffle_bench takes --distinct-count-precision.\n\nThe module docs now say why 12 is the default and what a lower precision\nsaves.\n\n* fix: pass column statistics through ExchangeExec::with_inactive_stage\n\nmain\u0027s #2743 (embedder rules for adaptive planning) landed after this\nbranch last merged main, and the two no longer compiled together:\n\n- ExchangeExec::with_inactive_stage, added by #2743, called\n  new_with_details without the column statistics argument. It now passes\n  the exchange\u0027s shared statistics, as to_broadcast does, so an exchange\n  whose stage is held back still reports them. The test that rebuilt and\n  broadcast exchanges keep their statistics covers it too.\n- The column statistics planner test called AdaptivePlanner::try_new\n  without the rules argument #2743 added."
    },
    {
      "commit": "964809d20d7a986a4b9de7c24794ef588e78549a",
      "tree": "accf490a687b14300c533380aa829d852b2a72c0",
      "parents": [
        "a747f637e5e113634466791962fcb5f5751e3bc1"
      ],
      "author": {
        "name": "goingforstudying-ctrl",
        "email": "goingforstudying@gmail.com",
        "time": "Mon Nov 02 21:30:16 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 02 21:30:16 2026 +0000"
      },
      "message": "fix(executor): cached session runtime ignores SET s3.* changes (#2562)\n\n* fix(executor): rekey session runtime cache by config fingerprint\n\nThe LRU was keyed by session id alone, so a SET s3.* landing between\ntwo tasks of the same session never took effect on the executor: every\nlater task reused the base RuntimeEnv built from the first task\u0027s\nS3Options. The cache key is now (session id, hash of the session\nconfig\u0027s extension entries), so a changed config builds a fresh base\nwhile an unchanged one keeps sharing it.\n\nFixes #2533\n\n* drop intra-doc links to private config_fingerprint\n\ncargo doc runs with -D warnings and rustdoc::private-intra-doc-links\nfired on the two mentions. Render them as inline code instead.\n\n* skip the ballista extension in the config fingerprint\n\nballista.job.name is re-sent by the client with every job, so a session\nthat SETs it got a fresh fingerprint per query - each query built a new\nbase env, dropping the footer cache and cross-query reuse, and taking\nanother LRU slot. None of the shipped producers read ballista.*, so\nleave it out of the key the same way datafusion.* is left out.\n\n* docs: say the runtime cache LRU counts (session, fingerprint) entries\n\nThe cache is keyed by (session id, config fingerprint), not by session,\nso a session that changes its extension config mid-session occupies one\nentry per distinct fingerprint. Say so in the struct doc,\nDefaultSessionRuntimeCache::new, the --session-runtime-cache-capacity\nhelp text, and the executor_process field doc, and note the\nstale-entry trade-off on the struct.\n\nAlso document on SessionRuntimeCache and RuntimeProducer which config\nfeeds the cache key, so embedders writing a custom producer know that\ndatafusion.* and ballista.* options stay pinned to the values the\nsession\u0027s first task saw.\n\n---------\n\nCo-authored-by: goingforstudying-ctrl \u003cgoingforstudying-ctrl@users.noreply.github.com\u003e"
    },
    {
      "commit": "a747f637e5e113634466791962fcb5f5751e3bc1",
      "tree": "45088007361de78a2dda37d039bbe162741cd5b5",
      "parents": [
        "ee6fde8dc283449dc444a80141a3145d95bb0a5c"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Mon Nov 02 21:02:51 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 02 21:02:51 2026 +0000"
      },
      "message": "chore(deps): bump tonic-prost-build from 0.14.7 to 0.14.9 in /python (#2737)\n\nBumps [tonic-prost-build](https://github.com/grpc/grpc-rust) from 0.14.7 to 0.14.9.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-prost-build-v0.14.7...tonic-prost-build-v0.14.9)\n\n---\nupdated-dependencies:\n- dependency-name: tonic-prost-build\n  dependency-version: 0.14.9\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "ee6fde8dc283449dc444a80141a3145d95bb0a5c",
      "tree": "4f2ba7f71291e26886a08c56af2d6ff81bb8c266",
      "parents": [
        "feb495eab52b1ec9ef655db7cb9eb64c3a03c53a"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Mon Nov 02 20:29:12 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 02 20:29:12 2026 +0000"
      },
      "message": "chore(ci): bump taiki-e/install-action from 2.87.32 to 2.88.1 (#2735)\n\nBumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.87.32 to 2.88.1.\n- [Release notes](https://github.com/taiki-e/install-action/releases)\n- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/taiki-e/install-action/compare/5488ac5a951645ce95062214902ac4b6bc1a1037...68a389c788b2cd04016ce8c80ee23b80d2ab3d68)\n\n---\nupdated-dependencies:\n- dependency-name: taiki-e/install-action\n  dependency-version: 2.88.1\n  dependency-type: direct:production\n  update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "feb495eab52b1ec9ef655db7cb9eb64c3a03c53a",
      "tree": "17746946eac90c676b040be77f1ff57ad29176de",
      "parents": [
        "c72059195ced6012ee8508374c4ea1403df234e2"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Mon Nov 02 20:28:43 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 02 20:28:43 2026 +0000"
      },
      "message": "chore(ci): bump astral-sh/setup-uv from 10.3.2 to 10.3.3 (#2736)\n\nBumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 10.3.2 to 10.3.3.\n- [Release notes](https://github.com/astral-sh/setup-uv/releases)\n- [Commits](https://github.com/astral-sh/setup-uv/compare/07a047e608db84b3d8c06cd9a7c7dcc9c355c18e...68559e99cc807c1eb7e9238fd43a15bba460eec2)\n\n---\nupdated-dependencies:\n- dependency-name: astral-sh/setup-uv\n  dependency-version: 10.3.3\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "c72059195ced6012ee8508374c4ea1403df234e2",
      "tree": "666653a737616a63fb1e4d586b39403e8310878f",
      "parents": [
        "60def1df057f9e1e42549d19f2ef5a3e11cd977c"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Mon Nov 02 20:25:58 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 02 20:25:58 2026 +0000"
      },
      "message": "fix: enable tracing with the scheduler\u0027s rest-api feature (#2747)\n\nThe REST handlers and the event-log history log through `tracing`, which only\nthe default `build-binary` feature enabled, so building ballista-scheduler with\n`--no-default-features --features rest-api` failed with 18 unresolved `tracing`\nerrors. `rest-api` now enables `tracing`, and CI checks that build."
    },
    {
      "commit": "60def1df057f9e1e42549d19f2ef5a3e11cd977c",
      "tree": "09ed368a91aa752098fb65f702b262545322824f",
      "parents": [
        "b52f5e193f274c679f6aa5676e5ce5aca2ac8bd4"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Mon Nov 02 20:24:52 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 02 20:24:52 2026 +0000"
      },
      "message": "chore(deps): bump tonic-prost-build from 0.14.7 to 0.14.9 (#2734)\n\nBumps [tonic-prost-build](https://github.com/grpc/grpc-rust) from 0.14.7 to 0.14.9.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-prost-build-v0.14.7...tonic-prost-build-v0.14.9)\n\n---\nupdated-dependencies:\n- dependency-name: tonic-prost-build\n  dependency-version: 0.14.9\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "b52f5e193f274c679f6aa5676e5ce5aca2ac8bd4",
      "tree": "c98dbd07885e5f787f904244779f2d9337f3a881",
      "parents": [
        "9665258cd8c433c9938405568d886b4b0e4fafa2"
      ],
      "author": {
        "name": "Marko Milenković",
        "email": "milenkovicm@users.noreply.github.com",
        "time": "Mon Nov 02 19:46:37 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 02 19:46:37 2026 +0000"
      },
      "message": "add execution modes to readme (#2744)"
    },
    {
      "commit": "9665258cd8c433c9938405568d886b4b0e4fafa2",
      "tree": "b2f4dcedc9fe4128a52751b512edb5ef0abf0c70",
      "parents": [
        "dc6af5fa334dc30ec6e4a4c5797532b8b92e5c1f"
      ],
      "author": {
        "name": "Marko Milenković",
        "email": "milenkovicm@users.noreply.github.com",
        "time": "Mon Nov 02 17:45:49 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 02 17:45:49 2026 +0000"
      },
      "message": "feat(python): Improve ballista session context configuration   (#2637)\n\n* change ballista session context config\n\n* add with_target_partitions\n\n* fix failing test\n\n* add test to cover df.cache()\n\n* check setters\n\n* restore cluster_config and complain about it\n\n* reformat benchmark files as ci will fail\n\n* copy session config\n\n* apply_datafusion_override has been removed\n\n---------\n\nCo-authored-by: Andy Grove \u003cagrove@apache.org\u003e"
    },
    {
      "commit": "dc6af5fa334dc30ec6e4a4c5797532b8b92e5c1f",
      "tree": "edaf95d793ab75ee9d79a4ef508734c2fe689ef3",
      "parents": [
        "19a62adb97507d10e768520346582de2799be9d2"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Mon Nov 02 17:37:20 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 02 17:37:20 2026 +0000"
      },
      "message": "docs: add a user guide page for pipelined execution (#2713)\n\n* docs: add a user guide page for pipelined execution\n\n* docs: link the configuration reference to the pipelined execution guide\n\n* docs: rename blocking execution mode to staged in the pipelined execution guide"
    },
    {
      "commit": "19a62adb97507d10e768520346582de2799be9d2",
      "tree": "2ae55535be8e804457722e9cecb5d2c8ce72b7aa",
      "parents": [
        "26699ca7a55ccac61b6df242de30cac0fb3a8b3c"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Mon Nov 02 15:58:16 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 02 15:58:16 2026 +0000"
      },
      "message": "feat: let a scheduler embedder add rules to adaptive query planning (#2743)\n\nA plan with ExecutionPlan nodes of an embedder\u0027s own gets none of Ballista\u0027s\nadaptive planning for them, and the rule list is fixed. SchedulerConfig now\ntakes AdaptiveRules: preparation rules, which run once while the job\u0027s plan is\ncreated, and replan rules, which run last each time the plan is optimized, so\nthey see every stage before it starts and can hold one back. ExchangeExec is\nexported, with accessors and with_inactive_stage, from state::adaptive.\n\nCloses #2742"
    },
    {
      "commit": "26699ca7a55ccac61b6df242de30cac0fb3a8b3c",
      "tree": "fb53473c826fc7a3c64775e440d7cc5d23bba7d0",
      "parents": [
        "6e77991bdf72a5ab2beedcebfbd1eac5c7d93a86"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Mon Nov 02 14:41:59 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Nov 02 14:41:59 2026 +0000"
      },
      "message": "refactor: rename blocking execution mode to staged (#2741)"
    },
    {
      "commit": "6e77991bdf72a5ab2beedcebfbd1eac5c7d93a86",
      "tree": "8ecf3b60eee95a881ceb0cdcaf1b3b7e29eeca45",
      "parents": [
        "f325830d9866d475d6c688c8205c246c997d6e16"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Sun Nov 01 21:55:38 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 01 21:55:38 2026 +0000"
      },
      "message": "chore: regenerate ballista.rs after tonic-prost-build 0.14.7 bump (#2732)\n\ntonic-prost-build 0.14.7 (#2702) adds #[allow(clippy::all)] to generated\nmessages and enums. build.rs rewrites the checked-in file on every build,\nso every local build left it dirty."
    },
    {
      "commit": "f325830d9866d475d6c688c8205c246c997d6e16",
      "tree": "a6c8d1a0749e56e2d902b67656eecc4dfca33129",
      "parents": [
        "5b621d1fd09edb64782973930b22fd17c1d4b6f8"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Sun Nov 01 20:27:19 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 01 20:27:19 2026 +0000"
      },
      "message": "docs: add versioning policy for minor releases from release branches (#2724)\n\n* docs: add versioning policy for minor releases from release branches\n\nBallista releases once per DataFusion major release, and nothing written\nsays what a minor or patch release may contain. Document that minor\nreleases (55.1.0) carry backward-compatible features and fixes backported\nfrom main, that patch releases (55.1.1) carry fixes only, and the rules\nthat keep them safe to adopt:\n\n- add a Versioning and Compatibility page to the user guide\n- describe releasing from an existing release branch in the release process\n- add a Backporting to a release branch section to the development guide\n- point the upgrade guide index at the new page\n- fix the label name in the pull request template (`api-change`)\n\n* docs: say that only the major version is shared with DataFusion\n\nBallista requires a DataFusion major version (`datafusion \u003d \"55\"`), not a\nspecific release, so Ballista 55.Y.Z can be built against any DataFusion\n55.y.z. The 55.0.0 lockfile, for example, pins DataFusion 55.1.0.\n\nSuggested in review by @milenkovicm.\n\n* docs: add a proto-change label for wire format changes\n\nMark PRs that alter the wire or serialization format, as `api-change`\nalready does for public API breaks, so that backports and the pre-release\ncheck on a release branch can find them without reading every diff.\n\nSuggested in review by @milenkovicm."
    },
    {
      "commit": "5b621d1fd09edb64782973930b22fd17c1d4b6f8",
      "tree": "1098139fc547940884ada5d666c3a3f77ba3a25b",
      "parents": [
        "0ef7399eeac239b867e46f1c9bcd23d8f071589e"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Sun Nov 01 20:26:54 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Nov 01 20:26:54 2026 +0000"
      },
      "message": "docs: add blocking and pipelined results to the benchmarking page (#2676)\n\n* docs: add blocking and pipelined results to the benchmarking page\n\n* docs: rerun the blocking and pipelined results at the #2657 merge commit\n\n* docs: format ballista.md with prettier 2.7.1"
    },
    {
      "commit": "0ef7399eeac239b867e46f1c9bcd23d8f071589e",
      "tree": "19f975c62934f74c2367d59480fc91ab6a4a1cee",
      "parents": [
        "760bab3157c5169b852ca91e26a96f4d38c88645"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Sat Oct 31 17:52:42 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 17:52:42 2026 +0000"
      },
      "message": "feat: Add experimental pipelined execution mode (all tasks placed up front, streaming exchange) (#2657)\n\n* feat: let a standalone cluster run push-staged\n\nAdd ballista.standalone.task_scheduling_policy (default pull-staged). With\npush-staged, the standalone scheduler pushes tasks and the standalone\nexecutor registers on a free gRPC port to receive them.\n\nThe standalone scheduler now binds its listener before it is built and\nadvertises its real address. Push-staged executors report task status to\nthe endpoint each launch names, which was hardcoded to localhost:50050.\n\n* feat: add pipelined exchange operators\n\nAdd PipelinedShuffleWriterExec, PipelinedShuffleReaderExec and the\nper-executor PipelinedRegistry that connects them, with their protobuf\nmessages, serde, the FetchPipelinedPartition Flight action and the\nballista.execution.mode and ballista.pipelined.* settings.\n\nNothing plans these operators yet. The scheduler rejects jobs with\nballista.execution.mode \u003d pipelined, and executors answer pipelined\nfetches with unimplemented, until later changes wire them in.\n\n* refactor: simplify the pipelined exchange and reuse shared client helpers\n\n- Lease pooled connections for the life of a remote pipelined stream, and\n  build unpooled clients with new_ballista_client, as the shuffle reader\n  does. Encode Flight tickets with encode_protobuf.\n- Compute the writer\u0027s routing once, drop unused builder and getter\n  methods, and let JoinSet\u0027s drop abort the remaining inputs.\n- Track unclaimed queues with a counter instead of rescanning every\n  partition on each open, share one bounded set for closed jobs and\n  stages, and stop cloning per batch in the queue stream.\n- Keep a broadcast reader whole when restricting partitions, forget a\n  consumer\u0027s waiting slot when it times out, and document the minimums of\n  the pipelined settings.\n\n* fix: share one connection per producer executor in the pipelined reader\n\nEach remote stream checked out its own connection, so a wide pipelined job\nopened one per producer and consumer task pair and overflowed the executors\u0027\nlisten queues. A reader partition now multiplexes its streams to an\nexecutor onto one connection, capped at 64 streams per connection.\n\n* fix: listen with a 4096 backlog on the executor\u0027s gRPC and Flight ports\n\ntonic\u0027s `serve` binds through the standard library, which listens with a\nbacklog of 128. A pipelined job connects from every reader task on every\nexecutor when it starts, so an executor can get thousands of connections\nwithin a second and overflow both its accept and SYN queues. Overflowed\nconnections wait for a SYN retransmit, and once the kernel falls back to\nSYN cookies, a client whose first segments were dropped is reset as soon\nas it sends more. The reader then sees `ConnectionReset` on a stream it\nnever opened, with nothing logged on either side.\n\nBind the Flight server through `create_grpc_server_incoming`, which the\nexecutor\u0027s gRPC server already uses, and have that helper listen with\n`GrpcServerConfig::listen_backlog`, 4096 by default. The kernel caps the\nvalue at `net.core.somaxconn`, which is 4096 on Linux 5.4 and later.\n\n* fix: retry a pipelined stream open whose connection failed before the server answered\n\nA wide pipelined job opens its remote streams in one burst, and a\nconnection the producer\u0027s executor could not accept in time can be reset\nby the kernel as the reader starts sending. The reader saw that as a\n`ConnectionReset` on a stream it had not opened, and since pipelined\njobs do not retry tasks, one such reset failed the job.\n\n`fetch_pipelined_partition` now reports a failure of the connection\nitself, before the server answered, as `GrpcConnectionError`, and keeps\n`GrpcActionError` for anything the server answered. The reader retries\nthe former on a new connection, `io_retries_times` times with\n`io_retry_wait_time_ms` between attempts, the settings the blocking\nshuffle reader already uses. A failed connection is dropped from its\nslot, so the other streams of the partition that share it connect\nagain rather than fail on it. An error the server answered, including\nthe producer\u0027s own failure, is still final: the producer may already\nhave handed the partition to the failed stream.\n\nTests cover a stream open that is reset on its first connection and\nserved on its second, and a server-side failure that is not retried.\n\n* feat: share one connection per executor pair for pipelined reads\n\nA pipelined reader opened a connection per reader partition to each\nproducer executor, so a job opened executors x tasks x stage boundaries\nconnections to every executor at once, enough to overflow its listen\nqueue however large the queue is.\n\nThe executor\u0027s client pool now keeps one shared connection per\n(host, port, config), which the streams of every task on the executor\nmultiplex over, so an executor holds one connection to each other\nexecutor. A connection that fails before the server answers is\ndiscarded from the pool, and the open is retried on a new one.\n\nSharing is safe because of how the windows are set. A stream nobody is\nreading holds up to its stream window of data on the connection, and if\nstalled streams could use up the connection window they would starve\nthe streams something is waiting on. The shared connection therefore\nadvertises the largest connection window HTTP/2 allows and a small\nstream window, `ballista.pipelined.stream_window_bytes` (512 KiB by\ndefault), so stalled streams hold at most one window each and a\nconnection carries over 4000 streams before any could starve the rest.\nThe executor\u0027s server is explicitly left without a limit on concurrent\nstreams, since a stream the client had to queue behind a limit would\nleave its producer blocked on a full queue.\n\n`BallistaClientPool` gains a `shared` method with a default\nimplementation, so existing pools keep compiling.\n\n* fix: close unclaimed pipelined queues on cleanup and simplify the exchange\n\nAddress review feedback on the pipelined exchange operators.\n\nFixes:\n\n- `PipelinedRegistry::remove_job` and `remove_stage` now close the\n  queues no consumer has claimed. The writer keeps its `ProducerOutputs`\n  alive for the life of the task, so dropping the registry\u0027s reference\n  alone left a producer blocked on a full queue until the claim timeout.\n  The test now holds the outputs the way the writer does.\n- A producer stays registered until its stage or job is removed, instead\n  of being forgotten once every queue is claimed. A second open of a\n  queue now fails at once with \"already being read\" rather than waiting\n  out the registration timeout for a producer that will never register.\n- A pipelined stream open is retried only when the connection failed\n  before the server answered. Once the response headers have arrived the\n  executor may have handed the partition to that stream, so a failure on\n  the first message is reported as a server failure and not retried.\n- `is_transport_failure` relies on the status\u0027s source chain alone. A\n  reset arrives as `Cancelled` and a refused connection as `Unavailable`,\n  both with the transport error as source; the string match on\n  \"transport error\" and the bare `Unavailable` check were redundant.\n\nSimplifications:\n\n- `ProducerKey` is replaced by the existing `TaskKey`, which gains a\n  `Display` impl.\n- The writer threads one `Outputs` struct through its input tasks in\n  place of an `Arc\u003cHashMap\u003e` and an `Arc\u003cAtomicUsize\u003e`; outputs are\n  dense slots, so hash routing indexes them directly, and the hash\n  coalescers live beside them rather than as an `Option` on every\n  output. `Routing::Hash` holds the `Partitioning` instead of rebuilding\n  it per input. `finish_outputs` becomes `Outputs::finish`.\n- `open_remote` reuses the blocking reader\u0027s `with_retry`.\n- `BallistaClient::do_get_stream` holds the `do_get` and schema-read\n  sequence that `execute_do_get` and `fetch_pipelined_partition` both\n  repeated.\n- `serialize_hash_partitioning` serves both the sort shuffle writer and\n  the pipelined writer.\n- The producer\u0027s failure is stored once, on `ProducerOutputs`; a\n  broadcast partition records only whether it finished or failed.\n- `try_new_broadcast` becomes `new_broadcast`, since it cannot fail.\n  `ProducerOutputs::schema` and `producer_count` are no longer public.\n- Reader metrics are `local_partitions` and `remote_partitions`, and the\n  writer\u0027s send time is `write_time`, matching the blocking operators.\n- `DefaultBallistaClientPool::shared` returns an open connection without\n  taking the connecting lock.\n- The `io-util` tokio feature moves to dev-dependencies.\n- Registry tests share a `queue` helper, and the remote-read tests keep\n  their listeners open instead of reusing a port a dropped listener had.\n\nDocs note where the claim timeout is measured from and the plan shapes\nthat relies on, that `max_concurrent_streams(None)` is tonic\u0027s default,\nand that the stream window also bounds a stream\u0027s throughput per round\ntrip.\n\n* refactor: simplify pipelined registry, writer outputs and shared connections\n\n- Mark a shared client discarded with a flag; the pool skips discarded\n  connections and evicts their slots, so no discard closure or generation\n  counter is needed\n- Hold a producer\u0027s registry slot and broadcast replay state in\n  tokio::sync::watch channels instead of waiter lists and Notify\n- Store the producer failure in a OnceLock\n- Remember closed jobs and stages in one bounded map keyed by job\n- Keep each output\u0027s coalescer inside the output and derive whether all\n  consumers are gone instead of counting\n- Take the registry from the session config only, dropping with_registry\n  from the pipelined writer and reader\n\n* feat: run pipelined jobs end to end\n\nWire the pipelined exchange operators into the executor, scheduler,\nclient and Flight SQL, and remove the guards that rejected pipelined\njobs until now.\n\n- Executor: own a PipelinedRegistry, serve FetchPipelinedPartition from\n  do_get, run PipelinedShuffleWriterExec stage roots, share one memory\n  pool among a job\u0027s tasks, and drop a job\u0027s registry entries on cleanup.\n- Scheduler: plan pipelined jobs as a PipelinedExecutionGraph and place\n  all of their tasks at once, reserving the widest stage\u0027s vcores on\n  each executor. Choose join strategies by estimated build size.\n- Client: stream every final-stage partition while the job runs, cancel\n  the job when its results are dropped, and report its failure.\n- Flight SQL: serve a pipelined result through one merged endpoint.\n- Standalone: run push-staged when the session asks for pipelined\n  execution.\n- Tests, a TPC-H SF10 pipelined CI leg, and a user guide page.\n\n* fix: keep the standalone executor\u0027s gRPC port bound until it serves\n\nPass the bound listener to a new crate-private\nexecutor_server::startup_with_incoming instead of releasing the port and\nbinding it again, which let another port-0 bind in the process take it.\nCorrect the keep-alive comment about the stop channel, and make the\ntwo-executor test check the scheduler rejects poll_work, so it fails if\nthe push-staged setting is ignored.\n\n* docs: move the pipelined execution page to its own PR\n\nThe user guide page is now #2713.\n\n* docs: restore the toctree without the pipelined page\n\n* fix: build caches blocking from pipelined sessions and drop lost cache data\n\nA pipelined job streams its output and leaves no shuffle files, so a\ncache built from a pipelined session recorded an empty entry. Cache\nbuilds now run blocking whatever the session\u0027s mode; reads keep it.\n\nA pipelined job that loses cache data, to a lost executor or a failed\nfetch from a live one, now fails with CACHE_DATA_LOST so the build is\ndropped and a retry rebuilds it.\n\n* fix: release pipelined reservations on executor loss and failed saves\n\nLosing an executor now drops its share of a pipelined job\u0027s reservation,\nso an executor that registers again under the same id does not get those\nvcores on top of its fresh capacity.\n\nsucceed_job now releases a pipelined job\u0027s reservation before persisting\nits terminal state, as abort_job does, so a failed save cannot strand\nthe vcores.\n\nAlso drop the configs.md link to the pipelined execution guide, which\nlands in a later PR.\n\n* fix: import ExecutionPlan in execution_graph tests"
    },
    {
      "commit": "760bab3157c5169b852ca91e26a96f4d38c88645",
      "tree": "d12b58cc944e2fa901686104dccfd83ad73f378b",
      "parents": [
        "3b1877d715cb9f540e0d141309b095e2ba4e527f"
      ],
      "author": {
        "name": "Xuanyi Li",
        "email": "shanelxy@outlook.com",
        "time": "Sat Oct 31 14:46:37 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 14:46:37 2026 +0000"
      },
      "message": "feat(aqe): split skewed partitioned joins (#2714)\n\nSplit hot shuffle buckets into paired mapper ranges and replicate the\nmatching inputs so partitioned joins can run across smaller parallel tasks.\nPreserve mapper ordering and every logical output shard through execution.\n\nAdd opt-in configuration, shuffle-reader support, and focused AQE tests."
    },
    {
      "commit": "3b1877d715cb9f540e0d141309b095e2ba4e527f",
      "tree": "72507691a2dc59af128b6bf82913a0030d478a7b",
      "parents": [
        "10a56e1ea9f23046ac1a4630a6498628eedbff7e"
      ],
      "author": {
        "name": "Xuanyi Li",
        "email": "shanelxy@outlook.com",
        "time": "Sat Oct 31 14:46:30 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 14:46:30 2026 +0000"
      },
      "message": "feat: add runtime filter operators and task reports (#2701)"
    },
    {
      "commit": "10a56e1ea9f23046ac1a4630a6498628eedbff7e",
      "tree": "f562af86619b6e7a356eec55092395ef70a3935c",
      "parents": [
        "0b40747890426159d7895f8ac5b7699b90d94973"
      ],
      "author": {
        "name": "Isaac Emmanuel",
        "email": "35623334+1cbyc@users.noreply.github.com",
        "time": "Sat Oct 31 14:46:22 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 14:46:22 2026 +0000"
      },
      "message": "fix: share Ballista client retry handling (#2608)\n\n* fix: share Ballista client retry handling\n\nCo-authored-by: insisong \u003cemmanuelisaacnsisong@gmail.com\u003e\n\n* fix: preserve retry warning visibility\n\nCo-authored-by: insisong \u003cemmanuelisaacnsisong@gmail.com\u003e\n\n---------\n\nCo-authored-by: insisong \u003cemmanuelisaacnsisong@gmail.com\u003e"
    },
    {
      "commit": "0b40747890426159d7895f8ac5b7699b90d94973",
      "tree": "1f638dd0f1d416900e0298049520280493a42e27",
      "parents": [
        "bb0640ff8156cc557cf0be6630822f49b156f8d1"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Sat Oct 31 14:40:12 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 14:40:12 2026 +0000"
      },
      "message": "chore(deps): bump tonic-prost-build from 0.14.6 to 0.14.7 in /python (#2709)\n\nBumps [tonic-prost-build](https://github.com/grpc/grpc-rust) from 0.14.6 to 0.14.7.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-prost-build-v0.14.6...tonic-prost-build-v0.14.7)\n\n---\nupdated-dependencies:\n- dependency-name: tonic-prost-build\n  dependency-version: 0.14.7\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "bb0640ff8156cc557cf0be6630822f49b156f8d1",
      "tree": "c56b2ac062943ec8ae1a20c8a48e7826309d094d",
      "parents": [
        "74bae51a097e6177715cd788e4df9a9a77989720"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Sat Oct 31 14:40:08 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 14:40:08 2026 +0000"
      },
      "message": "chore(deps): bump tonic from 0.14.6 to 0.14.7 (#2708)\n\nBumps [tonic](https://github.com/grpc/grpc-rust) from 0.14.6 to 0.14.7.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-v0.14.6...tonic-v0.14.7)\n\n---\nupdated-dependencies:\n- dependency-name: tonic\n  dependency-version: 0.14.7\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "74bae51a097e6177715cd788e4df9a9a77989720",
      "tree": "c56b2ac062943ec8ae1a20c8a48e7826309d094d",
      "parents": [
        "31c734da70292a3053d3f4e4569a05f9e26fb41b"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Sat Oct 31 14:40:05 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 14:40:05 2026 +0000"
      },
      "message": "chore(deps): bump tonic from 0.14.6 to 0.14.7 in /python (#2707)\n\nBumps [tonic](https://github.com/grpc/grpc-rust) from 0.14.6 to 0.14.7.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-v0.14.6...tonic-v0.14.7)\n\n---\nupdated-dependencies:\n- dependency-name: tonic\n  dependency-version: 0.14.7\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "31c734da70292a3053d3f4e4569a05f9e26fb41b",
      "tree": "0e75a5ec4a77684f71e145cf35b00626403d232e",
      "parents": [
        "0fcadecaca1b93ca30b2b87d76239a3712e94db5"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Sat Oct 31 14:40:02 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 14:40:02 2026 +0000"
      },
      "message": "chore(deps): bump tonic-build from 0.14.6 to 0.14.7 in /python (#2706)\n\nBumps [tonic-build](https://github.com/grpc/grpc-rust) from 0.14.6 to 0.14.7.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-build-v0.14.6...tonic-build-v0.14.7)\n\n---\nupdated-dependencies:\n- dependency-name: tonic-build\n  dependency-version: 0.14.7\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "0fcadecaca1b93ca30b2b87d76239a3712e94db5",
      "tree": "e01fd30dd0dc75f2efa3fbb005bd06628a35f239",
      "parents": [
        "d2efb100f0757c8ce7ed52c3db3224ec7b923339"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Sat Oct 31 14:39:59 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 14:39:59 2026 +0000"
      },
      "message": "chore(deps): bump tonic-prost from 0.14.6 to 0.14.7 (#2705)\n\nBumps [tonic-prost](https://github.com/grpc/grpc-rust) from 0.14.6 to 0.14.7.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-prost-v0.14.6...tonic-prost-v0.14.7)\n\n---\nupdated-dependencies:\n- dependency-name: tonic-prost\n  dependency-version: 0.14.7\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "d2efb100f0757c8ce7ed52c3db3224ec7b923339",
      "tree": "c0810c6865eecd9e839d20260de47779eaa6b7ad",
      "parents": [
        "72d68073946a24783f867eb1c33ee0fecc1cf6f0"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Sat Oct 31 14:39:56 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 14:39:56 2026 +0000"
      },
      "message": "chore(deps): bump arrow-flight from 59.3.1 to 59.3.2 (#2704)\n\nBumps [arrow-flight](https://github.com/apache/arrow-rs) from 59.3.1 to 59.3.2.\n- [Release notes](https://github.com/apache/arrow-rs/releases)\n- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.2/CHANGELOG.md)\n- [Commits](https://github.com/apache/arrow-rs/compare/59.3.1...59.3.2)\n\n---\nupdated-dependencies:\n- dependency-name: arrow-flight\n  dependency-version: 59.3.2\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "72d68073946a24783f867eb1c33ee0fecc1cf6f0",
      "tree": "53e0251dcbe93b85d26e43b9a0e019579cfd5c22",
      "parents": [
        "95ecadc75e6c93f2fa0ac53a810e52fb38f79240"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Sat Oct 31 14:39:52 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 14:39:52 2026 +0000"
      },
      "message": "chore(deps): bump arrow from 59.3.1 to 59.3.2 (#2703)\n\nBumps [arrow](https://github.com/apache/arrow-rs) from 59.3.1 to 59.3.2.\n- [Release notes](https://github.com/apache/arrow-rs/releases)\n- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.2/CHANGELOG.md)\n- [Commits](https://github.com/apache/arrow-rs/compare/59.3.1...59.3.2)\n\n---\nupdated-dependencies:\n- dependency-name: arrow\n  dependency-version: 59.3.2\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "95ecadc75e6c93f2fa0ac53a810e52fb38f79240",
      "tree": "65d60842fe95de677712b9aeaed5c26b3c5bb0b7",
      "parents": [
        "2342897fa57371802a5b4996b9735326c1eae4d9"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Sat Oct 31 14:39:49 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 14:39:49 2026 +0000"
      },
      "message": "chore(deps): bump tonic-prost-build from 0.14.6 to 0.14.7 (#2702)\n\nBumps [tonic-prost-build](https://github.com/grpc/grpc-rust) from 0.14.6 to 0.14.7.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-prost-build-v0.14.6...tonic-prost-build-v0.14.7)\n\n---\nupdated-dependencies:\n- dependency-name: tonic-prost-build\n  dependency-version: 0.14.7\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "2342897fa57371802a5b4996b9735326c1eae4d9",
      "tree": "d9891765305c6bb1af46e2734fb89a1c31efbdfe",
      "parents": [
        "52651f7357efa25ebe1879d72568026eeb8f39f9"
      ],
      "author": {
        "name": "ump45nose",
        "email": "52391318+ump45nose@users.noreply.github.com",
        "time": "Sat Oct 31 13:47:48 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 13:47:48 2026 +0000"
      },
      "message": "refactor(scheduler): split QueryStageScheduler::on_receive into per-event handlers (#2643)\n\n* refactor(scheduler): split QueryStageScheduler::on_receive into per-event handlers\n\nSigned-off-by: yuwk \u003c1729065730@qq.com\u003e\n\n* style: format job terminal callbacks\n\n---------\n\nSigned-off-by: yuwk \u003c1729065730@qq.com\u003e"
    },
    {
      "commit": "52651f7357efa25ebe1879d72568026eeb8f39f9",
      "tree": "67e337957cd1bad617951ae137aadacebecf59b9",
      "parents": [
        "325eca9f8e40650aa62e3ace3a3812da6e3c0035"
      ],
      "author": {
        "name": "DeviousCardi",
        "email": "115358213+DeviousCardi@users.noreply.github.com",
        "time": "Sat Oct 31 12:25:45 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 12:25:45 2026 +0000"
      },
      "message": "fix(scheduler): keep AQE stage in the graph when a stage transition fails (#2613)\n\nAdaptiveExecutionGraph::resolve_stage, rollback_running_stage and\nrollback_resolved_stage removed the stage from `stages` before running\nthe fallible plan rewrite, so an error dropped the stage from the graph.\nLook the stage up, build the new stage, and only then insert it, as\nStaticExecutionGraph already does.\n\nThe FailingPlanRewriteExec test helper moves from the static graph\u0027s\ntests to test_utils so the adaptive graph\u0027s tests can use it too.\n\nCloses #2594\n\n\nClaude-Session: https://claude.ai/code/session_01Y1b55sEL1gA1c3FCMcQCbm\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nCo-authored-by: Andy Grove \u003cagrove@apache.org\u003e"
    },
    {
      "commit": "325eca9f8e40650aa62e3ace3a3812da6e3c0035",
      "tree": "bf88a722e05a5f99549b089e27ab33866f7c9604",
      "parents": [
        "41eb785a6b80d6c6bc9608ff68aecfab8acca131"
      ],
      "author": {
        "name": "Samuel James",
        "email": "samuel7james@gmail.com",
        "time": "Sat Oct 31 12:19:50 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 31 12:19:50 2026 +0000"
      },
      "message": "fix(executor): honour scheduler_connect_timeout_seconds (#2607)\n\n* fix(executor): honour scheduler_connect_timeout_seconds\n\nThe retry loop compared two Instant::now().elapsed() values, both about\nzero, so the timeout never fired. Measure from a stored Instant instead\nand add a regression test.\n\n* test(executor): shorten the connect timeout guard to 5s\n\n* refactor(executor): compute the connect deadline once\n\n---------\n\nCo-authored-by: Andy Grove \u003cagrove@apache.org\u003e"
    },
    {
      "commit": "41eb785a6b80d6c6bc9608ff68aecfab8acca131",
      "tree": "62b69e9a5ad45f67098eb62910711c0f9bb17ef7",
      "parents": [
        "10c5877890a17c845b3baa3b61286412ebcc06d8"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Fri Oct 30 09:07:36 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 30 09:07:36 2026 +0000"
      },
      "message": "chore(deps): bump tonic-build from 0.14.6 to 0.14.7 (#2710)\n\nBumps [tonic-build](https://github.com/grpc/grpc-rust) from 0.14.6 to 0.14.7.\n- [Release notes](https://github.com/grpc/grpc-rust/releases)\n- [Changelog](https://github.com/grpc/grpc-rust/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/grpc/grpc-rust/compare/tonic-build-v0.14.6...tonic-build-v0.14.7)\n\n---\nupdated-dependencies:\n- dependency-name: tonic-build\n  dependency-version: 0.14.7\n  dependency-type: direct:production\n  update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "10c5877890a17c845b3baa3b61286412ebcc06d8",
      "tree": "4e03cb4100f114665fd63ba76cc88d014f3f2fa4",
      "parents": [
        "1fe8e2f30a804aebea84cad3f5edb307c0faa089"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Fri Oct 30 03:16:04 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 30 03:16:04 2026 +0000"
      },
      "message": "docs: compare Ballista with DataFusion Distributed (#2699)\n\n* docs: compare Ballista with DataFusion Distributed\n\n* docs: say why Ballista can\u0027t build on DataFusion Distributed"
    },
    {
      "commit": "1fe8e2f30a804aebea84cad3f5edb307c0faa089",
      "tree": "741da6e0499503e180428cd2f6f437999129f323",
      "parents": [
        "efa54e6b2ded5aaf9fef24b2cb4accb84ea39dbf"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Fri Oct 30 01:28:51 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 30 01:28:51 2026 +0000"
      },
      "message": "feat: let a standalone cluster run push-staged (#2669)\n\n* feat: let a standalone cluster run push-staged\n\nAdd ballista.standalone.task_scheduling_policy (default pull-staged). With\npush-staged, the standalone scheduler pushes tasks and the standalone\nexecutor registers on a free gRPC port to receive them.\n\nThe standalone scheduler now binds its listener before it is built and\nadvertises its real address. Push-staged executors report task status to\nthe endpoint each launch names, which was hardcoded to localhost:50050.\n\n* fix: keep the standalone executor\u0027s gRPC port bound until it serves\n\nPass the bound listener to a new crate-private\nexecutor_server::startup_with_incoming instead of releasing the port and\nbinding it again, which let another port-0 bind in the process take it.\nCorrect the keep-alive comment about the stop channel, and make the\ntwo-executor test check the scheduler rejects poll_work, so it fails if\nthe push-staged setting is ignored."
    },
    {
      "commit": "efa54e6b2ded5aaf9fef24b2cb4accb84ea39dbf",
      "tree": "86cd0d4afecff689a0d58839030966d90afa8ffe",
      "parents": [
        "1780e6d55b7559620447a524d55c684c19e64efe"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Thu Oct 29 19:38:14 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 19:38:14 2026 +0000"
      },
      "message": "ci: run the Docker image build nightly instead of on every PR (#2684)\n\n* ci: run the Docker image build nightly instead of on every PR\n\nPull requests now only build the images when the Docker artifacts change,\nand pushes to main no longer build them. A nightly and manual trigger\ncover Rust changes that break the image build. Release tags still publish.\n\nKey the concurrency group on the ref instead of the commit so a tag\npublish cannot be cancelled by another run on the same commit.\n\n* ci: file an issue when the nightly Docker build fails"
    },
    {
      "commit": "1780e6d55b7559620447a524d55c684c19e64efe",
      "tree": "85aabd8e0484d1c3a723b31090b8c5db8a11ec58",
      "parents": [
        "2787284638bc3c3428e5dcb1f439d07d0f648426"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Thu Oct 29 18:15:25 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 18:15:25 2026 +0000"
      },
      "message": "feat: stream pipelined job results to the client and Flight SQL (#2696)\n\n* feat: stream pipelined job results to the client and Flight SQL\n\nAdd pipelined_output_locations to RunningJob and SuccessfulJob. When a\njob reports them, the client reads every final-stage partition\nconcurrently while the job runs, ends the stream with the job\u0027s own\nerror if it fails, and cancels the job if the stream is dropped early.\nThe Flight SQL frontend returns such a result as soon as the job is\nrunning and serves all its partitions through one endpoint.\n\n* fix: take the pipelined fetch timeout from BallistaConfig and cancel after a failed fetch\n\nRead the client\u0027s registration timeout through\nBallistaConfig::pipelined_registration_timeout instead of re-parsing the\nsubmitted settings, so it shares the config\u0027s default and minimum. Cancel\nthe job when a pipelined result stream ends on a fetch error the job does\nnot explain, as it already did for a stream dropped early.\n\n* refactor: simplify pipelined result reading in the client and Flight SQL\n\nGive QueryResult one optional PipelinedOutput instead of two parallel\nfields. Merge the running and successful pipelined arms of the pull and\npush loops, drop the result stream\u0027s fetches as soon as it ends instead\nof tracking a done flag, and run both status watchers through one helper\nthat stops once the result stream is gone. Poll a pipelined job\u0027s status\nevery 500 ms rather than 50 ms, since the stream\u0027s end already reports\nsuccess."
    },
    {
      "commit": "2787284638bc3c3428e5dcb1f439d07d0f648426",
      "tree": "65327368f52efddfa28c2ff04972ab6e82fb90a7",
      "parents": [
        "cc17e865cfb4018f48d6257e864ae69edc66c4d8"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Thu Oct 29 17:43:22 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 17:43:22 2026 +0000"
      },
      "message": "feat(bench): scripts to run the Ballista, Spark, Comet and Trino comparison on Kubernetes (#2697)\n\n* feat(bench): scripts to run the Ballista, Spark, Comet and Trino comparison on Kubernetes\n\n* fix(bench): make Spark\u0027s shuffle volumes writable by the apache/spark user\n\n* fix(bench): read S3 with the web identity token, not the default chain\u0027s instance-role fallback\n\n* fix(bench): print results whose row count is unknown"
    },
    {
      "commit": "cc17e865cfb4018f48d6257e864ae69edc66c4d8",
      "tree": "5beb495c44c9f2a625f65fd84c9947c0618f3268",
      "parents": [
        "c1de8e5b15604bce4800f5e396cd42a97ccee06b"
      ],
      "author": {
        "name": "Andy Grove",
        "email": "agrove@apache.org",
        "time": "Thu Oct 29 17:32:29 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 17:32:29 2026 +0000"
      },
      "message": "feat: serve pipelined partitions from the executor (#2695)\n\n* feat: serve pipelined partitions from the executor\n\nGive each executor a PipelinedRegistry, attach it to every task\u0027s\nsession config, and serve FetchPipelinedPartition tickets from it in\nthe Flight service. Pipelined tasks run through a new\nPipelinedQueryStageExec, and a job\u0027s tasks on one executor share one\nruntime sized by the job\u0027s vcore reservation. Job cleanup drops the\njob\u0027s registry entries.\n\n* refactor: attach the pipelined registry in produce_config and tidy the executor wiring\n\nAttach the registry once in Executor::produce_config, which every task\nconfig starts from, instead of at each task call site. Make\nwith_default_execution_engine delegate to Executor::new, let the Flight\nservice hold its LocalDiskBackend directly, and share the setup of the\npipelined do_get tests."
    }
  ],
  "next": "c1de8e5b15604bce4800f5e396cd42a97ccee06b"
}
