From 9858a33dd15a5bcf771393fb46ec8603344e9905 Mon Sep 17 00:00:00 2001 From: Jason Pascucci Date: Tue, 8 Sep 2026 08:13:16 -0700 Subject: [PATCH 1/6] ci: make pixi lockfile updates predictable (#2298) - Fail CI when a committed `pixi.lock` is stale (`pixi lock --check` per workspace). - Run pixi source-build CI with `PIXI_LOCKED=1` so jobs install from the lockfile instead of refreshing it. - Open monthly (and on-demand) lockfile-only PRs, one workspace at a time, via `pixi update --no-install`. - Document the contributor policy in `CONTRIBUTING.md`. Used codex(auto-balance) for changes. --- .../workflows/ci-pixi-lockfile-refresh.yml | 148 ++++++++++++++++++ .github/workflows/ci-pixi-lockfile.yml | 81 ++++++++++ .github/workflows/ci-pixi-source-test.yml | 5 + .github/workflows/ci-workflow-health.yml | 1 + .github/workflows/pr-metadata-check.yml | 2 +- CONTRIBUTING.md | 44 ++++++ 6 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci-pixi-lockfile-refresh.yml create mode 100644 .github/workflows/ci-pixi-lockfile.yml diff --git a/.github/workflows/ci-pixi-lockfile-refresh.yml b/.github/workflows/ci-pixi-lockfile-refresh.yml new file mode 100644 index 00000000000..a56f1e60239 --- /dev/null +++ b/.github/workflows/ci-pixi-lockfile-refresh.yml @@ -0,0 +1,148 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +# Monthly (and on-demand) pixi lockfile refresh. Each workspace gets its own +# PR so a benchmark or docs environment cannot drag unrelated package churn +# into review. See #2298. + +name: "CI: pixi lockfile refresh" + +on: + schedule: + # 08:17 UTC on the 1st of each month. Offset from hour-start load and + # from the daily CI / pixi source-test windows. + - cron: "17 8 1 * *" + workflow_dispatch: + inputs: + package: + description: "Pixi workspace to refresh" + type: choice + default: all + options: + - all + - root + - cuda_pathfinder + - cuda_bindings + - cuda_core + - benchmarks/cuda_bindings + - benchmarks/cuda_core + +defaults: + run: + shell: bash --noprofile --norc -xeuo pipefail {0} + +env: + # Keep in sync with ci-pixi-source-test.yml. + PIXI_VERSION: "v0.73.0" + +permissions: {} + +jobs: + # Job-level `if` cannot use `matrix` (evaluated before expansion). Filter + # the workspace list here and pass it to refresh as a dynamic matrix. + plan: + name: Select workspaces + if: ${{ github.repository_owner == 'nvidia' }} + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + matrix: ${{ steps.select.outputs.matrix }} + steps: + - name: Select workspaces to refresh + id: select + env: + PACKAGE: ${{ inputs.package || 'all' }} + run: | + all='[ + {"id":"root","manifest":".","lockfile":"pixi.lock"}, + {"id":"cuda_pathfinder","manifest":"cuda_pathfinder","lockfile":"cuda_pathfinder/pixi.lock"}, + {"id":"cuda_bindings","manifest":"cuda_bindings","lockfile":"cuda_bindings/pixi.lock"}, + {"id":"cuda_core","manifest":"cuda_core","lockfile":"cuda_core/pixi.lock"}, + {"id":"benchmarks/cuda_bindings","manifest":"benchmarks/cuda_bindings","lockfile":"benchmarks/cuda_bindings/pixi.lock"}, + {"id":"benchmarks/cuda_core","manifest":"benchmarks/cuda_core","lockfile":"benchmarks/cuda_core/pixi.lock"} + ]' + if [ "${PACKAGE}" = "all" ]; then + selected="${all}" + else + selected="$(jq -c --arg id "${PACKAGE}" '[.[] | select(.id == $id)]' <<<"${all}")" + if [ "${selected}" = "[]" ]; then + echo "::error::Unknown package '${PACKAGE}'" + exit 1 + fi + fi + echo "matrix=$(jq -c '{include:.}' <<<"${selected}")" >> "${GITHUB_OUTPUT}" + + refresh: + name: "pixi update (${{ matrix.id }})" + needs: plan + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: write + pull-requests: write + concurrency: + group: pixi-lock-refresh-${{ matrix.id }} + cancel-in-progress: false + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.plan.outputs.matrix) }} + steps: + - name: Checkout ${{ github.event.repository.name }} + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 0 + ref: ${{ github.event.repository.default_branch }} + + - name: Setup pixi + # Pinned to a commit SHA; install logic lives in the action and is + # auditable/pinned (vs. a curl|bash of an unverified installer). + uses: prefix-dev/setup-pixi@5185adfbffb4bd703da3010310260805d89ebb11 # v0.9.6 + with: + pixi-version: ${{ env.PIXI_VERSION }} + run-install: false + + - name: Update lockfile without installing + run: pixi update --no-install --manifest-path "${{ matrix.manifest }}" + + - name: Open or update a lockfile-only PR + id: cpr + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 + with: + token: ${{ github.token }} + add-paths: ${{ matrix.lockfile }} + commit-message: | + chore: refresh pixi.lock for ${{ matrix.id }} + + Scheduled pixi update --no-install for this workspace only. + signoff: true + sign-commits: true + branch: ci/pixi-lock-refresh/${{ matrix.id }} + delete-branch: true + title: "chore: refresh pixi.lock (${{ matrix.id }})" + labels: | + CI/CD + dependencies + body: | + Automated lockfile refresh for `${{ matrix.id }}` (`pixi update --no-install --manifest-path ${{ matrix.manifest }}`). + + This PR is workspace-scoped so other packages are not forced to review unrelated solver churn. See #2298. + + If the diff looks wrong, close this PR and leave the branch deleted; the next scheduled run will open a fresh one if an update is still needed. + author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> + committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> + + - name: Summarize + run: | + { + echo "### pixi lock refresh (${{ matrix.id }})" + echo "" + echo "- Manifest: \`${{ matrix.manifest }}\`" + echo "- Lockfile: \`${{ matrix.lockfile }}\`" + echo "- Operation: \`${{ steps.cpr.outputs.pull-request-operation }}\`" + if [ -n "${{ steps.cpr.outputs.pull-request-url }}" ]; then + echo "- PR: ${{ steps.cpr.outputs.pull-request-url }}" + else + echo "- No lockfile diff; PR not opened." + fi + } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/ci-pixi-lockfile.yml b/.github/workflows/ci-pixi-lockfile.yml new file mode 100644 index 00000000000..b6b44440b70 --- /dev/null +++ b/.github/workflows/ci-pixi-lockfile.yml @@ -0,0 +1,81 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +# Fails when a committed pixi.lock is out of date with its pixi.toml. +# Remediation: regenerate and commit the stale lockfile, e.g. +# pixi lock --manifest-path +# See #2298. + +name: "CI: pixi lockfile freshness" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} + cancel-in-progress: true + +on: + pull_request: + paths: + - "**/pixi.toml" + - "**/pixi.lock" + - ".github/workflows/ci-pixi-lockfile.yml" + push: + branches: + - "pull-request/[0-9]+" + - "main" + paths: + - "**/pixi.toml" + - "**/pixi.lock" + - ".github/workflows/ci-pixi-lockfile.yml" + workflow_dispatch: {} + +defaults: + run: + shell: bash --noprofile --norc -xeuo pipefail {0} + +env: + # Keep in sync with ci-pixi-source-test.yml. Must be >=0.71.0 so the + # committed lockfile format (v7) matches what this job checks against. + PIXI_VERSION: "v0.73.0" + +permissions: {} + +jobs: + lockfile-fresh: + name: "pixi lock --check (${{ matrix.manifest }})" + if: ${{ github.repository_owner == 'nvidia' }} + runs-on: ubuntu-latest + timeout-minutes: 20 + permissions: + contents: read + strategy: + fail-fast: false + matrix: + manifest: + - . + - cuda_pathfinder + - cuda_bindings + - cuda_core + - benchmarks/cuda_bindings + - benchmarks/cuda_core + steps: + - name: Checkout ${{ github.event.repository.name }} + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 1 + persist-credentials: false + + - name: Setup pixi + # Pinned to a commit SHA; install logic lives in the action and is + # auditable/pinned (vs. a curl|bash of an unverified installer). + uses: prefix-dev/setup-pixi@5185adfbffb4bd703da3010310260805d89ebb11 # v0.9.6 + with: + pixi-version: ${{ env.PIXI_VERSION }} + run-install: false + + - name: Check lockfile is current with its manifest + run: | + if ! pixi lock --check --manifest-path "${{ matrix.manifest }}"; then + echo "::error::Lockfile is stale for '${{ matrix.manifest }}'. Regenerate with: pixi lock --manifest-path ${{ matrix.manifest }}" + exit 1 + fi diff --git a/.github/workflows/ci-pixi-source-test.yml b/.github/workflows/ci-pixi-source-test.yml index 1fa0261c02b..39ef25c6510 100644 --- a/.github/workflows/ci-pixi-source-test.yml +++ b/.github/workflows/ci-pixi-source-test.yml @@ -61,7 +61,12 @@ env: # older pixi re-ran the editable source build on every `pixi run`, recompiling # all Cython extensions (#2138). The fix (content-addressed source-build cache, # prefix-dev/pixi#6285 + #6123) also bumps the pixi.lock format to v7. + # Keep in sync with ci-pixi-lockfile-refresh.yml and ci-pixi-lockfile.yml. PIXI_VERSION: "v0.73.0" + # Install from the committed lockfile only. Covers nested `pixi run` calls + # from root pixi.toml tasks; a stale lock must fail rather than being + # refreshed in CI (#2298). Equivalent to `pixi run --locked`. + PIXI_LOCKED: "1" jobs: # ── PR guard: CPU-only build + import + placement smoke ── diff --git a/.github/workflows/ci-workflow-health.yml b/.github/workflows/ci-workflow-health.yml index 0a17564b20f..9e789ee0c25 100644 --- a/.github/workflows/ci-workflow-health.yml +++ b/.github/workflows/ci-workflow-health.yml @@ -13,6 +13,7 @@ on: - "CI: Coverage" - "CI: Nightly optional-deps" - "CI: pixi run test (source build)" + - "CI: pixi lockfile refresh" - "Security Suite (Pulse + CodeQL)" - "Static Analysis: Bandit Scan" types: diff --git a/.github/workflows/pr-metadata-check.yml b/.github/workflows/pr-metadata-check.yml index 62110dcd93b..89f6304a67d 100644 --- a/.github/workflows/pr-metadata-check.yml +++ b/.github/workflows/pr-metadata-check.yml @@ -32,7 +32,7 @@ jobs: PR_NUMBER: ${{ github.event.pull_request.number }} GH_REPO: ${{ github.repository }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - IS_BOT: ${{ github.actor == 'dependabot[bot]' || github.actor == 'pre-commit-ci[bot]' || github.actor == 'copy-pr-bot[bot]' }} + IS_BOT: ${{ github.actor == 'dependabot[bot]' || github.actor == 'pre-commit-ci[bot]' || github.actor == 'copy-pr-bot[bot]' || github.actor == 'github-actions[bot]' }} IS_DRAFT: ${{ github.event.pull_request.draft }} run: | if [ "$IS_BOT" = "true" ] || [ "$IS_DRAFT" = "true" ]; then diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7474ac4d840..1bc68e93f9a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,6 +26,7 @@ Thank you for your interest in contributing to CUDA Python! Based on the type of - [Type stubs for cuda.core](#type-stubs-for-cudacore) - [Pre-commit](#pre-commit) - [Pre-commit on Windows](#pre-commit-on-windows) + - [Pixi lockfiles](#pixi-lockfiles) - [Signing Your Work](#signing-your-work) - [Code signing](#code-signing) - [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco) @@ -179,6 +180,49 @@ commit` workflow. To resolve this, you can either: 2. Skip it by setting the environment variable `SKIP` to `lychee`. This would be `$env:SKIP = "lychee"` in PowerShell or `set SKIP=lychee` in cmd. +## Pixi lockfiles + +The repository checks in a `pixi.lock` next to each `pixi.toml`. Those lockfiles +pin the solved dependency graph used by local pixi workflows and by CI, so they +must stay in sync with their manifests and easy to review. + +Manifests and lockfiles currently live at: + +- `pixi.toml` / `pixi.lock` +- `cuda_pathfinder/pixi.toml` / `cuda_pathfinder/pixi.lock` +- `cuda_bindings/pixi.toml` / `cuda_bindings/pixi.lock` +- `cuda_core/pixi.toml` / `cuda_core/pixi.lock` +- `benchmarks/cuda_bindings/pixi.toml` / `benchmarks/cuda_bindings/pixi.lock` +- `benchmarks/cuda_core/pixi.toml` / `benchmarks/cuda_core/pixi.lock` + +Contributor expectations: + +- If a PR changes a `pixi.toml`, update the corresponding `pixi.lock` in the + same PR. Regenerating one lockfile: + + ```console + $ pixi lock --manifest-path cuda_core + ``` + + Use `--manifest-path .` for the repository-root environment. +- If a PR does not intentionally change pixi dependencies or metadata, do not + include unrelated lockfile churn. `pixi run` can refresh a stale lockfile + implicitly; revert that noise unless the refresh is the point of the change. +- If a lockfile changes, the PR description should briefly say why. +- Isolate large dependency refreshes from feature work when possible. Prefer a + dedicated lockfile-only PR over mixing solver churn into an unrelated change. + +CI enforces the contract: `pixi lock --check` fails when a committed lockfile is +stale, and pixi source-build jobs run with `PIXI_LOCKED=1` so they install from +the committed lock rather than updating it during the job. If either check +fails, regenerate and commit the affected lockfile. + +A monthly scheduled workflow (`CI: pixi lockfile refresh`) runs +`pixi update --no-install` per workspace and opens a dedicated PR when that +lockfile changes, so broad dependency churn is reviewed as maintenance rather +than landing inside unrelated feature work. The workflow can also be dispatched +manually for one package or for all of them. + ## Secret Scanning The `secret-scan-trufflehog` pre-commit hook scans staged files and installs TruffleHog into its own environment on first run, on Linux, macOS, and Windows. If it flags a secret, remove it before committing, or contact a maintainer if it's a false positive. Secrets are also scanned server-side in CI. From 7d9a6cdcbbe3f5eb3a86d4d1106d85e92dca99b4 Mon Sep 17 00:00:00 2001 From: Jason Pascucci Date: Tue, 8 Sep 2026 08:22:21 -0700 Subject: [PATCH 2/6] Update manifest so pixi scan runs correctly --- benchmarks/cuda_core/pixi.lock | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/benchmarks/cuda_core/pixi.lock b/benchmarks/cuda_core/pixi.lock index 7df6ff2092b..40642f8b88e 100644 --- a/benchmarks/cuda_core/pixi.lock +++ b/benchmarks/cuda_core/pixi.lock @@ -6,7 +6,7 @@ platforms: - __linux=4.18 - __glibc=2.28 - __archspec=0=x86_64 -- name: p1 +- name: linux-64-cuda-13 subdir: linux-64 virtual-packages: - __cuda=13 @@ -27,7 +27,7 @@ environments: options: channel-priority: disabled packages: - p1: + linux-64-cuda-13: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda @@ -76,7 +76,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_linux-64-13.3.29-h376f20c_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-pathfinder-1.5.6-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-pathfinder-1.8.1-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-version-13.3-hcbadf70_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.0-pyhd8ed1ab_0.conda @@ -94,14 +94,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.1-pyhcf101f3_0.conda - - conda_source: cuda-core[77fd68c4] @ ../../cuda_core + - conda_source: cuda-core[7d81c9f9] @ ../../cuda_core wheel: channels: - url: https://conda.anaconda.org/conda-forge/ options: channel-priority: disabled packages: - p1: + linux-64-cuda-13: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda @@ -1330,6 +1330,18 @@ packages: run_exports: {} size: 45350 timestamp: 1782782777927 +- conda: https://conda.anaconda.org/conda-forge/noarch/cuda-pathfinder-1.8.1-pyhc364b38_0.conda + sha256: f4fa56e00f4077adb794a1e27e28aa6c70ffc7d61fc5cddcd458eaab856319e2 + md5: 45716133412f5e899d2d23a3c88f563f + depends: + - python >=3.10 + - cuda-version >=12.0,<14 + - python + license: Apache-2.0 + license_family: APACHE + run_exports: {} + size: 53370 + timestamp: 1788375531780 - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-version-13.1-h2ff5cdb_3.conda sha256: 176ac20fdb95611af8fb2bf0d3d16fee998019b1d0f12fc9ddd5fa0df4553992 md5: d85448460c25ee43ff2f8346bb9ad52b @@ -1639,7 +1651,7 @@ packages: license_family: MIT size: 24461 timestamp: 1776131454755 -- conda_source: cuda-core[77fd68c4] @ ../../cuda_core +- conda_source: cuda-core[7d81c9f9] @ ../../cuda_core variants: c_stdlib: sysroot c_stdlib_version: '2.28' @@ -1657,8 +1669,8 @@ packages: - libstdcxx >=15 - __glibc >=2.28,<3.0.a0 - python_abi 3.14.* *_cp314 - - cuda-cudart >=13.3.29,<14.0a0 - cuda-nvrtc >=13.3.33,<14.0a0 + - cuda-cudart >=13.3.29,<14.0a0 license: Apache-2.0 build_packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda From 60bb35b2451f24b2b42d344dfbc093afc44bcb44 Mon Sep 17 00:00:00 2001 From: Jason Pascucci Date: Tue, 8 Sep 2026 10:42:02 -0700 Subject: [PATCH 3/6] Updates wrt comments in PR. --- ...-lockfile.yml => ci-pixi-lockfile-freshness-check.yml} | 2 +- .github/workflows/ci-pixi-lockfile-refresh.yml | 8 ++++---- .github/workflows/ci-pixi-source-test.yml | 3 ++- .github/workflows/ci-workflow-health.yml | 1 + CONTRIBUTING.md | 4 ++-- 5 files changed, 10 insertions(+), 8 deletions(-) rename .github/workflows/{ci-pixi-lockfile.yml => ci-pixi-lockfile-freshness-check.yml} (98%) diff --git a/.github/workflows/ci-pixi-lockfile.yml b/.github/workflows/ci-pixi-lockfile-freshness-check.yml similarity index 98% rename from .github/workflows/ci-pixi-lockfile.yml rename to .github/workflows/ci-pixi-lockfile-freshness-check.yml index b6b44440b70..e3a5c7552a4 100644 --- a/.github/workflows/ci-pixi-lockfile.yml +++ b/.github/workflows/ci-pixi-lockfile-freshness-check.yml @@ -7,7 +7,7 @@ # pixi lock --manifest-path # See #2298. -name: "CI: pixi lockfile freshness" +name: "CI: pixi lockfile freshness check" concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} diff --git a/.github/workflows/ci-pixi-lockfile-refresh.yml b/.github/workflows/ci-pixi-lockfile-refresh.yml index a56f1e60239..d061ffa2a5a 100644 --- a/.github/workflows/ci-pixi-lockfile-refresh.yml +++ b/.github/workflows/ci-pixi-lockfile-refresh.yml @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 -# Monthly (and on-demand) pixi lockfile refresh. Each workspace gets its own +# Scheduled (and on-demand) pixi lockfile refresh. Each workspace gets its own # PR so a benchmark or docs environment cannot drag unrelated package churn # into review. See #2298. @@ -10,9 +10,9 @@ name: "CI: pixi lockfile refresh" on: schedule: - # 08:17 UTC on the 1st of each month. Offset from hour-start load and - # from the daily CI / pixi source-test windows. - - cron: "17 8 1 * *" + # 08:00 UTC every Monday = 03:00 EST. GitHub cron is UTC-only, so this + # stays 03:00 EST year-round and is 04:00 EDT during daylight saving. + - cron: "0 8 * * 1" workflow_dispatch: inputs: package: diff --git a/.github/workflows/ci-pixi-source-test.yml b/.github/workflows/ci-pixi-source-test.yml index 39ef25c6510..0a1c0019d9c 100644 --- a/.github/workflows/ci-pixi-source-test.yml +++ b/.github/workflows/ci-pixi-source-test.yml @@ -61,7 +61,8 @@ env: # older pixi re-ran the editable source build on every `pixi run`, recompiling # all Cython extensions (#2138). The fix (content-addressed source-build cache, # prefix-dev/pixi#6285 + #6123) also bumps the pixi.lock format to v7. - # Keep in sync with ci-pixi-lockfile-refresh.yml and ci-pixi-lockfile.yml. + # Keep in sync with ci-pixi-lockfile-refresh.yml and + # ci-pixi-lockfile-freshness-check.yml. PIXI_VERSION: "v0.73.0" # Install from the committed lockfile only. Covers nested `pixi run` calls # from root pixi.toml tasks; a stale lock must fail rather than being diff --git a/.github/workflows/ci-workflow-health.yml b/.github/workflows/ci-workflow-health.yml index 9e789ee0c25..a6072e96524 100644 --- a/.github/workflows/ci-workflow-health.yml +++ b/.github/workflows/ci-workflow-health.yml @@ -14,6 +14,7 @@ on: - "CI: Nightly optional-deps" - "CI: pixi run test (source build)" - "CI: pixi lockfile refresh" + - "CI: pixi lockfile freshness check" - "Security Suite (Pulse + CodeQL)" - "Static Analysis: Bandit Scan" types: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1bc68e93f9a..9770116df99 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -217,8 +217,8 @@ stale, and pixi source-build jobs run with `PIXI_LOCKED=1` so they install from the committed lock rather than updating it during the job. If either check fails, regenerate and commit the affected lockfile. -A monthly scheduled workflow (`CI: pixi lockfile refresh`) runs -`pixi update --no-install` per workspace and opens a dedicated PR when that +A scheduled workflow (`CI: pixi lockfile refresh`) +runs `pixi update --no-install` per workspace and opens a dedicated PR when that lockfile changes, so broad dependency churn is reviewed as maintenance rather than landing inside unrelated feature work. The workflow can also be dispatched manually for one package or for all of them. From 5968afd9fa9ec566cfd2397aafa1eeea5fbe742b Mon Sep 17 00:00:00 2001 From: Jason Pascucci Date: Tue, 8 Sep 2026 10:45:16 -0700 Subject: [PATCH 4/6] Fix extra whitespace --- .github/workflows/ci-pixi-source-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pixi-source-test.yml b/.github/workflows/ci-pixi-source-test.yml index 0a1c0019d9c..7f310b1af42 100644 --- a/.github/workflows/ci-pixi-source-test.yml +++ b/.github/workflows/ci-pixi-source-test.yml @@ -61,7 +61,7 @@ env: # older pixi re-ran the editable source build on every `pixi run`, recompiling # all Cython extensions (#2138). The fix (content-addressed source-build cache, # prefix-dev/pixi#6285 + #6123) also bumps the pixi.lock format to v7. - # Keep in sync with ci-pixi-lockfile-refresh.yml and + # Keep in sync with ci-pixi-lockfile-refresh.yml and # ci-pixi-lockfile-freshness-check.yml. PIXI_VERSION: "v0.73.0" # Install from the committed lockfile only. Covers nested `pixi run` calls From de9d019825ba19ef1feeb9062a7453b6a8920c97 Mon Sep 17 00:00:00 2001 From: Jason Pascucci Date: Tue, 8 Sep 2026 10:55:31 -0700 Subject: [PATCH 5/6] Remove path enumeration --- CONTRIBUTING.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9770116df99..c188ca372cd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -186,15 +186,6 @@ The repository checks in a `pixi.lock` next to each `pixi.toml`. Those lockfiles pin the solved dependency graph used by local pixi workflows and by CI, so they must stay in sync with their manifests and easy to review. -Manifests and lockfiles currently live at: - -- `pixi.toml` / `pixi.lock` -- `cuda_pathfinder/pixi.toml` / `cuda_pathfinder/pixi.lock` -- `cuda_bindings/pixi.toml` / `cuda_bindings/pixi.lock` -- `cuda_core/pixi.toml` / `cuda_core/pixi.lock` -- `benchmarks/cuda_bindings/pixi.toml` / `benchmarks/cuda_bindings/pixi.lock` -- `benchmarks/cuda_core/pixi.toml` / `benchmarks/cuda_core/pixi.lock` - Contributor expectations: - If a PR changes a `pixi.toml`, update the corresponding `pixi.lock` in the From 420c0fa7534f9f2d60a67cc167fff45d4485139a Mon Sep 17 00:00:00 2001 From: Jason Pascucci Date: Wed, 9 Sep 2026 08:49:21 -0700 Subject: [PATCH 6/6] Updated from codex comments --- .../ci-pixi-lockfile-freshness-check.yml | 74 +- .../workflows/ci-pixi-lockfile-refresh.yml | 109 +- .github/workflows/ci-pixi-source-test.yml | 11 +- .github/workflows/pr-metadata-check.yml | 6 +- .gitignore | 6 +- CONTRIBUTING.md | 26 +- benchmarks/cuda_core/pixi.lock | 6 +- ci/tools/list_pixi_workspaces.py | 99 ++ ci/tools/tests/test_list_pixi_workspaces.py | 109 ++ pixi.lock | 959 +++++++++--------- 10 files changed, 859 insertions(+), 546 deletions(-) create mode 100644 ci/tools/list_pixi_workspaces.py create mode 100644 ci/tools/tests/test_list_pixi_workspaces.py diff --git a/.github/workflows/ci-pixi-lockfile-freshness-check.yml b/.github/workflows/ci-pixi-lockfile-freshness-check.yml index e3a5c7552a4..d7f9d265c9d 100644 --- a/.github/workflows/ci-pixi-lockfile-freshness-check.yml +++ b/.github/workflows/ci-pixi-lockfile-freshness-check.yml @@ -2,31 +2,40 @@ # # SPDX-License-Identifier: Apache-2.0 -# Fails when a committed pixi.lock is out of date with its pixi.toml. -# Remediation: regenerate and commit the stale lockfile, e.g. +# Fails when a committed pixi.lock is out of date with its pixi.toml, or when +# its bytes are not what the pinned pixi version generates. +# Remediation for both: regenerate and commit the lockfile with that pixi +# version, e.g. # pixi lock --manifest-path # See #2298. name: "CI: pixi lockfile freshness check" concurrency: + # Keyed on the event as well as the ref so a manual dispatch and a push to + # the same branch do not cancel each other. group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} cancel-in-progress: true on: pull_request: - paths: + # `pyproject.toml` is a lockfile input too: the manifests consume sibling + # packages (including cuda_python_test_helpers) as path dependencies, so + # their metadata can stale a lock without any pixi.toml edit. Matched by + # glob rather than by name so the filter cannot drift as packages move. + paths: &lockfile_inputs - "**/pixi.toml" - "**/pixi.lock" - - ".github/workflows/ci-pixi-lockfile.yml" + - "**/pyproject.toml" + - "ci/tools/list_pixi_workspaces.py" + - ".github/workflows/ci-pixi-lockfile-freshness-check.yml" push: + # `pull_request` already covers PRs, including those from forks: this check + # needs no secrets or GPU runner. Watching copy-pr-bot's `pull-request/N` + # mirror too would run the whole matrix a second time per PR. branches: - - "pull-request/[0-9]+" - "main" - paths: - - "**/pixi.toml" - - "**/pixi.lock" - - ".github/workflows/ci-pixi-lockfile.yml" + paths: *lockfile_inputs workflow_dispatch: {} defaults: @@ -41,23 +50,40 @@ env: permissions: {} jobs: + # The workspace list is derived from the committed manifests so this matrix + # cannot silently skip a newly added workspace (#2298). + plan: + name: Discover pixi workspaces + if: ${{ github.repository_owner == 'nvidia' }} + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: read + outputs: + matrix: ${{ steps.discover.outputs.matrix }} + steps: + - name: Checkout ${{ github.event.repository.name }} + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 1 + persist-credentials: false + + - name: Discover workspaces + id: discover + run: | + workspaces="$(python3 ci/tools/list_pixi_workspaces.py)" + echo "matrix=$(jq -c '{include: .}' <<<"${workspaces}")" >> "${GITHUB_OUTPUT}" + lockfile-fresh: name: "pixi lock --check (${{ matrix.manifest }})" - if: ${{ github.repository_owner == 'nvidia' }} + needs: plan runs-on: ubuntu-latest timeout-minutes: 20 permissions: contents: read strategy: fail-fast: false - matrix: - manifest: - - . - - cuda_pathfinder - - cuda_bindings - - cuda_core - - benchmarks/cuda_bindings - - benchmarks/cuda_core + matrix: ${{ fromJSON(needs.plan.outputs.matrix) }} steps: - name: Checkout ${{ github.event.repository.name }} uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -79,3 +105,15 @@ jobs: echo "::error::Lockfile is stale for '${{ matrix.manifest }}'. Regenerate with: pixi lock --manifest-path ${{ matrix.manifest }}" exit 1 fi + + # `pixi lock --check` exits 0 on a semantically current lock even when it + # rewrites the file into the pinned version's canonical form (lockfile + # format upgrades, platform alias renames). Without this guard that drift + # is invisible: the check prints "Updated lock file" and still passes, + # while every later pixi run keeps rewriting the committed file (#2298). + - name: Check lockfile is byte-for-byte canonical + run: | + if ! git diff --exit-code -- "${{ matrix.lockfile }}"; then + echo "::error::pixi ${PIXI_VERSION} rewrote ${{ matrix.lockfile }} during the check, so the committed bytes are not what it generates. Regenerate with pixi ${PIXI_VERSION}: pixi lock --manifest-path ${{ matrix.manifest }}" + exit 1 + fi diff --git a/.github/workflows/ci-pixi-lockfile-refresh.yml b/.github/workflows/ci-pixi-lockfile-refresh.yml index d061ffa2a5a..2ee774cbf1b 100644 --- a/.github/workflows/ci-pixi-lockfile-refresh.yml +++ b/.github/workflows/ci-pixi-lockfile-refresh.yml @@ -10,23 +10,19 @@ name: "CI: pixi lockfile refresh" on: schedule: - # 08:00 UTC every Monday = 03:00 EST. GitHub cron is UTC-only, so this - # stays 03:00 EST year-round and is 04:00 EDT during daylight saving. - - cron: "0 8 * * 1" + # Monday 03:17 Eastern. GitHub handles the DST offset for the IANA zone, + # and a non-zero minute avoids the start-of-hour window where GitHub + # documents scheduled runs being delayed or dropped. + - cron: "17 3 * * 1" + timezone: "America/New_York" workflow_dispatch: inputs: package: - description: "Pixi workspace to refresh" - type: choice + description: > + Pixi workspace id to refresh, or "all". Valid ids come from + ci/tools/list_pixi_workspaces.py; an unknown id fails the run. + type: string default: all - options: - - all - - root - - cuda_pathfinder - - cuda_bindings - - cuda_core - - benchmarks/cuda_bindings - - benchmarks/cuda_core defaults: run: @@ -39,39 +35,32 @@ env: permissions: {} jobs: - # Job-level `if` cannot use `matrix` (evaluated before expansion). Filter - # the workspace list here and pass it to refresh as a dynamic matrix. + # Job-level `if` cannot use `matrix` (evaluated before expansion), and the + # workspace list must not drift from the committed manifests, so resolve the + # requested workspaces here and pass them to refresh as a dynamic matrix. plan: name: Select workspaces if: ${{ github.repository_owner == 'nvidia' }} runs-on: ubuntu-latest timeout-minutes: 5 + permissions: + contents: read outputs: matrix: ${{ steps.select.outputs.matrix }} steps: + - name: Checkout ${{ github.event.repository.name }} + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 1 + persist-credentials: false + - name: Select workspaces to refresh id: select env: PACKAGE: ${{ inputs.package || 'all' }} run: | - all='[ - {"id":"root","manifest":".","lockfile":"pixi.lock"}, - {"id":"cuda_pathfinder","manifest":"cuda_pathfinder","lockfile":"cuda_pathfinder/pixi.lock"}, - {"id":"cuda_bindings","manifest":"cuda_bindings","lockfile":"cuda_bindings/pixi.lock"}, - {"id":"cuda_core","manifest":"cuda_core","lockfile":"cuda_core/pixi.lock"}, - {"id":"benchmarks/cuda_bindings","manifest":"benchmarks/cuda_bindings","lockfile":"benchmarks/cuda_bindings/pixi.lock"}, - {"id":"benchmarks/cuda_core","manifest":"benchmarks/cuda_core","lockfile":"benchmarks/cuda_core/pixi.lock"} - ]' - if [ "${PACKAGE}" = "all" ]; then - selected="${all}" - else - selected="$(jq -c --arg id "${PACKAGE}" '[.[] | select(.id == $id)]' <<<"${all}")" - if [ "${selected}" = "[]" ]; then - echo "::error::Unknown package '${PACKAGE}'" - exit 1 - fi - fi - echo "matrix=$(jq -c '{include:.}' <<<"${selected}")" >> "${GITHUB_OUTPUT}" + workspaces="$(python3 ci/tools/list_pixi_workspaces.py --select "${PACKAGE}")" + echo "matrix=$(jq -c '{include: .}' <<<"${workspaces}")" >> "${GITHUB_OUTPUT}" refresh: name: "pixi update (${{ matrix.id }})" @@ -94,6 +83,19 @@ jobs: fetch-depth: 0 ref: ${{ github.event.repository.default_branch }} + # GitHub suppresses workflow-triggering events for pushes and PRs made + # with GITHUB_TOKEN, so a refresh PR opened with the default token cannot + # reach a green required-check state on its own. An App token restores + # normal event delivery; without one the PR needs a manual nudge, which + # the PR body and a run warning spell out. + - name: Mint App token for the refresh PR + id: app-token + if: ${{ vars.PIXI_LOCK_REFRESH_APP_ID != '' }} + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 + with: + app-id: ${{ vars.PIXI_LOCK_REFRESH_APP_ID }} + private-key: ${{ secrets.PIXI_LOCK_REFRESH_APP_PRIVATE_KEY }} + - name: Setup pixi # Pinned to a commit SHA; install logic lives in the action and is # auditable/pinned (vs. a curl|bash of an unverified installer). @@ -105,11 +107,43 @@ jobs: - name: Update lockfile without installing run: pixi update --no-install --manifest-path "${{ matrix.manifest }}" + - name: Compose PR body + id: pr-body + env: + WORKSPACE_ID: ${{ matrix.id }} + MANIFEST: ${{ matrix.manifest }} + HAS_APP_TOKEN: ${{ steps.app-token.outputs.token != '' }} + run: | + body_path="${RUNNER_TEMP}/pixi-lock-refresh-body.md" + { + echo "Automated lockfile refresh for \`${WORKSPACE_ID}\`" \ + "(\`pixi update --no-install --manifest-path ${MANIFEST}\`)." + echo + echo "This PR is workspace-scoped so other packages are not forced to review" + echo "unrelated solver churn. See #2298." + echo + if [ "${HAS_APP_TOKEN}" != "true" ]; then + echo "> [!IMPORTANT]" + echo "> No refresh App token is configured, so this PR was opened with" + echo "> \`GITHUB_TOKEN\` and GitHub will not deliver its \`pull_request\` events." + echo "> Required checks stay pending until a maintainer nudges the branch, by" + echo "> closing and reopening the PR or pushing an empty commit to it." + echo + fi + echo "If the diff looks wrong, close this PR and leave the branch deleted; the" + echo "next scheduled run opens a fresh one if an update is still needed." + } > "${body_path}" + echo "path=${body_path}" >> "${GITHUB_OUTPUT}" + + if [ "${HAS_APP_TOKEN}" != "true" ]; then + echo "::warning::Opened with GITHUB_TOKEN; the refresh PR's checks must be triggered manually." + fi + - name: Open or update a lockfile-only PR id: cpr uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: - token: ${{ github.token }} + token: ${{ steps.app-token.outputs.token || github.token }} add-paths: ${{ matrix.lockfile }} commit-message: | chore: refresh pixi.lock for ${{ matrix.id }} @@ -123,12 +157,7 @@ jobs: labels: | CI/CD dependencies - body: | - Automated lockfile refresh for `${{ matrix.id }}` (`pixi update --no-install --manifest-path ${{ matrix.manifest }}`). - - This PR is workspace-scoped so other packages are not forced to review unrelated solver churn. See #2298. - - If the diff looks wrong, close this PR and leave the branch deleted; the next scheduled run will open a fresh one if an update is still needed. + body-path: ${{ steps.pr-body.outputs.path }} author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> diff --git a/.github/workflows/ci-pixi-source-test.yml b/.github/workflows/ci-pixi-source-test.yml index 7f310b1af42..1dd12dd3980 100644 --- a/.github/workflows/ci-pixi-source-test.yml +++ b/.github/workflows/ci-pixi-source-test.yml @@ -38,6 +38,9 @@ on: paths: - "**/pixi.toml" - "**/pixi.lock" + # Path-dependency metadata (including cuda_python_test_helpers) feeds the + # solve, so it can break the source build without a pixi.toml edit. + - "**/pyproject.toml" - "cuda_bindings/build_hooks.py" - "cuda_core/build_hooks.py" - "cuda_bindings/cuda/bindings/**" # generated bindings sources @@ -67,7 +70,7 @@ env: # Install from the committed lockfile only. Covers nested `pixi run` calls # from root pixi.toml tasks; a stale lock must fail rather than being # refreshed in CI (#2298). Equivalent to `pixi run --locked`. - PIXI_LOCKED: "1" + PIXI_LOCKED: "true" jobs: # ── PR guard: CPU-only build + import + placement smoke ── @@ -90,7 +93,7 @@ jobs: - name: Setup pixi # Pinned to a commit SHA; install logic lives in the action and is # auditable/pinned (vs. a curl|bash of an unverified installer). - uses: prefix-dev/setup-pixi@d3f436a425481402e6a95a1d1fc10331c708cd9e # v0.10.2 + uses: prefix-dev/setup-pixi@5185adfbffb4bd703da3010310260805d89ebb11 # v0.9.6 with: pixi-version: ${{ env.PIXI_VERSION }} run-install: false @@ -151,7 +154,7 @@ jobs: - name: Setup pixi # Pinned to a commit SHA; install logic lives in the action and is # auditable/pinned (vs. a curl|bash of an unverified installer). - uses: prefix-dev/setup-pixi@d3f436a425481402e6a95a1d1fc10331c708cd9e # v0.10.2 + uses: prefix-dev/setup-pixi@5185adfbffb4bd703da3010310260805d89ebb11 # v0.9.6 with: pixi-version: ${{ env.PIXI_VERSION }} run-install: false @@ -216,7 +219,7 @@ jobs: - name: Setup pixi # Pinned to a commit SHA; install logic lives in the action and is # auditable/pinned (vs. a curl|bash of an unverified installer). - uses: prefix-dev/setup-pixi@d3f436a425481402e6a95a1d1fc10331c708cd9e # v0.10.2 + uses: prefix-dev/setup-pixi@5185adfbffb4bd703da3010310260805d89ebb11 # v0.9.6 with: pixi-version: ${{ env.PIXI_VERSION }} run-install: false diff --git a/.github/workflows/pr-metadata-check.yml b/.github/workflows/pr-metadata-check.yml index 89f6304a67d..076d0d47e3b 100644 --- a/.github/workflows/pr-metadata-check.yml +++ b/.github/workflows/pr-metadata-check.yml @@ -32,7 +32,11 @@ jobs: PR_NUMBER: ${{ github.event.pull_request.number }} GH_REPO: ${{ github.repository }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - IS_BOT: ${{ github.actor == 'dependabot[bot]' || github.actor == 'pre-commit-ci[bot]' || github.actor == 'copy-pr-bot[bot]' || github.actor == 'github-actions[bot]' }} + # Keyed on the PR author, not the actor: a maintainer labelling a bot + # PR re-triggers this workflow as themselves. Any bot author is + # exempt because none of them can set an assignee or milestone + # (e.g. the App identity used by the pixi lockfile refresh). + IS_BOT: ${{ github.event.pull_request.user.type == 'Bot' || github.actor == 'dependabot[bot]' || github.actor == 'pre-commit-ci[bot]' || github.actor == 'copy-pr-bot[bot]' || github.actor == 'github-actions[bot]' }} IS_DRAFT: ${{ github.event.pull_request.draft }} run: | if [ "$IS_BOT" = "true" ] || [ "$IS_DRAFT" = "true" ]; then diff --git a/.gitignore b/.gitignore index 91c3b74a105..b8eaa5ca208 100644 --- a/.gitignore +++ b/.gitignore @@ -176,8 +176,10 @@ cython_debug/ # Dont ignore !.github/actions/build/ # pixi environments -.pixi/* -!.pixi/config.toml +# Per-workspace commands such as `pixi lock --manifest-path cuda_bindings` +# create a .pixi/ next to that manifest, so match at any depth. +**/.pixi/* +!**/.pixi/config.toml # Cursor .cursorrules diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c188ca372cd..0061809a946 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -195,7 +195,12 @@ Contributor expectations: $ pixi lock --manifest-path cuda_core ``` - Use `--manifest-path .` for the repository-root environment. + Use `--manifest-path .` for the repository-root environment. Regenerate with + the pixi version CI pins in `PIXI_VERSION` (see + `.github/workflows/ci-pixi-source-test.yml`): different pixi versions write + different canonical forms, such as the `pixi.lock` format version or the + generated platform alias names, and CI requires the committed bytes to match + what the pinned version produces. - If a PR does not intentionally change pixi dependencies or metadata, do not include unrelated lockfile churn. `pixi run` can refresh a stale lockfile implicitly; revert that noise unless the refresh is the point of the change. @@ -204,15 +209,30 @@ Contributor expectations: dedicated lockfile-only PR over mixing solver churn into an unrelated change. CI enforces the contract: `pixi lock --check` fails when a committed lockfile is -stale, and pixi source-build jobs run with `PIXI_LOCKED=1` so they install from +stale, and pixi source-build jobs run with `PIXI_LOCKED=true` so they install from the committed lock rather than updating it during the job. If either check fails, regenerate and commit the affected lockfile. +The freshness check additionally fails when the check itself rewrote a lockfile. +`pixi lock --check` accepts a lock whose solution is current but whose bytes are +not canonical for the pinned pixi version, quietly normalizing the file instead, +which leaves every later pixi run rewriting the committed lockfile. + A scheduled workflow (`CI: pixi lockfile refresh`) runs `pixi update --no-install` per workspace and opens a dedicated PR when that lockfile changes, so broad dependency churn is reviewed as maintenance rather than landing inside unrelated feature work. The workflow can also be dispatched -manually for one package or for all of them. +manually for one workspace or for all of them. Its dispatch input and every +lockfile CI matrix resolve through `ci/tools/list_pixi_workspaces.py`, which +derives the workspace list from the committed manifests, so a newly added +workspace is picked up without editing any workflow. + +Those refresh PRs need an App token to pick up CI on their own: GitHub does not +deliver workflow-triggering events for branches pushed with `GITHUB_TOKEN`. Set +the `PIXI_LOCK_REFRESH_APP_ID` variable and `PIXI_LOCK_REFRESH_APP_PRIVATE_KEY` +secret to enable that path. Until they are set, the workflow says so in the PR +body and in a run warning, and required checks stay pending until a maintainer +closes and reopens the PR or pushes to its branch. ## Secret Scanning diff --git a/benchmarks/cuda_core/pixi.lock b/benchmarks/cuda_core/pixi.lock index 40642f8b88e..4cda778b118 100644 --- a/benchmarks/cuda_core/pixi.lock +++ b/benchmarks/cuda_core/pixi.lock @@ -6,7 +6,7 @@ platforms: - __linux=4.18 - __glibc=2.28 - __archspec=0=x86_64 -- name: linux-64-cuda-13 +- name: p1 subdir: linux-64 virtual-packages: - __cuda=13 @@ -27,7 +27,7 @@ environments: options: channel-priority: disabled packages: - linux-64-cuda-13: + p1: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda @@ -101,7 +101,7 @@ environments: options: channel-priority: disabled packages: - linux-64-cuda-13: + p1: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda diff --git a/ci/tools/list_pixi_workspaces.py b/ci/tools/list_pixi_workspaces.py new file mode 100644 index 00000000000..78930266ac7 --- /dev/null +++ b/ci/tools/list_pixi_workspaces.py @@ -0,0 +1,99 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""List the checked-in pixi workspaces as JSON. + +Single source of truth for the pixi lockfile CI workflows, so their job +matrices cannot drift from the manifests actually committed to the repository +(see #2298). Each workspace is reported as an object with: + + id stable name used for job names and refresh branches ("root" for + the top-level workspace, otherwise the directory path) + manifest --manifest-path argument for pixi + lockfile path of the committed lockfile + +Every manifest must have a sibling lockfile; a missing one is an error rather +than a silently skipped workspace. +""" + +from __future__ import annotations + +import argparse +import json +import subprocess +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +ROOT_WORKSPACE_ID = "root" +ALL = "all" + + +def discover() -> list[dict[str, str]]: + """Return every tracked pixi workspace, ordered by manifest path.""" + tracked = subprocess.run( # noqa: S603 - argv is passed directly without a shell. + ["git", "-C", str(ROOT), "ls-files", "-z", "pixi.toml", "*/pixi.toml"], # noqa: S607 + capture_output=True, + check=True, + text=True, + ).stdout + # Root workspace first, then nested ones by path, so job names and matrix + # order stay stable as workspaces are added. + manifests = sorted((path for path in tracked.split("\0") if path), key=lambda p: (p != "pixi.toml", p)) + if not manifests: + raise RuntimeError(f"no tracked pixi.toml found under {ROOT}") + + workspaces: list[dict[str, str]] = [] + missing: list[str] = [] + for manifest in manifests: + directory = str(Path(manifest).parent.as_posix()) + lockfile = "pixi.lock" if directory == "." else f"{directory}/pixi.lock" + if not (ROOT / lockfile).is_file(): + missing.append(f"{manifest} has no committed {lockfile}") + continue + workspaces.append( + { + "id": ROOT_WORKSPACE_ID if directory == "." else directory, + "manifest": directory, + "lockfile": lockfile, + } + ) + + if missing: + raise RuntimeError("incomplete pixi workspaces:\n - " + "\n - ".join(missing)) + return workspaces + + +def main() -> int: + """Print the workspace inventory, optionally narrowed to one workspace.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--select", + default=ALL, + help=f"workspace id to keep, or {ALL!r} (the default) for every workspace", + ) + args = parser.parse_args() + + try: + workspaces = discover() + except (RuntimeError, subprocess.CalledProcessError) as exc: + print(f"error: {exc}", file=sys.stderr) + return 2 + + if args.select != ALL: + selected = [w for w in workspaces if w["id"] == args.select] + if not selected: + valid = ", ".join([ALL, *(w["id"] for w in workspaces)]) + print( + f"error: unknown pixi workspace {args.select!r}; expected one of: {valid}", + file=sys.stderr, + ) + return 1 + workspaces = selected + + print(json.dumps(workspaces)) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/ci/tools/tests/test_list_pixi_workspaces.py b/ci/tools/tests/test_list_pixi_workspaces.py new file mode 100644 index 00000000000..4e88e9d7aba --- /dev/null +++ b/ci/tools/tests/test_list_pixi_workspaces.py @@ -0,0 +1,109 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +from __future__ import annotations + +import json +import subprocess +import sys +from pathlib import Path + +import pytest + +sys.path.insert(0, str(Path(__file__).parent.parent)) +import list_pixi_workspaces + + +def _make_repo(root: Path, manifests: list[str], *, lockfiles: list[str] | None = None) -> None: + """Create a git repo tracking the given pixi manifests and their lockfiles.""" + if lockfiles is None: + lockfiles = [str(Path(m).parent / "pixi.lock") for m in manifests] + subprocess.run(["git", "init", "-q", str(root)], check=True) # noqa: S603,S607 + for rel in [*manifests, *lockfiles]: + path = root / rel + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text("", encoding="utf-8") + subprocess.run(["git", "-C", str(root), "add", "-A"], check=True) # noqa: S603,S607 + + +@pytest.mark.agent_authored(model="claude-opus-5") +def test_discover_this_repo(): + workspaces = list_pixi_workspaces.discover() + by_id = {w["id"]: w for w in workspaces} + assert by_id["root"] == {"id": "root", "manifest": ".", "lockfile": "pixi.lock"} + for workspace in workspaces: + assert (list_pixi_workspaces.ROOT / workspace["manifest"] / "pixi.toml").is_file() + assert (list_pixi_workspaces.ROOT / workspace["lockfile"]).is_file() + + +@pytest.mark.agent_authored(model="claude-opus-5") +def test_discover_reports_root_and_nested(tmp_path, monkeypatch): + _make_repo(tmp_path, ["pixi.toml", "cuda_core/pixi.toml", "benchmarks/cuda_core/pixi.toml"]) + monkeypatch.setattr(list_pixi_workspaces, "ROOT", tmp_path) + assert list_pixi_workspaces.discover() == [ + {"id": "root", "manifest": ".", "lockfile": "pixi.lock"}, + { + "id": "benchmarks/cuda_core", + "manifest": "benchmarks/cuda_core", + "lockfile": "benchmarks/cuda_core/pixi.lock", + }, + {"id": "cuda_core", "manifest": "cuda_core", "lockfile": "cuda_core/pixi.lock"}, + ] + + +@pytest.mark.agent_authored(model="claude-opus-5") +def test_discover_ignores_untracked_manifest(tmp_path, monkeypatch): + _make_repo(tmp_path, ["pixi.toml"]) + (tmp_path / "scratch").mkdir() + (tmp_path / "scratch" / "pixi.toml").write_text("", encoding="utf-8") + (tmp_path / "scratch" / "pixi.lock").write_text("", encoding="utf-8") + monkeypatch.setattr(list_pixi_workspaces, "ROOT", tmp_path) + assert [w["id"] for w in list_pixi_workspaces.discover()] == ["root"] + + +@pytest.mark.agent_authored(model="claude-opus-5") +def test_discover_rejects_manifest_without_lockfile(tmp_path, monkeypatch): + _make_repo(tmp_path, ["pixi.toml", "cuda_core/pixi.toml"], lockfiles=["pixi.lock"]) + monkeypatch.setattr(list_pixi_workspaces, "ROOT", tmp_path) + with pytest.raises(RuntimeError, match=r"cuda_core/pixi.toml has no committed cuda_core/pixi.lock"): + list_pixi_workspaces.discover() + + +@pytest.mark.agent_authored(model="claude-opus-5") +def test_discover_rejects_repo_without_manifests(tmp_path, monkeypatch): + _make_repo(tmp_path, [], lockfiles=[]) + monkeypatch.setattr(list_pixi_workspaces, "ROOT", tmp_path) + with pytest.raises(RuntimeError, match="no tracked pixi.toml"): + list_pixi_workspaces.discover() + + +@pytest.mark.agent_authored(model="claude-opus-5") +def test_main_selects_one_workspace(tmp_path, monkeypatch, capsys): + _make_repo(tmp_path, ["pixi.toml", "cuda_core/pixi.toml"]) + monkeypatch.setattr(list_pixi_workspaces, "ROOT", tmp_path) + monkeypatch.setattr(sys, "argv", ["list_pixi_workspaces.py", "--select", "cuda_core"]) + assert list_pixi_workspaces.main() == 0 + assert json.loads(capsys.readouterr().out) == [ + {"id": "cuda_core", "manifest": "cuda_core", "lockfile": "cuda_core/pixi.lock"} + ] + + +@pytest.mark.agent_authored(model="claude-opus-5") +def test_main_rejects_unknown_workspace(tmp_path, monkeypatch, capsys): + _make_repo(tmp_path, ["pixi.toml", "cuda_core/pixi.toml"]) + monkeypatch.setattr(list_pixi_workspaces, "ROOT", tmp_path) + monkeypatch.setattr(sys, "argv", ["list_pixi_workspaces.py", "--select", "cuda_kore"]) + assert list_pixi_workspaces.main() == 1 + captured = capsys.readouterr() + assert captured.out == "" + assert "unknown pixi workspace 'cuda_kore'" in captured.err + assert "expected one of: all, root, cuda_core" in captured.err + + +@pytest.mark.agent_authored(model="claude-opus-5") +def test_main_defaults_to_every_workspace(tmp_path, monkeypatch, capsys): + _make_repo(tmp_path, ["pixi.toml", "cuda_core/pixi.toml"]) + monkeypatch.setattr(list_pixi_workspaces, "ROOT", tmp_path) + monkeypatch.setattr(sys, "argv", ["list_pixi_workspaces.py"]) + assert list_pixi_workspaces.main() == 0 + assert [w["id"] for w in json.loads(capsys.readouterr().out)] == ["root", "cuda_core"] diff --git a/pixi.lock b/pixi.lock index 73cfe5fcffc..45afc2f8fd9 100644 --- a/pixi.lock +++ b/pixi.lock @@ -1,15 +1,29 @@ -version: 6 +version: 7 +platforms: +- name: linux-64 + virtual-packages: + - __unix=0=0 + - __linux=4.18 + - __glibc=2.28 + - __archspec=0=x86_64 +- name: linux-aarch64 + virtual-packages: + - __unix=0=0 + - __linux=4.18 + - __glibc=2.28 + - __archspec=0=aarch64 +- name: win-64 + virtual-packages: + - __win=10.0 + - __archspec=0=x86_64 environments: cu12: channels: - url: https://conda.anaconda.org/conda-forge/ - options: - pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda @@ -23,16 +37,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.6-habeac84_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.15.22-h462bb3b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd70dff1_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda linux-aarch64: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_1.conda @@ -48,15 +62,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-hf8d1292_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.3-h546c87b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.6-hc679e19_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruff-0.15.22-hd82de44_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h5cf4473_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda win-64: - - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.8.1-hac47afa_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.3-hfd05255_0.conda @@ -65,10 +82,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.3-hf411b9b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.14.6-h4b44e0e_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ruff-0.15.22-h6b72154_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h967ab96_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.5-h1b7c187_39.conda - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.51.36231-h1b9f54f_39.conda @@ -77,13 +92,10 @@ environments: cu13: channels: - url: https://conda.anaconda.org/conda-forge/ - options: - pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda @@ -97,16 +109,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.6-habeac84_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.15.22-h462bb3b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd70dff1_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda linux-aarch64: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_1.conda @@ -122,15 +134,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-hf8d1292_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.3-h546c87b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.6-hc679e19_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruff-0.15.22-hd82de44_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h5cf4473_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda win-64: - - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.8.1-hac47afa_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.3-hfd05255_0.conda @@ -139,10 +154,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.3-hf411b9b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.14.6-h4b44e0e_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ruff-0.15.22-h6b72154_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h967ab96_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.5-h1b7c187_39.conda - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.51.36231-h1b9f54f_39.conda @@ -151,13 +164,10 @@ environments: default: channels: - url: https://conda.anaconda.org/conda-forge/ - options: - pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda @@ -171,16 +181,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.6-habeac84_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.15.22-h462bb3b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd70dff1_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda linux-aarch64: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_1.conda @@ -196,15 +206,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-hf8d1292_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.3-h546c87b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.6-hc679e19_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruff-0.15.22-hd82de44_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h5cf4473_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda win-64: - - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.8.1-hac47afa_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.3-hfd05255_0.conda @@ -213,10 +226,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.3-hf411b9b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.14.6-h4b44e0e_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ruff-0.15.22-h6b72154_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h967ab96_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.5-h1b7c187_39.conda - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.51.36231-h1b9f54f_39.conda @@ -225,13 +236,10 @@ environments: docs: channels: - url: https://conda.anaconda.org/conda-forge/ - options: - pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda @@ -245,16 +253,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.6-habeac84_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.15.22-h462bb3b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd70dff1_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda linux-aarch64: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_1.conda @@ -270,15 +278,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-hf8d1292_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.3-h546c87b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.6-hc679e19_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruff-0.15.22-hd82de44_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h5cf4473_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda win-64: - - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.8.1-hac47afa_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.3-hfd05255_0.conda @@ -287,10 +298,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.3-hf411b9b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.14.6-h4b44e0e_100_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ruff-0.15.22-h6b72154_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h967ab96_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.5-h1b7c187_39.conda - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.51.36231-h1b9f54f_39.conda @@ -310,18 +319,6 @@ packages: license_family: BSD size: 28948 timestamp: 1770939786096 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda - build_number: 20 - sha256: a2527b1d81792a0ccd2c05850960df119c2b6d8f5fdec97f2db7d25dc23b1068 - md5: 468fd3bb9e1f671d36c2cbc677e56f1d - depends: - - libgomp >=7.5.0 - constrains: - - openmp_impl <0.0a0 - license: BSD-3-Clause - license_family: BSD - size: 28926 - timestamp: 1770939656741 - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6 md5: d2ffd7602c02f2b316fd921d39876885 @@ -332,51 +329,6 @@ packages: license_family: BSD size: 260182 timestamp: 1771350215188 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda - sha256: b3495077889dde6bb370938e7db82be545c73e8589696ad0843a32221520ad4c - md5: 840d8fc0d7b3209be93080bc20e07f2d - depends: - - libgcc >=14 - license: bzip2-1.0.6 - license_family: BSD - size: 192412 - timestamp: 1771350241232 -- conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda - sha256: 76dfb71df5e8d1c4eded2dbb5ba15bb8fb2e2b0fe42d94145d5eed4c75c35902 - md5: 4cb8e6b48f67de0b018719cdf1136306 - depends: - - ucrt >=10.0.20348.0 - - vc >=14.3,<15 - - vc14_runtime >=14.44.35208 - license: bzip2-1.0.6 - license_family: BSD - size: 56115 - timestamp: 1771350256444 -- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-h4c7d964_0.conda - sha256: 7f458e4a82514d7bebbfef23d92817794a16aaf1c748a15f04870d4fb49aeab2 - md5: b9696b2cf00dfeec138c70cee38ed192 - depends: - - __win - license: ISC - size: 129352 - timestamp: 1781709016515 -- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda - sha256: f8e3c730fa14ee3f170493779f06522c4acf89169f43db4f039727709b6419cf - md5: a9965dd99f683c5f444428f896635716 - depends: - - __unix - license: ISC - size: 128866 - timestamp: 1781708962055 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_1.conda - sha256: ba4e1acdaf6c66961d6a1863c10851dde2378fa18af48de0156b9874556ca438 - md5: da55da4ed68dcac1ce28faa0a3450b65 - depends: - - libgcc >=14 - - libstdcxx >=14 - license: MIT - size: 12870753 - timestamp: 1784588696185 - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda sha256: 27d83f1188cd19bcb7754a078b3fa7f4cfb8527f8eb2fde54dd01fc529d1adec md5: 449500f2c089da11c40f5c21312e3e07 @@ -389,17 +341,6 @@ packages: license_family: GPL size: 745303 timestamp: 1784214507189 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_102.conda - sha256: 2c4901f4227b0850328ed0c69f958b30ad2cd18982f7a31c7c1f911827004d08 - md5: 489444d0acb2a579d2a002d85a08c059 - depends: - - zstd >=1.5.7,<1.6.0a0 - constrains: - - binutils_impl_linux-aarch64 2.46.1 - license: GPL-3.0-only - license_family: GPL - size: 905305 - timestamp: 1784214534868 - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda sha256: 16feffd9ddbbe5b718515d38ee376c685ba95491cd901244e24671d20b952a77 md5: b24d3c612f71e7aa74158d92106318b2 @@ -412,30 +353,6 @@ packages: license_family: MIT size: 77856 timestamp: 1781203599810 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_1.conda - sha256: 20a5726bc8705d91437c9e6ef83b30da64a1719b869656d20a1ee818333ea5ac - md5: fac3b65a605cd253037fdf3daf2de8d9 - depends: - - libgcc >=14 - constrains: - - expat 2.8.1.* - license: MIT - license_family: MIT - size: 77649 - timestamp: 1781203572523 -- conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.8.1-hac47afa_1.conda - sha256: 1a54d874addda73b6f7164d5f3905821277a1831bcc05edd74b3085391688571 - md5: ccc490c81ffe14181861beac0e8f3169 - depends: - - ucrt >=10.0.20348.0 - - vc >=14.3,<15 - - vc14_runtime >=14.44.35208 - constrains: - - expat 2.8.1.* - license: MIT - license_family: MIT - size: 71631 - timestamp: 1781203724164 - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda sha256: 31f19b6a88ce40ebc0d5a992c131f57d919f73c0b92cd1617a5bec83f6e961e6 md5: a360c33a5abe61c07959e449fa1453eb @@ -446,26 +363,6 @@ packages: license_family: MIT size: 58592 timestamp: 1769456073053 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda - sha256: 3df4c539449aabc3443bbe8c492c01d401eea894603087fca2917aa4e1c2dea9 - md5: 2f364feefb6a7c00423e80dcb12db62a - depends: - - libgcc >=14 - license: MIT - license_family: MIT - size: 55952 - timestamp: 1769456078358 -- conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda - sha256: 59d01f2dfa8b77491b5888a5ab88ff4e1574c9359f7e229da254cdfe27ddc190 - md5: 720b39f5ec0610457b725eb3f396219a - depends: - - ucrt >=10.0.20348.0 - - vc >=14.3,<15 - - vc14_runtime >=14.44.35208 - license: MIT - license_family: MIT - size: 45831 - timestamp: 1769456418774 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda sha256: 8e0a3b5e41272e5678499b5dfc4cddb673f9e935de01eb0767ce857001229f46 md5: 57736f29cc2b0ec0b6c2952d3f101b6a @@ -479,18 +376,6 @@ packages: license_family: GPL size: 1041084 timestamp: 1778269013026 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_19.conda - sha256: 4592b096e553f67799ae70d4b6167eeda3ec74587d68c7aecbf4e7b1df136681 - md5: f35b3f52d0a2ec4ffe3c89ba135cdb9a - depends: - - _openmp_mutex >=4.5 - constrains: - - libgomp 15.2.0 h8acb6b2_19 - - libgcc-ng ==15.2.0=*_19 - license: GPL-3.0-only WITH GCC-exception-3.1 - license_family: GPL - size: 622462 - timestamp: 1778268755949 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda sha256: 5abe4ab9d93f6c9757d654f1969ae2267d4505315c1f2f8fe705fd60af084f1b md5: faac990cb7aedc7f3a2224f2c9b0c26c @@ -500,13 +385,6 @@ packages: license_family: GPL size: 603817 timestamp: 1778268942614 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_19.conda - sha256: 2370ef0ffcbae5bede3c4bf136add4abc257245eb91f724c99bb4a43116c5a83 - md5: c5e8a379c4a2ec2aea4ba22758c001d9 - license: GPL-3.0-only WITH GCC-exception-3.1 - license_family: GPL - size: 587387 - timestamp: 1778268674393 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda sha256: ec30e52a3c1bf7d0425380a189d209a52baa03f22fb66dd3eb587acaa765bd6d md5: b88d90cad08e6bc8ad540cb310a761fb @@ -518,28 +396,6 @@ packages: license: 0BSD size: 113478 timestamp: 1775825492909 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_0.conda - sha256: d61962b9cd54c3554361550203c64d5b65b71e3058a285b66e4b04b9769f0a5c - md5: 76298a9e6d71ee6e832a8d0d7373b261 - depends: - - libgcc >=14 - constrains: - - xz 5.8.3.* - license: 0BSD - size: 126102 - timestamp: 1775828008518 -- conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.3-hfd05255_0.conda - sha256: d636d1a25234063642f9c531a7bb58d84c1c496411280a36ea000bd122f078f1 - md5: 8f83619ab1588b98dd99c90b0bfc5c6d - depends: - - ucrt >=10.0.20348.0 - - vc >=14.3,<15 - - vc14_runtime >=14.44.35208 - constrains: - - xz 5.8.3.* - license: 0BSD - size: 106486 - timestamp: 1775825663227 - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda sha256: fe171ed5cf5959993d43ff72de7596e8ac2853e9021dec0344e583734f1e0843 md5: 2c21e66f50753a083cbe6b80f38268fa @@ -550,26 +406,6 @@ packages: license_family: BSD size: 92400 timestamp: 1769482286018 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda - sha256: 57c0dd12d506e84541c4e877898bd2a59cca141df493d34036f18b2751e0a453 - md5: 7b9813e885482e3ccb1fa212b86d7fd0 - depends: - - libgcc >=14 - license: BSD-2-Clause - license_family: BSD - size: 114056 - timestamp: 1769482343003 -- conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-hfd05255_1.conda - sha256: 40dcd0b9522a6e0af72a9db0ced619176e7cfdb114855c7a64f278e73f8a7514 - md5: e4a9fc2bba3b022dad998c78856afe47 - depends: - - ucrt >=10.0.20348.0 - - vc >=14.3,<15 - - vc14_runtime >=14.44.35208 - license: BSD-2-Clause - license_family: BSD - size: 89411 - timestamp: 1769482314283 - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.3-h0c1763c_0.conda sha256: 365376f4815e5e80def2b3462a2419708b7c292da0da85278386c2618621fff4 md5: 4aed8e657e9ff156bdbe849b4df44389 @@ -580,16 +416,438 @@ packages: license: blessing size: 962119 timestamp: 1782519076616 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.53.3-h10b116e_0.conda - sha256: a835400072fb638fb582ee9fc2271169da84cbcad664d28b852610201116027e - md5: 2cd50877f494b34383af22560ced8b04 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.2-h5347b49_0.conda + sha256: 9b1bdce27a7e31f7d241aeecff67a1f3101d52a2b1e33ccc2cdf2613072bf81f + md5: 01bb81d12c957de066ea7362007df642 depends: - - icu >=78.3,<79.0a0 - libgcc >=14 - - libzlib >=1.3.2,<2.0a0 - license: blessing - size: 968420 - timestamp: 1782519054102 + - __glibc >=2.17,<3.0.a0 + license: BSD-3-Clause + license_family: BSD + size: 40017 + timestamp: 1781625522462 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9 + md5: d87ff7921124eccd67248aa483c23fec + depends: + - __glibc >=2.17,<3.0.a0 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + size: 63629 + timestamp: 1774072609062 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda + sha256: fc89f74bbe362fb29fa3c037697a89bec140b346a2469a90f7936d1d7ea4d8a3 + md5: fc21868a1a5aacc937e7a18747acb8a5 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: X11 AND BSD-3-Clause + size: 918956 + timestamp: 1777422145199 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_0.conda + sha256: d48f5c22b9897c01e4dff3680f1f57ceb02711ab9c62f74339b080419dfad34b + md5: 79dd2074b5cd5c5c6b2930514a11e22d + depends: + - __glibc >=2.17,<3.0.a0 + - ca-certificates + - libgcc >=14 + license: Apache-2.0 + license_family: Apache + size: 3159683 + timestamp: 1781069855778 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.6-habeac84_100_cp314.conda + build_number: 100 + sha256: 6d28ac2b061179deb434d3d57afa98ffd20ec3c5d44ab8048a1ca33424b22d38 + md5: 0b9b2f83b5b600e1ac38becde8d0dd44 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.8.1,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.3,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.53.2,<4.0a0 + - libuuid >=2.42.1,<3.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 + - openssl >=3.5.7,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + size: 36717183 + timestamp: 1781255094700 + python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + sha256: 12ffde5a6f958e285aa22c191ca01bbd3d6e710aa852e00618fa6ddc59149002 + md5: d7d95fc8287ea7bf33e0e7116d2b95ec + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + size: 345073 + timestamp: 1765813471974 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.15.22-h462bb3b_0.conda + noarch: python + sha256: 2002c7869a95ed94b03303a033fcc24b608597bdd01c8f01d90c47175616edb9 + md5: ad7d8b2d37a1098a04ddd8b34b962481 + depends: + - python + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - __glibc >=2.17 + license: MIT + license_family: MIT + size: 9333318 + timestamp: 1784237314764 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd70dff1_3.conda + build_number: 103 + sha256: 43624eab22f5f29df7d6ffe914cf442f28fd559b55b290906255492826e636e8 + md5: 48a1049e710857572fc2a832aa394d9f + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libzlib >=1.3.2,<2.0a0 + constrains: + - xorg-libx11 >=1.8.13,<2.0a0 + license: TCL + size: 3550916 + timestamp: 1784229071544 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7 + md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829 + depends: + - __glibc >=2.17,<3.0.a0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + size: 601375 + timestamp: 1764777111296 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + build_number: 20 + sha256: a2527b1d81792a0ccd2c05850960df119c2b6d8f5fdec97f2db7d25dc23b1068 + md5: 468fd3bb9e1f671d36c2cbc677e56f1d + depends: + - libgomp >=7.5.0 + constrains: + - openmp_impl <0.0a0 + license: BSD-3-Clause + license_family: BSD + size: 28926 + timestamp: 1770939656741 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda + sha256: b3495077889dde6bb370938e7db82be545c73e8589696ad0843a32221520ad4c + md5: 840d8fc0d7b3209be93080bc20e07f2d + depends: + - libgcc >=14 + license: bzip2-1.0.6 + license_family: BSD + size: 192412 + timestamp: 1771350241232 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_1.conda + sha256: ba4e1acdaf6c66961d6a1863c10851dde2378fa18af48de0156b9874556ca438 + md5: da55da4ed68dcac1ce28faa0a3450b65 + depends: + - libgcc >=14 + - libstdcxx >=14 + license: MIT + size: 12870753 + timestamp: 1784588696185 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_102.conda + sha256: 2c4901f4227b0850328ed0c69f958b30ad2cd18982f7a31c7c1f911827004d08 + md5: 489444d0acb2a579d2a002d85a08c059 + depends: + - zstd >=1.5.7,<1.6.0a0 + constrains: + - binutils_impl_linux-aarch64 2.46.1 + license: GPL-3.0-only + license_family: GPL + size: 905305 + timestamp: 1784214534868 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_1.conda + sha256: 20a5726bc8705d91437c9e6ef83b30da64a1719b869656d20a1ee818333ea5ac + md5: fac3b65a605cd253037fdf3daf2de8d9 + depends: + - libgcc >=14 + constrains: + - expat 2.8.1.* + license: MIT + license_family: MIT + size: 77649 + timestamp: 1781203572523 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda + sha256: 3df4c539449aabc3443bbe8c492c01d401eea894603087fca2917aa4e1c2dea9 + md5: 2f364feefb6a7c00423e80dcb12db62a + depends: + - libgcc >=14 + license: MIT + license_family: MIT + size: 55952 + timestamp: 1769456078358 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_19.conda + sha256: 4592b096e553f67799ae70d4b6167eeda3ec74587d68c7aecbf4e7b1df136681 + md5: f35b3f52d0a2ec4ffe3c89ba135cdb9a + depends: + - _openmp_mutex >=4.5 + constrains: + - libgomp 15.2.0 h8acb6b2_19 + - libgcc-ng ==15.2.0=*_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 622462 + timestamp: 1778268755949 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_19.conda + sha256: 2370ef0ffcbae5bede3c4bf136add4abc257245eb91f724c99bb4a43116c5a83 + md5: c5e8a379c4a2ec2aea4ba22758c001d9 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 587387 + timestamp: 1778268674393 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_0.conda + sha256: d61962b9cd54c3554361550203c64d5b65b71e3058a285b66e4b04b9769f0a5c + md5: 76298a9e6d71ee6e832a8d0d7373b261 + depends: + - libgcc >=14 + constrains: + - xz 5.8.3.* + license: 0BSD + size: 126102 + timestamp: 1775828008518 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda + sha256: 57c0dd12d506e84541c4e877898bd2a59cca141df493d34036f18b2751e0a453 + md5: 7b9813e885482e3ccb1fa212b86d7fd0 + depends: + - libgcc >=14 + license: BSD-2-Clause + license_family: BSD + size: 114056 + timestamp: 1769482343003 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.53.3-h10b116e_0.conda + sha256: a835400072fb638fb582ee9fc2271169da84cbcad664d28b852610201116027e + md5: 2cd50877f494b34383af22560ced8b04 + depends: + - icu >=78.3,<79.0a0 + - libgcc >=14 + - libzlib >=1.3.2,<2.0a0 + license: blessing + size: 968420 + timestamp: 1782519054102 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_19.conda + sha256: 1dadc45e599f510dd5f97141dddcdbb9844d9f1430c1f3a38075cf1c58f87b4e + md5: 543fbc8d71f2a0baf04cf88ce96cb8bb + depends: + - libgcc 15.2.0 h8acb6b2_19 + constrains: + - libstdcxx-ng ==15.2.0=*_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 5546559 + timestamp: 1778268777463 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42.2-h1022ec0_0.conda + sha256: 7663489f97c104ae3814db10f384932c74b439f3c1fd4247e4fe3599830c090a + md5: 58fa42bc4bc71fc329889497ec15effb + depends: + - libgcc >=14 + license: BSD-3-Clause + license_family: BSD + size: 43248 + timestamp: 1781625528371 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda + sha256: eb111e32e5a7313a5bf799c7fb2419051fa2fe7eff74769fac8d5a448b309f7f + md5: 502006882cf5461adced436e410046d1 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + size: 69833 + timestamp: 1774072605429 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-hf8d1292_0.conda + sha256: 369db85c5cd8d99dde364ce70725d76511d9c8199e5b820c740414091bf5bcca + md5: b2a43456aa56fe80c2477a5094899eff + depends: + - libgcc >=14 + license: X11 AND BSD-3-Clause + size: 960036 + timestamp: 1777422174534 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.3-h546c87b_0.conda + sha256: da4a5df42614166b69c2f6d8602fc1425f7aaa699f77c3bafb5c7fe69b3d9fb7 + md5: fa6260b3e6eababf6ca85a7eb3336383 + depends: + - ca-certificates + - libgcc >=14 + license: Apache-2.0 + license_family: Apache + size: 3704664 + timestamp: 1781069675555 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.6-hc679e19_100_cp314.conda + build_number: 100 + sha256: dd56fd95db3cb49a69fbe41df80afc8bd5214daa829bcd3930de80f0408ba5eb + md5: 416c74941d13d9f2b9e68b1a900f7f50 + depends: + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-aarch64 >=2.36.1 + - libexpat >=2.8.1,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.3,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.53.2,<4.0a0 + - libuuid >=2.42.1,<3.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 + - openssl >=3.5.7,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + size: 34900936 + timestamp: 1781254861576 + python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda + sha256: fe695f9d215e9a2e3dd0ca7f56435ab4df24f5504b83865e3d295df36e88d216 + md5: 3d49cad61f829f4f0e0611547a9cda12 + depends: + - libgcc >=14 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + size: 357597 + timestamp: 1765815673644 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruff-0.15.22-hd82de44_0.conda + noarch: python + sha256: 7db6db19bf42622fbb4a52bec37a57962453b45347ffffde78beef2cffc3db2e + md5: 7d7a99174374aee86591f23078a2c315 + depends: + - python + - libgcc >=14 + constrains: + - __glibc >=2.17 + license: MIT + license_family: MIT + size: 9107871 + timestamp: 1784237315859 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h5cf4473_3.conda + build_number: 103 + sha256: cd51fbda051a9f3679d10ef4a94cd1ff38c10533b82845dadce8ba87245ba4ce + md5: 89e78452e06563964e419059ee45584a + depends: + - libgcc >=14 + - libzlib >=1.3.2,<2.0a0 + constrains: + - xorg-libx11 >=1.8.13,<2.0a0 + license: TCL + size: 3683040 + timestamp: 1784229053797 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + sha256: 569990cf12e46f9df540275146da567d9c618c1e9c7a0bc9d9cfefadaed20b75 + md5: c3655f82dcea2aa179b291e7099c1fcc + depends: + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + size: 614429 + timestamp: 1764777145593 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-h4c7d964_0.conda + sha256: 7f458e4a82514d7bebbfef23d92817794a16aaf1c748a15f04870d4fb49aeab2 + md5: b9696b2cf00dfeec138c70cee38ed192 + depends: + - __win + license: ISC + size: 129352 + timestamp: 1781709016515 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda + sha256: f8e3c730fa14ee3f170493779f06522c4acf89169f43db4f039727709b6419cf + md5: a9965dd99f683c5f444428f896635716 + depends: + - __unix + license: ISC + size: 128866 + timestamp: 1781708962055 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + build_number: 8 + sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 + md5: 0539938c55b6b1a59b560e843ad864a4 + constrains: + - python 3.14.* *_cp314 + license: BSD-3-Clause + license_family: BSD + size: 6989 + timestamp: 1752805904792 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + sha256: b928c30ddcb0e3f544c6eade8352737e6e610e263276b90232db6a578ef899d8 + md5: fcb489df604d100968b737f2cb6076c6 + license: LicenseRef-Public-Domain + size: 118849 + timestamp: 1784250406640 +- conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda + sha256: 76dfb71df5e8d1c4eded2dbb5ba15bb8fb2e2b0fe42d94145d5eed4c75c35902 + md5: 4cb8e6b48f67de0b018719cdf1136306 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: bzip2-1.0.6 + license_family: BSD + size: 56115 + timestamp: 1771350256444 +- conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.8.1-hac47afa_1.conda + sha256: 1a54d874addda73b6f7164d5f3905821277a1831bcc05edd74b3085391688571 + md5: ccc490c81ffe14181861beac0e8f3169 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - expat 2.8.1.* + license: MIT + license_family: MIT + size: 71631 + timestamp: 1781203724164 +- conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda + sha256: 59d01f2dfa8b77491b5888a5ab88ff4e1574c9359f7e229da254cdfe27ddc190 + md5: 720b39f5ec0610457b725eb3f396219a + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + size: 45831 + timestamp: 1769456418774 +- conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.3-hfd05255_0.conda + sha256: d636d1a25234063642f9c531a7bb58d84c1c496411280a36ea000bd122f078f1 + md5: 8f83619ab1588b98dd99c90b0bfc5c6d + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - xz 5.8.3.* + license: 0BSD + size: 106486 + timestamp: 1775825663227 +- conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-hfd05255_1.conda + sha256: 40dcd0b9522a6e0af72a9db0ced619176e7cfdb114855c7a64f278e73f8a7514 + md5: e4a9fc2bba3b022dad998c78856afe47 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: BSD-2-Clause + license_family: BSD + size: 89411 + timestamp: 1769482314283 - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.53.3-hf5d6505_0.conda sha256: 692dfb73a22c873656d5e393b8f1e2b019a3c8a6486c97cb6900552e64e38c25 md5: 051f1b2228e7517a2ef8cca5146c8967 @@ -600,56 +858,6 @@ packages: license: blessing size: 1315909 timestamp: 1782519131898 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_19.conda - sha256: 1dadc45e599f510dd5f97141dddcdbb9844d9f1430c1f3a38075cf1c58f87b4e - md5: 543fbc8d71f2a0baf04cf88ce96cb8bb - depends: - - libgcc 15.2.0 h8acb6b2_19 - constrains: - - libstdcxx-ng ==15.2.0=*_19 - license: GPL-3.0-only WITH GCC-exception-3.1 - license_family: GPL - size: 5546559 - timestamp: 1778268777463 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.2-h5347b49_0.conda - sha256: 9b1bdce27a7e31f7d241aeecff67a1f3101d52a2b1e33ccc2cdf2613072bf81f - md5: 01bb81d12c957de066ea7362007df642 - depends: - - libgcc >=14 - - __glibc >=2.17,<3.0.a0 - license: BSD-3-Clause - license_family: BSD - size: 40017 - timestamp: 1781625522462 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42.2-h1022ec0_0.conda - sha256: 7663489f97c104ae3814db10f384932c74b439f3c1fd4247e4fe3599830c090a - md5: 58fa42bc4bc71fc329889497ec15effb - depends: - - libgcc >=14 - license: BSD-3-Clause - license_family: BSD - size: 43248 - timestamp: 1781625528371 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9 - md5: d87ff7921124eccd67248aa483c23fec - depends: - - __glibc >=2.17,<3.0.a0 - constrains: - - zlib 1.3.2 *_2 - license: Zlib - license_family: Other - size: 63629 - timestamp: 1774072609062 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda - sha256: eb111e32e5a7313a5bf799c7fb2419051fa2fe7eff74769fac8d5a448b309f7f - md5: 502006882cf5461adced436e410046d1 - constrains: - - zlib 1.3.2 *_2 - license: Zlib - license_family: Other - size: 69833 - timestamp: 1774072605429 - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda sha256: 88609816e0cc7452bac637aaf65783e5edf4fee8a9f8e22bdc3a75882c536061 md5: dbabbd6234dea34040e631f87676292f @@ -663,44 +871,6 @@ packages: license_family: Other size: 58347 timestamp: 1774072851498 -- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - sha256: fc89f74bbe362fb29fa3c037697a89bec140b346a2469a90f7936d1d7ea4d8a3 - md5: fc21868a1a5aacc937e7a18747acb8a5 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - license: X11 AND BSD-3-Clause - size: 918956 - timestamp: 1777422145199 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-hf8d1292_0.conda - sha256: 369db85c5cd8d99dde364ce70725d76511d9c8199e5b820c740414091bf5bcca - md5: b2a43456aa56fe80c2477a5094899eff - depends: - - libgcc >=14 - license: X11 AND BSD-3-Clause - size: 960036 - timestamp: 1777422174534 -- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_0.conda - sha256: d48f5c22b9897c01e4dff3680f1f57ceb02711ab9c62f74339b080419dfad34b - md5: 79dd2074b5cd5c5c6b2930514a11e22d - depends: - - __glibc >=2.17,<3.0.a0 - - ca-certificates - - libgcc >=14 - license: Apache-2.0 - license_family: Apache - size: 3159683 - timestamp: 1781069855778 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.3-h546c87b_0.conda - sha256: da4a5df42614166b69c2f6d8602fc1425f7aaa699f77c3bafb5c7fe69b3d9fb7 - md5: fa6260b3e6eababf6ca85a7eb3336383 - depends: - - ca-certificates - - libgcc >=14 - license: Apache-2.0 - license_family: Apache - size: 3704664 - timestamp: 1781069675555 - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.3-hf411b9b_0.conda sha256: cb6e7ba0d010ee0d3249ce9886de3d7613d26d9965d4c95666fa66b9c4c31001 md5: e99f95734a326c0fd4d02bbd995150d4 @@ -713,59 +883,6 @@ packages: license_family: Apache size: 9414790 timestamp: 1781071745579 -- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.6-habeac84_100_cp314.conda - build_number: 100 - sha256: 6d28ac2b061179deb434d3d57afa98ffd20ec3c5d44ab8048a1ca33424b22d38 - md5: 0b9b2f83b5b600e1ac38becde8d0dd44 - depends: - - __glibc >=2.17,<3.0.a0 - - bzip2 >=1.0.8,<2.0a0 - - ld_impl_linux-64 >=2.36.1 - - libexpat >=2.8.1,<3.0a0 - - libffi >=3.5.2,<3.6.0a0 - - libgcc >=14 - - liblzma >=5.8.3,<6.0a0 - - libmpdec >=4.0.0,<5.0a0 - - libsqlite >=3.53.2,<4.0a0 - - libuuid >=2.42.1,<3.0a0 - - libzlib >=1.3.2,<2.0a0 - - ncurses >=6.6,<7.0a0 - - openssl >=3.5.7,<4.0a0 - - python_abi 3.14.* *_cp314 - - readline >=8.3,<9.0a0 - - tk >=8.6.13,<8.7.0a0 - - tzdata - - zstd >=1.5.7,<1.6.0a0 - license: Python-2.0 - size: 36717183 - timestamp: 1781255094700 - python_site_packages_path: lib/python3.14/site-packages -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.6-hc679e19_100_cp314.conda - build_number: 100 - sha256: dd56fd95db3cb49a69fbe41df80afc8bd5214daa829bcd3930de80f0408ba5eb - md5: 416c74941d13d9f2b9e68b1a900f7f50 - depends: - - bzip2 >=1.0.8,<2.0a0 - - ld_impl_linux-aarch64 >=2.36.1 - - libexpat >=2.8.1,<3.0a0 - - libffi >=3.5.2,<3.6.0a0 - - libgcc >=14 - - liblzma >=5.8.3,<6.0a0 - - libmpdec >=4.0.0,<5.0a0 - - libsqlite >=3.53.2,<4.0a0 - - libuuid >=2.42.1,<3.0a0 - - libzlib >=1.3.2,<2.0a0 - - ncurses >=6.6,<7.0a0 - - openssl >=3.5.7,<4.0a0 - - python_abi 3.14.* *_cp314 - - readline >=8.3,<9.0a0 - - tk >=8.6.13,<8.7.0a0 - - tzdata - - zstd >=1.5.7,<1.6.0a0 - license: Python-2.0 - size: 34900936 - timestamp: 1781254861576 - python_site_packages_path: lib/python3.14/site-packages - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.14.6-h4b44e0e_100_cp314.conda build_number: 100 sha256: f1acb89cb1a6bec9a94ae9f8e7411839de009cd64d3ac6a6aec4f3d8a481099a @@ -790,64 +907,6 @@ packages: size: 18481352 timestamp: 1781256034828 python_site_packages_path: Lib/site-packages -- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - build_number: 8 - sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 - md5: 0539938c55b6b1a59b560e843ad864a4 - constrains: - - python 3.14.* *_cp314 - license: BSD-3-Clause - license_family: BSD - size: 6989 - timestamp: 1752805904792 -- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - sha256: 12ffde5a6f958e285aa22c191ca01bbd3d6e710aa852e00618fa6ddc59149002 - md5: d7d95fc8287ea7bf33e0e7116d2b95ec - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - ncurses >=6.5,<7.0a0 - license: GPL-3.0-only - license_family: GPL - size: 345073 - timestamp: 1765813471974 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda - sha256: fe695f9d215e9a2e3dd0ca7f56435ab4df24f5504b83865e3d295df36e88d216 - md5: 3d49cad61f829f4f0e0611547a9cda12 - depends: - - libgcc >=14 - - ncurses >=6.5,<7.0a0 - license: GPL-3.0-only - license_family: GPL - size: 357597 - timestamp: 1765815673644 -- conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.15.22-h462bb3b_0.conda - noarch: python - sha256: 2002c7869a95ed94b03303a033fcc24b608597bdd01c8f01d90c47175616edb9 - md5: ad7d8b2d37a1098a04ddd8b34b962481 - depends: - - python - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - constrains: - - __glibc >=2.17 - license: MIT - license_family: MIT - size: 9333318 - timestamp: 1784237314764 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruff-0.15.22-hd82de44_0.conda - noarch: python - sha256: 7db6db19bf42622fbb4a52bec37a57962453b45347ffffde78beef2cffc3db2e - md5: 7d7a99174374aee86591f23078a2c315 - depends: - - python - - libgcc >=14 - constrains: - - __glibc >=2.17 - license: MIT - license_family: MIT - size: 9107871 - timestamp: 1784237315859 - conda: https://conda.anaconda.org/conda-forge/win-64/ruff-0.15.22-h6b72154_0.conda noarch: python sha256: 47c20477fb35f1e9748852dbe21d1c53ff5a9639ac0c99f52e651ffa30fced44 @@ -861,31 +920,6 @@ packages: license_family: MIT size: 9849056 timestamp: 1784237363067 -- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd70dff1_3.conda - build_number: 103 - sha256: 43624eab22f5f29df7d6ffe914cf442f28fd559b55b290906255492826e636e8 - md5: 48a1049e710857572fc2a832aa394d9f - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - libzlib >=1.3.2,<2.0a0 - constrains: - - xorg-libx11 >=1.8.13,<2.0a0 - license: TCL - size: 3550916 - timestamp: 1784229071544 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h5cf4473_3.conda - build_number: 103 - sha256: cd51fbda051a9f3679d10ef4a94cd1ff38c10533b82845dadce8ba87245ba4ce - md5: 89e78452e06563964e419059ee45584a - depends: - - libgcc >=14 - - libzlib >=1.3.2,<2.0a0 - constrains: - - xorg-libx11 >=1.8.13,<2.0a0 - license: TCL - size: 3683040 - timestamp: 1784229053797 - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h967ab96_3.conda sha256: 13fa29257d43f8e630a1e591ed77fae9bbbb236b011432f01e2034cf36e6bf03 md5: aaf79e2af50a151fb5b5a3e3f38b7a69 @@ -896,12 +930,6 @@ packages: license: TCL size: 3782314 timestamp: 1784229072899 -- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - sha256: b928c30ddcb0e3f544c6eade8352737e6e610e263276b90232db6a578ef899d8 - md5: fcb489df604d100968b737f2cb6076c6 - license: LicenseRef-Public-Domain - size: 118849 - timestamp: 1784250406640 - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda sha256: 3005729dce6f3d3f5ec91dfc49fc75a0095f9cd23bab49efb899657297ac91a5 md5: 71b24316859acd00bdb8b38f5e2ce328 @@ -945,25 +973,6 @@ packages: license_family: Proprietary size: 120684 timestamp: 1781320948530 -- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7 - md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829 - depends: - - __glibc >=2.17,<3.0.a0 - - libzlib >=1.3.1,<2.0a0 - license: BSD-3-Clause - license_family: BSD - size: 601375 - timestamp: 1764777111296 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda - sha256: 569990cf12e46f9df540275146da567d9c618c1e9c7a0bc9d9cfefadaed20b75 - md5: c3655f82dcea2aa179b291e7099c1fcc - depends: - - libzlib >=1.3.1,<2.0a0 - license: BSD-3-Clause - license_family: BSD - size: 614429 - timestamp: 1764777145593 - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda sha256: 368d8628424966fd8f9c8018326a9c779e06913dd39e646cf331226acc90e5b2 md5: 053b84beec00b71ea8ff7a4f84b55207