Skip to content

feat(worker): add cpu_shares resource control to protect earners under host contention - #317

Merged
GeiserX merged 3 commits into
mainfrom
feat/cpu-shares-earner-protection
Aug 10, 2026
Merged

feat(worker): add cpu_shares resource control to protect earners under host contention#317
GeiserX merged 3 commits into
mainfrom
feat/cpu-shares-earner-protection

Conversation

@GeiserX

@GeiserX GeiserX commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Why

The storj node on watchtower was repeatedly reported offline by satellites (US1 offline emails) while the container was up and healthy. Root cause: satellites dial the node back in, and under heavy host contention (copyparty at 330%+ CPU, load 24-28 during a disk-zeroing run) those inbound connections timed out. To the network, a slow node is indistinguishable from a dead one — and sustained offline status leads to suspension and forfeited held balance.

The resources schema only supported memory controls (mem_limit, mem_reservation, oom_score_adj), so there was no way to keep an earner responsive when the host is saturated.

What

  • ResourceSpec.cpu_shares in app/worker_api.py with validation (2..262144 — Docker treats 0 as default, rejects 1, kernel caps at 262144), rejected at the API instead of failing later at container create
  • Passthrough in app/orchestrator.py deploy_raw alongside the existing memory kwargs
  • Schema documentation in services/_schema.yml
  • cpu_shares: 2048 for storj in services/storage/storj.yml — double the 1024 default; relative weight, so it only takes effect under contention and costs nothing on an idle host

Testing

  • uv run pytest tests/4539 passed, 6 skipped, 0 failed
  • New tests: valid range accepted (2/1024/2048/262144), out-of-range rejected (0, 1, negatives, 262145), forwarding from both pydantic spec and plain catalog dict, omitted-when-absent
  • Real-catalog guard test updated to assert storj carries cpu_shares: 2048
  • ruff check + ruff format --check clean

Summary by CodeRabbit

  • New Features

    • Added support for configuring container CPU scheduling priority with cpu_shares.
    • Added CPU priority settings to the Storj service.
    • Redeployments now preserve recorded resource values while adopting newly configured resource settings.
  • Bug Fixes

    • Resource settings now correctly forward CPU scheduling values during deployment.
    • Invalid CPU share values outside the supported range of 2–262144 are rejected with a clear validation error.
  • Documentation

    • Documented CPU share limits, contention behavior, and recommended settings for latency-sensitive services.

…r host contention

Storj satellites dial the node back in and mark it offline when the
connection times out, so a node starved of CPU by co-located workloads
is indistinguishable from a dead one -- and sustained offline status
leads to suspension. The resources schema only covered memory, leaving
no way to keep an earner responsive on a contended host.

Add cpu_shares end-to-end: ResourceSpec field with 2..262144 validation
(Docker rejects 0/1 and the kernel caps the weight), deploy_raw
passthrough in the orchestrator, schema documentation, and a 2048
weight for storj. The weight is relative, so it costs nothing while
the host is idle.
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@GeiserX, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 54 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 91d48947-c13e-4fdd-83fc-eb4e54213141

📥 Commits

Reviewing files that changed from the base of the PR and between 1a90ff4 and eeb7693.

📒 Files selected for processing (1)
  • tests/test_worker_resources.py
📝 Walkthrough

Walkthrough

The PR adds optional Docker cpu_shares support. It validates values from 2 through 262144, forwards configured values during deployment, documents the setting, configures Storj with 4096 shares, and reconciles recorded and catalog resource keys per key.

Changes

Docker resource limits

Layer / File(s) Summary
Resource contract and validation
app/worker_api.py, services/_schema.yml, tests/test_worker_resources.py
ResourceSpec supports optional cpu_shares. Validation rejects values outside 2 through 262144 with HTTP 400 responses. Service schemas and catalog checks document and validate Docker resource keys.
Recorded resource reconciliation
app/main.py, tests/test_deployed_spec.py
Redeployment starts with catalog resources and overlays recorded values. Recorded values remain authoritative per key, including when catalog resources are removed.
Deployment resource forwarding
app/orchestrator.py, tests/test_worker_resources.py
deploy_raw forwards explicit cpu_shares values to Docker and logs the applied resource configuration or Docker defaults.
Storj catalog configuration
services/storage/storj.yml, tests/test_main_deploy_routes.py
The Storj service sets cpu_shares to 4096. The deployment test verifies the complete resource specification.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • GeiserX/CashPilot#95: Adds the durable Docker resource-limit implementation extended by this PR.
  • GeiserX/CashPilot#143: Modifies the same Docker resource and deployment configuration areas for a separate feature.
  • GeiserX/CashPilot#146: Modifies deployment-spec reconciliation in app/main.py and related tests.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding cpu_shares resource control for workers under host CPU contention.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cpu-shares-earner-protection

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.58%. Comparing base (03a8c0f) to head (eeb7693).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #317   +/-   ##
=======================================
  Coverage   95.57%   95.58%           
=======================================
  Files          51       51           
  Lines        6685     6697   +12     
=======================================
+ Hits         6389     6401   +12     
  Misses        296      296           
Files with missing lines Coverage Δ
app/main.py 97.70% <100.00%> (+0.01%) ⬆️
app/orchestrator.py 81.71% <100.00%> (ø)
app/worker_api.py 89.64% <100.00%> (+0.05%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…vices, correct cpu_shares to 4096

Review findings on the cpu_shares PR, in severity order:

- _merge_recorded_spec treated resources as an opaque whole where the
  record beats the catalog, so a deployment recorded before a resource
  key existed could never receive it on redeploy — the exact rollout
  this PR exists for. Resources now merge per key like env: the catalog
  supplies keys the record never set, a key the deployment actually ran
  with still wins (reported as a divergence), and only a genuine keep is
  reported as kept.
- storj cpu_shares 2048 -> 4096: on cgroup v2 the unset default is
  cpu.weight 100, and runc older than 1.2 maps shares linearly, putting
  anything under ~2600 BELOW that default — 2048 would have given the
  protected service less CPU than its neighbours on older hosts. 4096
  clears the default on both mappings (157 old, 303 new).
- The storj comment claimed satellites time out dialling a CPU-starved
  node; live evidence disproves that for the motivating incident (the
  node advertises a stale ADDRESS after a WAN failover — dial-backs fail
  at a constant rate on an idle host). Reworded as defensive rationale
  that names what the weight does NOT fix.
- Catalog-wide guard: every docker.resources block must use keys the
  worker honors (derived from ResourceSpec, tied back to _schema.yml)
  and pass the worker's own validation — a typo like cpushares was
  silently ignored end to end. Loads through app.catalog so .yaml
  services stay covered.
- deploy_raw now logs the resource kwargs it applied; endpoint-level 400
  negative control for cpu_shares; stale key enumerations updated;
  misleading dict-path test comment corrected (no such production path).
@GeiserX

GeiserX commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

Review record (7-lens review + independent re-review of the fix)

Verdict on the original head (41b9595): two findings that mattered, both fixed in 1a90ff4.

  1. HIGH — the feature never reached an already-deployed service. _merge_recorded_spec merged resources as an opaque whole with the recorded spec winning, so any deployment recorded before a resource key existed could never receive it on redeploy — proven by executing the real function: the recorded {mem_limit, oom_score_adj} beat the catalog and cpu_shares was dropped, silently (the divergence note is returned in a JSON field no UI renders). The only escape was remove-and-redeploy, which for storj is the identity-risk operation the recorded spec exists to prevent. The PR's guard test passed because it exercised the fresh-deploy path only. Fix: resources now merge per key, exactly like env ten lines below — the catalog supplies keys the record never set, a key the deployment actually ran with still wins, and only a genuine keep is reported. Six regression tests cover the merge path (it had zero before).

  2. MEDIUM→value change — 2048 was counterproductive on older hosts. On cgroup v2 an unset container runs at cpu.weight 100. runc ≥ 1.2 maps shares 1024→100, 2048→174, 4096→303; runc < 1.2 maps linearly, where 2048→79 — below the unset default, i.e. the "protected" service would get less CPU than its neighbours. Anything ≥ ~2600 clears 100 on both mappings, so storj now ships 4096 (157 old / 303 new). The schema comment documents both mappings.

  3. Root-cause correction. The motivating incident was re-verified live: the node's dial-back failures continue at a constant rate on an uncontended host, and the mechanism is a stale advertised ADDRESS after a WAN failover — a reachability problem no CPU weight can touch. The storj comment is reworded as a defensive rationale that names what the weight does not fix (I/O-wait, wrong/stale ADDRESS). The knob itself remains worth shipping: it is free when idle and real under container CPU contention.

Also in 1a90ff4: a catalog-wide guard (every docker.resources block must use keys ResourceSpec honors — a cpushares typo previously deployed green with the limit silently unset — tied back to _schema.yml, loading through app.catalog so .yaml services stay covered); deploy_raw logs the resource kwargs it applied (deploy responses never echo them, and version-skewed workers drop unknown keys silently); an endpoint-level 400 negative control for cpu_shares; and comment accuracy fixes (kernel MIN_SHARES..MAX_SHARES range, stale key enumerations, a test comment describing a production path that does not exist).

Follow-ups filed separately rather than widening this PR: compose export drops the whole resources block (pre-existing); Desktop needs CPUShares in its Go ResourceLimits + runtime before its catalog copy is synced; kept_from_previous_deployment deserves a UI rendering; and a storj reachability signal (lastPinged/quicStatus from the node's own API) — the check that would have diagnosed the incident in seconds.

Full suite: 4549 passed, 6 skipped, coverage 95.62%. Independent re-review of the fix commit: APPROVE.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_worker_resources.py`:
- Around line 379-390: Update test_every_honored_key_is_documented_in_the_schema
to parse _schema.yml as YAML and locate the properties mapping for
docker.resources, then assert every key in DOCUMENTED_RESOURCE_KEYS exists
there. Remove the raw substring check so matches in comments, descriptions, or
unrelated fields cannot satisfy the test.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e9c7bf52-6401-4954-b9b1-48aa7c55ae26

📥 Commits

Reviewing files that changed from the base of the PR and between 41b9595 and 1a90ff4.

📒 Files selected for processing (8)
  • app/main.py
  • app/orchestrator.py
  • app/worker_api.py
  • services/_schema.yml
  • services/storage/storj.yml
  • tests/test_deployed_spec.py
  • tests/test_main_deploy_routes.py
  • tests/test_worker_resources.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • services/_schema.yml
  • app/orchestrator.py
  • app/worker_api.py

Comment thread tests/test_worker_resources.py
A bare substring check passed on any mention of the key anywhere in
_schema.yml. The file is documentation written entirely in comments (no
parseable YAML structure), so the honest tightening is a regex on the
commented mapping-key form, which prose cannot satisfy.
GeiserX added a commit that referenced this pull request Aug 10, 2026
…d version

requirements.txt is a pinned export of uv.lock (the lockfile is what CI
and the Docker image install), so a bump that edits only requirements.txt
fails test_it_matches_the_lockfile by design. The lock now carries the
same upgrades, regenerated with the documented
  uv export --no-dev --no-hashes --format requirements-txt

One deliberate deviation: pydantic-core stays at 2.46.4 instead of the
proposed 2.48.0. Stable pydantic pins its core exactly, so forcing
2.48.0 drags pydantic itself to the 2.14.0b1 BETA prerelease — a
minor-and-patch group must not ship a beta. pydantic-core follows
whenever pydantic's next stable lands.

Verified locally against the new resolution: full suite 4588 passed
(6 skipped), coverage >= 90, ruff clean; docker-py 7.2.0 still exposes
the cpu_shares run kwarg (PR #317 depends on it).
GeiserX added a commit that referenced this pull request Aug 10, 2026
* deps: bump the minor-and-patch group with 20 updates

Bumps the minor-and-patch group with 20 updates:

| Package | From | To |
| --- | --- | --- |
| [fastapi](https://github.com/fastapi/fastapi) | `0.136.1` | `0.141.1` |
| [uvicorn](https://github.com/Kludex/uvicorn) | `0.47.0` | `0.52.1` |
| [httptools](https://github.com/MagicStack/httptools) | `0.7.1` | `0.8.0` |
| [apscheduler](https://github.com/agronholm/apscheduler) | `3.11.2` | `3.11.3` |
| [python-multipart](https://github.com/Kludex/python-multipart) | `0.0.31` | `0.0.32` |
| [prometheus-client](https://github.com/prometheus/client_python) | `0.25.0` | `0.26.0` |
| [docker](https://github.com/docker/docker-py) | `7.1.0` | `7.2.0` |
| [tzdata](https://github.com/python/tzdata) | `2026.2` | `2026.3` |
| [annotated-doc](https://github.com/fastapi/annotated-doc) | `0.0.4` | `0.0.5` |
| [annotated-types](https://github.com/annotated-types/annotated-types) | `0.7.0` | `0.8.0` |
| [anyio](https://github.com/agronholm/anyio) | `4.13.0` | `4.14.2` |
| [certifi](https://github.com/certifi/python-certifi) | `2026.5.20` | `2026.7.22` |
| [cffi](https://github.com/python-cffi/cffi) | `2.0.0` | `2.1.1` |
| [charset-normalizer](https://github.com/jawah/charset_normalizer) | `3.4.7` | `3.4.9` |
| [click](https://github.com/pallets/click) | `8.4.1` | `8.4.2` |
| [idna](https://github.com/kjd/idna) | `3.16` | `3.18` |
| [pydantic-core](https://github.com/pydantic/pydantic) | `2.46.4` | `2.48.0` |
| [starlette](https://github.com/Kludex/starlette) | `1.3.1` | `1.4.1` |
| [typing-extensions](https://github.com/python/typing_extensions) | `4.15.0` | `4.16.0` |
| [tzlocal](https://github.com/regebro/tzlocal) | `5.3.1` | `5.4.4` |


Updates `fastapi` from 0.136.1 to 0.141.1
- [Release notes](https://github.com/fastapi/fastapi/releases)
- [Commits](fastapi/fastapi@0.136.1...0.141.1)

Updates `uvicorn` from 0.47.0 to 0.52.1
- [Release notes](https://github.com/Kludex/uvicorn/releases)
- [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md)
- [Commits](Kludex/uvicorn@0.47.0...0.52.1)

Updates `httptools` from 0.7.1 to 0.8.0
- [Release notes](https://github.com/MagicStack/httptools/releases)
- [Commits](MagicStack/httptools@v0.7.1...v0.8.0)

Updates `apscheduler` from 3.11.2 to 3.11.3
- [Release notes](https://github.com/agronholm/apscheduler/releases)
- [Commits](agronholm/apscheduler@3.11.2...3.11.3)

Updates `python-multipart` from 0.0.31 to 0.0.32
- [Release notes](https://github.com/Kludex/python-multipart/releases)
- [Changelog](https://github.com/Kludex/python-multipart/blob/main/CHANGELOG.md)
- [Commits](Kludex/python-multipart@0.0.31...0.0.32)

Updates `prometheus-client` from 0.25.0 to 0.26.0
- [Release notes](https://github.com/prometheus/client_python/releases)
- [Commits](prometheus/client_python@v0.25.0...v0.26.0)

Updates `docker` from 7.1.0 to 7.2.0
- [Release notes](https://github.com/docker/docker-py/releases)
- [Commits](docker/docker-py@7.1.0...7.2.0)

Updates `tzdata` from 2026.2 to 2026.3
- [Release notes](https://github.com/python/tzdata/releases)
- [Changelog](https://github.com/python/tzdata/blob/master/NEWS.md)
- [Commits](python/tzdata@2026.2...2026.3)

Updates `annotated-doc` from 0.0.4 to 0.0.5
- [Release notes](https://github.com/fastapi/annotated-doc/releases)
- [Changelog](https://github.com/fastapi/annotated-doc/blob/main/release-notes.md)
- [Commits](fastapi/annotated-doc@0.0.4...0.0.5)

Updates `annotated-types` from 0.7.0 to 0.8.0
- [Release notes](https://github.com/annotated-types/annotated-types/releases)
- [Commits](annotated-types/annotated-types@v0.7.0...v0.8.0)

Updates `anyio` from 4.13.0 to 4.14.2
- [Release notes](https://github.com/agronholm/anyio/releases)
- [Commits](agronholm/anyio@4.13.0...4.14.2)

Updates `certifi` from 2026.5.20 to 2026.7.22
- [Commits](certifi/python-certifi@2026.05.20...2026.07.22)

Updates `cffi` from 2.0.0 to 2.1.1
- [Release notes](https://github.com/python-cffi/cffi/releases)
- [Commits](python-cffi/cffi@v2.0.0...v2.1.1)

Updates `charset-normalizer` from 3.4.7 to 3.4.9
- [Release notes](https://github.com/jawah/charset_normalizer/releases)
- [Changelog](https://github.com/jawah/charset_normalizer/blob/master/CHANGELOG.md)
- [Commits](jawah/charset_normalizer@3.4.7...3.4.9)

Updates `click` from 8.4.1 to 8.4.2
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.md)
- [Commits](pallets/click@8.4.1...8.4.2)

Updates `idna` from 3.16 to 3.18
- [Release notes](https://github.com/kjd/idna/releases)
- [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.md)
- [Commits](kjd/idna@v3.16...v3.18)

Updates `pydantic-core` from 2.46.4 to 2.48.0
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](pydantic/pydantic@core-v2.46.4...core-v2.48.0)

Updates `starlette` from 1.3.1 to 1.4.1
- [Release notes](https://github.com/Kludex/starlette/releases)
- [Changelog](https://github.com/Kludex/starlette/blob/main/docs/release-notes.md)
- [Commits](Kludex/starlette@1.3.1...1.4.1)

Updates `typing-extensions` from 4.15.0 to 4.16.0
- [Release notes](https://github.com/python/typing_extensions/releases)
- [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md)
- [Commits](python/typing_extensions@4.15.0...4.16.0)

Updates `tzlocal` from 5.3.1 to 5.4.4
- [Changelog](https://github.com/regebro/tzlocal/blob/master/CHANGES.txt)
- [Commits](regebro/tzlocal@5.3.1...5.4.4)

---
updated-dependencies:
- dependency-name: fastapi
  dependency-version: 0.141.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: uvicorn
  dependency-version: 0.52.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: httptools
  dependency-version: 0.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: apscheduler
  dependency-version: 3.11.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: python-multipart
  dependency-version: 0.0.32
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: prometheus-client
  dependency-version: 0.26.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: docker
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: tzdata
  dependency-version: '2026.3'
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: annotated-doc
  dependency-version: 0.0.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: annotated-types
  dependency-version: 0.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: anyio
  dependency-version: 4.14.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: certifi
  dependency-version: 2026.7.22
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: cffi
  dependency-version: 2.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: charset-normalizer
  dependency-version: 3.4.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: click
  dependency-version: 8.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: idna
  dependency-version: '3.18'
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: pydantic-core
  dependency-version: 2.48.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: starlette
  dependency-version: 1.4.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: typing-extensions
  dependency-version: 4.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: tzlocal
  dependency-version: 5.4.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* deps: update uv.lock to match, hold pydantic-core at the stable-pinned version

requirements.txt is a pinned export of uv.lock (the lockfile is what CI
and the Docker image install), so a bump that edits only requirements.txt
fails test_it_matches_the_lockfile by design. The lock now carries the
same upgrades, regenerated with the documented
  uv export --no-dev --no-hashes --format requirements-txt

One deliberate deviation: pydantic-core stays at 2.46.4 instead of the
proposed 2.48.0. Stable pydantic pins its core exactly, so forcing
2.48.0 drags pydantic itself to the 2.14.0b1 BETA prerelease — a
minor-and-patch group must not ship a beta. pydantic-core follows
whenever pydantic's next stable lands.

Verified locally against the new resolution: full suite 4588 passed
(6 skipped), coverage >= 90, ruff clean; docker-py 7.2.0 still exposes
the cpu_shares run kwarg (PR #317 depends on it).

* deps: keep the GENERATED header on the requirements export

The raw uv-export output replaced the repo's do-not-edit-by-hand header
with uv's own; test_it_says_it_is_generated exists precisely to stop the
file drifting back into a hand-edited second opinion.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: GeiserX <9169332+GeiserX@users.noreply.github.com>
@GeiserX
GeiserX merged commit c065044 into main Aug 10, 2026
9 checks passed
@GeiserX
GeiserX deleted the feat/cpu-shares-earner-protection branch August 10, 2026 15:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant