Display metric units in web UI, make seed idempotent, simplify code

- Load m.unit in get_domain() so MetricBound carries units from DB
- Add Unit column to domains list template
- Make load_transport_seed() idempotent with IntegrityError handling
  and metric unit backfill for existing DBs
- Remove unused imports (json, sqlite3, Entity)
- Simplify combinator loop to list comprehension
- Merge duplicate conditional/valid branches in pipeline
- Consolidate duplicated SQL in get_all_results()
- Expand CLAUDE.md with fuller architecture docs and conventions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-18 16:18:50 -06:00
parent d2028a642b
commit f1b3c75190
9 changed files with 63 additions and 53 deletions

View File

@@ -1,12 +1,20 @@
# PhysCom — Physical Combinatorics
# CLAUDE.md
Innovation discovery engine: generate entity combinations, filter by physical constraints, score against domain-specific metrics, rank results.
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What this project is
PhysCom (Physical Combinatorics) — innovation discovery engine that generates entity combinations across dimensions (e.g. platform × power_source), filters by physical constraints, scores against domain-specific metrics, and ranks results. Includes a CLI, a Flask/HTMX web UI, and a 5-pass pipeline (constraints → estimation → scoring → LLM review → human review).
## Commands
- **Tests**: `python -m pytest tests/ -q` (48 tests, ~3s). Run after every change.
- **Install**: `pip install -e ".[dev,web]"` (editable install with test and web deps)
- **Tests (all)**: `python -m pytest tests/ -q` (48 tests, ~5s). Run after every change.
- **Single test file**: `python -m pytest tests/test_scorer.py -q`
- **Single test**: `python -m pytest tests/test_scorer.py::test_score_combination -q`
- **Web dev server**: `python -m physcom_web`
- **CLI**: `python -m physcom`
- **CLI**: `python -m physcom` (or `physcom` if installed)
- **Docker**: `docker compose up web` / `docker compose run cli physcom seed`
- **Seed data**: loaded automatically on first DB init (SQLite, `physcom.db` or `$PHYSCOM_DB`)
## Architecture
@@ -53,13 +61,19 @@ tests/ # pytest, uses seeded_repo fixture from conftest.py
1. **Pass 1 — Constraints**: `ConstraintResolver.resolve()` → blocked/conditional/valid. Blocked combos get a result row and `continue`.
2. **Pass 2 — Estimation**: LLM or `_stub_estimate()` → raw metric values. Saved immediately via `save_raw_estimates()` (normalized_score=NULL).
3. **Pass 3 — Scoring**: `Scorer.score_combination()` → log-normalized scores + weighted geometric mean composite. Saves via `save_scores()` + `save_result()`.
4. **Pass 4 — LLM Review**: Only for above-threshold combos with an LLM provider.
4. **Pass 4 — LLM Review**: Only for above-threshold combos with an LLM provider. No real provider yet (only `MockLLMProvider`).
5. **Pass 5 — Human Review**: Manual via web UI results page.
## Testing
- Tests use `seeded_repo` fixture (in-memory SQLite with transport seed data: 9 platforms, 9 power sources, 2 domains). There's also a bare `repo` fixture for tests that seed their own data.
- Individual entity fixtures (walking, bicycle, spaceship, solar_sail, etc.) are defined in `conftest.py`.
## Conventions
- Python 3.11+, `from __future__ import annotations` everywhere.
- Dataclasses for models, no ORM.
- Tests use `seeded_repo` fixture (in-memory SQLite with transport seed data).
- Don't use `cd` in Bash commands — run from the working directory so pre-approved permission patterns match.
- Don't add docstrings/comments/type annotations to code you didn't change.
- `INSERT OR IGNORE` won't update existing rows — if adding a new column/field to seed data, also add an UPDATE for backfill.
- Jinja2 `0.0` is falsy — use `is not none` not `if value` when displaying scores that can legitimately be zero.