What happened
#609 (closing #605) declared birds and infra as conflicting extras, because without that declaration uv lock could not resolve at all and the lock had been rotting for two weeks — the SBOM and pip-audit workflows were describing a dependency set the project no longer had.
That unblocked the lock, but it is worth being plain that it cost something real, and this issue is the cost.
$ curl -s https://pypi.org/pypi/birdnetlib/json | jq '.info.requires_dist[] | select(contains("watchdog"))'
"watchdog==2.1.9"
birdnetlib pins watchdog to an exact version. The infra extra needs watchdog>=6,<7 for the filesystem watcher. The two cannot be satisfied together.
Unlike the pillow conflicts declared above it in [tool.uv] conflicts, this is not a per-machine split. Those are honest: the profiles say "pick ONE per machine" and the two sides live on different hardware. This one is not — both would run on the same Mac. Five capabilities are now mutually exclusive with one other capability for no reason a wearer would recognise:
| extra |
capability |
impact |
birds |
bird_song |
2 |
infra |
lan_discovery |
3 |
infra |
doc_read via dashboard |
2 |
infra |
fs_watch |
2 |
infra |
memory_explorer |
2 |
infra |
spatial_viz |
2 |
Somebody who wants their Brain to name the birds outside and watch a folder for new files currently cannot have both, and nothing in the product explains why.
Ask
Any of these is a good answer; they are listed roughly easiest-first, not best-first.
-
Upstream it. watchdog==2.1.9 is almost certainly incidental — birdnetlib uses watchdog for directory-watching analysis, and the API it needs is stable across 2.x→6.x. A PR to joeweiss/birdnetlib relaxing it to a range would fix this for everyone, not just us, and would let the conflict declaration be deleted outright. This is the outcome I would most like.
-
Find out whether birdnetlib actually needs watchdog at all for our use. We call it to identify a bird from an audio buffer. If the directory-watcher is a separate entry point we never touch, the pin may be avoidable with a narrower install or by depending on the analyzer package directly.
-
Replace the dependency. birdnetlib is a wrapper around BirdNET-Analyzer. If the model can be driven through onnxruntime/tflite directly — which the project already ships for other lenses — bird_song stops needing the wrapper and its pin.
-
Argue it does not matter and close this. A defensible position: birds ships in no profile, it is opt-in, and someone who wants bird ID probably is not also running a Datasette dashboard. If you think that is right, say so here and I will fold the reasoning into decisions/ so nobody re-litigates it in six months.
Verifying a fix
cd host-python
# remove the [{ extra = "birds" }, { extra = "infra" }] pair from [tool.uv] conflicts
uv lock # must resolve
uv lock --check
python -m pytest src/dreamlayer/tests/test_lockfile.py -q
test_lockfile.py was added in #609 and asserts, among other things, that no shipped profile contains a conflicting pair — so it will keep you honest if you shuffle extras between profiles to dodge the problem rather than solve it.
Related
Two more conflicts were declared in the same change and are the same shape, if this one interests you:
math-ocr / vision — pix2tex pins timm==0.5.4, open-clip-torch wants timm>=1.0.17. Costs math_ocr (impact 2) alongside the whole vision tier.
doc-ocr / dream — the pillow<11 vs >=11 split. This one is a genuine per-machine split (glasses-bridge host vs Mac Brain) and was simply never named; it is the least objectionable of the three.
Where
host-python
What happened
#609 (closing #605) declared
birdsandinfraas conflicting extras, because without that declarationuv lockcould not resolve at all and the lock had been rotting for two weeks — the SBOM and pip-audit workflows were describing a dependency set the project no longer had.That unblocked the lock, but it is worth being plain that it cost something real, and this issue is the cost.
birdnetlib pins
watchdogto an exact version. Theinfraextra needswatchdog>=6,<7for the filesystem watcher. The two cannot be satisfied together.Unlike the pillow conflicts declared above it in
[tool.uv] conflicts, this is not a per-machine split. Those are honest: the profiles say "pick ONE per machine" and the two sides live on different hardware. This one is not — both would run on the same Mac. Five capabilities are now mutually exclusive with one other capability for no reason a wearer would recognise:birdsbird_songinfralan_discoveryinfradoc_readviadashboardinfrafs_watchinframemory_explorerinfraspatial_vizSomebody who wants their Brain to name the birds outside and watch a folder for new files currently cannot have both, and nothing in the product explains why.
Ask
Any of these is a good answer; they are listed roughly easiest-first, not best-first.
Upstream it.
watchdog==2.1.9is almost certainly incidental — birdnetlib uses watchdog for directory-watching analysis, and the API it needs is stable across 2.x→6.x. A PR to joeweiss/birdnetlib relaxing it to a range would fix this for everyone, not just us, and would let the conflict declaration be deleted outright. This is the outcome I would most like.Find out whether birdnetlib actually needs watchdog at all for our use. We call it to identify a bird from an audio buffer. If the directory-watcher is a separate entry point we never touch, the pin may be avoidable with a narrower install or by depending on the analyzer package directly.
Replace the dependency. birdnetlib is a wrapper around BirdNET-Analyzer. If the model can be driven through
onnxruntime/tflitedirectly — which the project already ships for other lenses —bird_songstops needing the wrapper and its pin.Argue it does not matter and close this. A defensible position:
birdsships in no profile, it is opt-in, and someone who wants bird ID probably is not also running a Datasette dashboard. If you think that is right, say so here and I will fold the reasoning intodecisions/so nobody re-litigates it in six months.Verifying a fix
test_lockfile.pywas added in #609 and asserts, among other things, that no shipped profile contains a conflicting pair — so it will keep you honest if you shuffle extras between profiles to dodge the problem rather than solve it.Related
Two more conflicts were declared in the same change and are the same shape, if this one interests you:
math-ocr/vision— pix2tex pinstimm==0.5.4, open-clip-torch wantstimm>=1.0.17. Costsmath_ocr(impact 2) alongside the whole vision tier.doc-ocr/dream— thepillow<11vs>=11split. This one is a genuine per-machine split (glasses-bridge host vs Mac Brain) and was simply never named; it is the least objectionable of the three.Where
host-python