Constraint resolver: aggregate mass/footprint across a combo instead of
pairwise-only checks, treat medium/atmosphere as agreement not supply/demand,
reduce multi-provider checks by best/sum instead of AND-ing every provider,
fail closed on unrecognized mutex values, add a propulsion-viability
(thrust-to-weight) rule. Seed data updated to match (nuclear/solar-sail
footprint floors, water-medium exclusions, explicit ground/gravity providers).
Domain metric units were stored globally per metric name instead of
per-domain, silently corrupting cost_efficiency for every domain but the
first one seeded — fixed with a schema migration.
Stub estimator's cost_efficiency/safety/availability/reliability were a
backwards formula and flat constants; replaced with heuristics grounded in
each entity's thrust_profile/energy_form/infrastructure.
LLM estimate_physics() now receives each metric's unit and expected range
instead of a bare name, fixing wildly miscalibrated estimates traced back to
the prompt's own hardcoded example anchoring the model to the wrong order of
magnitude. Sharpened the safety-estimation and plausibility-review prompts.
Deduped provider parsing logic into llm/parsing.py.
Web pipeline form can now pick an LLM provider per run instead of only via
server env var.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add LLMProvider registry (llm/registry.py) that builds a provider from
env vars (LLM_PROVIDER, GEMINI_API_KEY, GEMINI_MODEL)
- Add GeminiLLMProvider using the google-genai SDK
- Wire build_llm_provider() into CLI and web pipeline route (replacing llm=None)
- Wrap pass 2 and pass 4 LLM calls in per-combo try/except so API errors
skip individual combos rather than aborting the whole run
- Add gemini optional dep to pyproject.toml; Dockerfile installs [web,gemini]
- Document env vars in .env.example and README
- Lower requires-python to >=3.10 to match installed system Python
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>