Add domain CRUD, energy density constraint, LLM status, reset results, score display fixes
Domain management: - Add domain list/detail/form templates and full CRUD routes (domains.py) - Add metric bound add/edit/delete via HTMX partials (_metrics_table.html) Energy density constraint (Rule 6 in ConstraintResolver): - Hard-block combos where power source provides <25% of platform's required Wh/kg - Warn (conditional) when under-density but within 4x - Solar Sail exempt (no stored energy); Airplane requires 400 Wh/kg, Spaceship 2000 Wh/kg - Add energy_density_wh_kg provides to all 8 stored-energy power sources in seed data - 3 new constraint resolver tests LLM-complete status: - Pipeline Pass 4 now sets combo status to llm_reviewed after successful LLM review - update_combination_status guards against downgrading: scored won't overwrite llm_reviewed or reviewed; llm_reviewed won't overwrite reviewed - Add badge-llm_reviewed CSS style (light blue) Reset results: - Repository.reset_domain_results() deletes combination_results, combination_scores, and pipeline_runs for a domain; pipeline re-evaluates on next run - POST /results/<domain>/reset route with flash confirmation - "Reset results" danger button with JS confirm dialog in results list Fix composite score 0 displaying as --- (Jinja2 falsy 0.0 bug): - Change `if r.composite_score` to `if r.composite_score is not none` Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -119,3 +119,67 @@ def test_hydrogen_bicycle_valid(bicycle, hydrogen_engine):
|
||||
# This is actually a borderline case — let's just verify no hard physics blocks
|
||||
range_blocks = [v for v in result.violations if "mutually exclusive" in v or "atmosphere" in v]
|
||||
assert len(range_blocks) == 0
|
||||
|
||||
|
||||
def test_energy_density_deficit_blocks():
|
||||
"""A platform needing 2000 Wh/kg paired with a 200 Wh/kg battery → blocked."""
|
||||
platform = Entity(
|
||||
name="Spaceship", dimension="platform",
|
||||
dependencies=[
|
||||
Dependency("physical", "energy_density_wh_kg", "2000", "Wh/kg", "range_min"),
|
||||
],
|
||||
)
|
||||
power = Entity(
|
||||
name="Battery", dimension="power_source",
|
||||
dependencies=[
|
||||
Dependency("physical", "energy_density_wh_kg", "200", "Wh/kg", "provides"),
|
||||
],
|
||||
)
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[platform, power])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status == "blocked"
|
||||
assert any("energy density deficit" in v for v in result.violations)
|
||||
|
||||
|
||||
def test_energy_density_under_density_warning():
|
||||
"""A platform needing 400 Wh/kg paired with a 200 Wh/kg battery → conditional."""
|
||||
platform = Entity(
|
||||
name="Airplane", dimension="platform",
|
||||
dependencies=[
|
||||
Dependency("physical", "energy_density_wh_kg", "400", "Wh/kg", "range_min"),
|
||||
],
|
||||
)
|
||||
power = Entity(
|
||||
name="Battery", dimension="power_source",
|
||||
dependencies=[
|
||||
Dependency("physical", "energy_density_wh_kg", "200", "Wh/kg", "provides"),
|
||||
],
|
||||
)
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[platform, power])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status != "blocked"
|
||||
assert any("under-density" in w for w in result.warnings)
|
||||
|
||||
|
||||
def test_energy_density_no_constraint_if_no_provider():
|
||||
"""A platform with energy density requirement but no declared provider → no violation."""
|
||||
platform = Entity(
|
||||
name="Spaceship", dimension="platform",
|
||||
dependencies=[
|
||||
Dependency("physical", "energy_density_wh_kg", "2000", "Wh/kg", "range_min"),
|
||||
],
|
||||
)
|
||||
# Solar Sail-style: no energy_density_wh_kg declared
|
||||
power = Entity(
|
||||
name="Solar Sail", dimension="power_source",
|
||||
dependencies=[
|
||||
Dependency("force", "force_output_watts", "1", "watts", "provides"),
|
||||
],
|
||||
)
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[platform, power])
|
||||
result = resolver.resolve(combo)
|
||||
density_violations = [v for v in result.violations if "energy density" in v]
|
||||
assert len(density_violations) == 0
|
||||
|
||||
Reference in New Issue
Block a user