Audit of the spore.host Python bindings (python-sdk spore package + truffle/bindings/python). The spore SDK's two documented entry points both fail, and the failures ship green because there are no tests.
P0 — spore.truffle / spore.spawn top-level access is broken (module shadowing)
spore/__init__.py:11 does from . import truffle, spawn, which binds the submodules as real attributes on the package. The lazy-default-client hook __getattr__ (only called when normal lookup fails) therefore never fires for truffle/spawn. So the documented quickstart —
import spore
spore.truffle.find("nvidia h100") # AttributeError: module 'spore.truffle' has no attribute 'find'
— resolves spore.truffle to the module (no .find), not a TruffleClient. Verified: type(spore.truffle) == module, hasattr(spore.truffle,'find') == False. Every example in examples/ uses this broken path.
Fix: don't import the submodules into the package namespace (drop them from from . import … / __all__), or make the top-level API an explicit default-client accessor rather than relying on __getattr__ shadowed by real modules.
P0 — SpawnClient.launch() raises TypeError on every call
spawn.py:202-211 constructs Instance(..., private_ip=..., availability_zone=...) but the Instance dataclass (spawn.py:15-29) has no private_ip or availability_zone fields → TypeError: __init__() got an unexpected keyword argument 'private_ip'. Verified against the dataclass fields. launch() cannot succeed.
Fix: add the fields to Instance (and map them in _parse), or drop them from the launch() constructor call.
P1 — truffle.find() returns zeroed memory / GPU-memory / AZs (wrong JSON keys)
truffle.py:_parse reads memory_mi_b, gpu_memory_mi_b, available_a_zs, v_cp_us, gp_us — a mangled auto-snake-casing. The REST API (truffleaws.InstanceTypeResult) actually emits memory_mib, gpu_memory_mib, availability_zones, vcpus, gpus. vcpus/gpus survive via fallback, but:
memory_gib → always 0.0 (reads memory_mi_b, absent; else memory_gib, also absent — API sends memory_mib)
gpu_memory_gib → always 0.0 (no fallback)
available_azs → always empty (API sends availability_zones)
Fix: map to the real keys: memory_mib, gpu_memory_mib, availability_zones, vcpus, gpus (÷1024 for the MiB→GiB fields). (spawn's instances.go keys, by contrast, match spawn._parse correctly — that path is fine.)
P1 — No tests; CI masks all of the above
There is no tests/ dir. CI (test-python-build.yaml) runs pytest tests/ … || echo "No tests yet" (swallows absence) and a smoke check of only import spore; spore.__version__ — which passes because all three bugs are one level deeper than a bare import. A broken SDK ships green.
Fix: add tests that (a) call spore.truffle.find/spore.spawn.launch against a mocked Client.get/post (responses/requests-mock), asserting parsed fields; (b) make CI fail on missing tests. These three bugs are all caught by a single "does the documented quickstart run?" test.
Separate: truffle/bindings/python (native CGO) is non-functional / not committed
setup.py + Makefile build truffle/native.go and test_native.py imports from truffle import Truffle, …, but there is no truffle/ package, no native.go, no __init__.py in the repo — only docs (README/CGO_IMPLEMENTATION/NATIVE_CGO), a Makefile, setup.py, and the test. So the package can't build or import. The README presents it as a finished "10-50× faster" product. Also placeholder metadata (author="Your Name", you@example.com, MIT while the suite is Apache-2.0), package name truffle-aws. Recommend: either commit the missing native.go+wrapper, or clearly mark the dir WIP/remove it so it isn't mistaken for a shippable binding. (Filed here for visibility; may warrant its own issue in spore-host/truffle.)
lagotto — no gap
The hosted REST API exposes no lagotto/capacity-watch endpoints, and the SDK doesn't claim lagotto coverage. So "no lagotto bindings" is a scoping reality (nothing to call), not a defect.
Suggested priority
Fix the two P0s + P1 field-mapping together (they're all in the same two small files and all covered by one quickstart test), add the test + CI gate, then decide the CGO binding's fate separately.
Audit of the spore.host Python bindings (
python-sdksporepackage +truffle/bindings/python). ThesporeSDK's two documented entry points both fail, and the failures ship green because there are no tests.P0 —
spore.truffle/spore.spawntop-level access is broken (module shadowing)spore/__init__.py:11doesfrom . import truffle, spawn, which binds the submodules as real attributes on the package. The lazy-default-client hook__getattr__(only called when normal lookup fails) therefore never fires fortruffle/spawn. So the documented quickstart —— resolves
spore.truffleto the module (no.find), not aTruffleClient. Verified:type(spore.truffle) == module,hasattr(spore.truffle,'find') == False. Every example inexamples/uses this broken path.Fix: don't import the submodules into the package namespace (drop them from
from . import …/__all__), or make the top-level API an explicit default-client accessor rather than relying on__getattr__shadowed by real modules.P0 —
SpawnClient.launch()raises TypeError on every callspawn.py:202-211constructsInstance(..., private_ip=..., availability_zone=...)but theInstancedataclass (spawn.py:15-29) has noprivate_iporavailability_zonefields →TypeError: __init__() got an unexpected keyword argument 'private_ip'. Verified against the dataclass fields.launch()cannot succeed.Fix: add the fields to
Instance(and map them in_parse), or drop them from thelaunch()constructor call.P1 —
truffle.find()returns zeroed memory / GPU-memory / AZs (wrong JSON keys)truffle.py:_parsereadsmemory_mi_b,gpu_memory_mi_b,available_a_zs,v_cp_us,gp_us— a mangled auto-snake-casing. The REST API (truffleaws.InstanceTypeResult) actually emitsmemory_mib,gpu_memory_mib,availability_zones,vcpus,gpus.vcpus/gpussurvive via fallback, but:memory_gib→ always 0.0 (readsmemory_mi_b, absent; elsememory_gib, also absent — API sendsmemory_mib)gpu_memory_gib→ always 0.0 (no fallback)available_azs→ always empty (API sendsavailability_zones)Fix: map to the real keys:
memory_mib,gpu_memory_mib,availability_zones,vcpus,gpus(÷1024 for the MiB→GiB fields). (spawn'sinstances.gokeys, by contrast, matchspawn._parsecorrectly — that path is fine.)P1 — No tests; CI masks all of the above
There is no
tests/dir. CI (test-python-build.yaml) runspytest tests/ … || echo "No tests yet"(swallows absence) and a smoke check of onlyimport spore; spore.__version__— which passes because all three bugs are one level deeper than a bare import. A broken SDK ships green.Fix: add tests that (a) call
spore.truffle.find/spore.spawn.launchagainst a mockedClient.get/post(responses/requests-mock), asserting parsed fields; (b) make CI fail on missing tests. These three bugs are all caught by a single "does the documented quickstart run?" test.Separate:
truffle/bindings/python(native CGO) is non-functional / not committedsetup.py+Makefilebuildtruffle/native.goandtest_native.pyimportsfrom truffle import Truffle, …, but there is notruffle/package, nonative.go, no__init__.pyin the repo — only docs (README/CGO_IMPLEMENTATION/NATIVE_CGO), a Makefile, setup.py, and the test. So the package can't build or import. The README presents it as a finished "10-50× faster" product. Also placeholder metadata (author="Your Name",you@example.com,MITwhile the suite is Apache-2.0), package nametruffle-aws. Recommend: either commit the missingnative.go+wrapper, or clearly mark the dir WIP/remove it so it isn't mistaken for a shippable binding. (Filed here for visibility; may warrant its own issue inspore-host/truffle.)lagotto — no gap
The hosted REST API exposes no lagotto/capacity-watch endpoints, and the SDK doesn't claim lagotto coverage. So "no lagotto bindings" is a scoping reality (nothing to call), not a defect.
Suggested priority
Fix the two P0s + P1 field-mapping together (they're all in the same two small files and all covered by one quickstart test), add the test + CI gate, then decide the CGO binding's fate separately.