Summary
uf/specs.py:114 wraps the entire ju spec-generation block in a bare except ImportError: that falls back to _generate_basic_spec. In the GitHub Actions runner environment, something in the ju import chain raises ImportError, so the fallback is what actually runs there.
Consequence: uf's ju integration — the package's entire reason to exist — has never been exercised in CI. CI is green because the fallback path is green.
How this was found
While fixing a real bug in #3 (func_to_form_spec was called without nest_under_field=None, so ju returned {'rjsf': {...}} and form_spec.get('schema', {}) yielded {} — every generated RJSF form was empty, served to the browser from uf/routes.py:123 and :189).
That bug reproduced locally (2 failing tests) but CI was green throughout — which is only possible if CI never took the ju path. The except ImportError was left deliberately untouched in #3, because narrowing it would have surfaced the hidden failure as a CI failure in a PR that was about something else.
What is not known
Which import fails on the runner. The following were ruled out during investigation and are not the cause: ipywidgets, graphviz (lazily imported), every name in ju/__init__ checked against the 0.1.31 wheel, dol 0.3.44, i2 0.1.63. An isolated-venv reproduction attempt failed for unrelated permission reasons.
Suggested approach
Narrowing the except clause is not the right first move — it converts a silent problem into a red CI with no diagnosis.
Better:
- Add a no-fallback smoke test (or a
strict=True flag on the spec store) that imports ju and generates one spec with no except guard, and let it fail loudly in CI. The traceback will name the failing import — which is the missing piece.
- With that known, fix the actual dependency problem (likely an undeclared or under-pinned transitive dep) and then narrow the
except to the specific import it was meant to guard, if it is still needed at all.
- Consider whether the fallback should exist at all in a package whose purpose is the
ju integration. If ju is not importable, silently serving degraded empty-ish forms is arguably worse than failing.
Reproduce
# locally the ju path IS taken — tests pass post-#3
python -m pytest -q # 29 passed
# in CI the fallback is taken; prove it by asserting the ju path
python -c "from ju.rjsf import func_to_form_spec; print('ju import OK')"
Add the equivalent assertion to CI to see it fail there.
Surfaced during the 2026-07-30 wave-0 rollout batch.
Summary
uf/specs.py:114wraps the entirejuspec-generation block in a bareexcept ImportError:that falls back to_generate_basic_spec. In the GitHub Actions runner environment, something in thejuimport chain raisesImportError, so the fallback is what actually runs there.Consequence:
uf'sjuintegration — the package's entire reason to exist — has never been exercised in CI. CI is green because the fallback path is green.How this was found
While fixing a real bug in #3 (
func_to_form_specwas called withoutnest_under_field=None, sojureturned{'rjsf': {...}}andform_spec.get('schema', {})yielded{}— every generated RJSF form was empty, served to the browser fromuf/routes.py:123and:189).That bug reproduced locally (2 failing tests) but CI was green throughout — which is only possible if CI never took the
jupath. Theexcept ImportErrorwas left deliberately untouched in #3, because narrowing it would have surfaced the hidden failure as a CI failure in a PR that was about something else.What is not known
Which import fails on the runner. The following were ruled out during investigation and are not the cause:
ipywidgets,graphviz(lazily imported), every name inju/__init__checked against the 0.1.31 wheel,dol0.3.44,i20.1.63. An isolated-venv reproduction attempt failed for unrelated permission reasons.Suggested approach
Narrowing the
exceptclause is not the right first move — it converts a silent problem into a red CI with no diagnosis.Better:
strict=Trueflag on the spec store) that importsjuand generates one spec with noexceptguard, and let it fail loudly in CI. The traceback will name the failing import — which is the missing piece.exceptto the specific import it was meant to guard, if it is still needed at all.juintegration. Ifjuis not importable, silently serving degraded empty-ish forms is arguably worse than failing.Reproduce
Add the equivalent assertion to CI to see it fail there.
Surfaced during the 2026-07-30 wave-0 rollout batch.