Files
Conflict_Checker/NOTES.md
T
woogiandCursor a6b0c8fdfa
Docker Release / build-and-push (push) Successful in 1m27s
Docker Release / release (push) Skipped
Add per-job run logs and separate vision/text model selection.
Capture pipeline stdout into job.log + API/UI so failed runs can be reviewed, and let users pick OpenRouter vision vs text models independently.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 14:56:48 -05:00

97 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Session Notes — Conflict Checker
Orientation for a new coding session. Setup and Docker details live in [README.md](README.md). This file tracks what the code actually does and what tends to waste time.
## What this is
Cross-discipline **design contradiction / senior-architect QAQC** for construction drawing PDFs (Arch, Struct, Mech, Elec, Plumb, FP, etc.). Flags disagreements *between disciplines* before a set goes to bid/permit.
**Not** IronBids scope-ownership conflict checker.
Source of truth: Scout IT Gitea — `gitea.scoutitsystems.com/woogi/Conflict_Checker`.
## Stack
| Layer | Detail |
|-------|--------|
| API | Python 3.12, FastAPI, Uvicorn ([backend/main.py](backend/main.py)) |
| UI | Single static file [frontend/index.html](frontend/index.html), served by FastAPI |
| Pipeline | Shared by web + CLI: [backend/pipeline/runner.py](backend/pipeline/runner.py) |
| LLM | OpenRouter via `openai` SDK; default `google/gemini-2.5-pro`. Vision always OpenRouter; text stages can use local vLLM |
| PDF | `pdf2image` + system `poppler-utils` → JPEG page images |
| Jobs | In-memory threads ([backend/jobs.py](backend/jobs.py)) — no Redis/DB |
| Deploy | Docker Compose; app on port **8099** |
## Live pipeline (authoritative)
README still describes an older 5-stage extract-then-compare loop. **Trust `runner.py`.** Actual flow:
```
PDF → images → extract → sheet index → jurisdiction
→ normalize → project intelligence (GOIDs)
→ cluster → conflict reason
→ QAQC / code / constructability
→ dedup-validate → risk → RFIs → report
```
| Runner stage | Module | Notes |
|--------------|--------|--------|
| PDF → images | `pdf_processor` | Rasterize |
| Extract assertions | `extractor` | Vision, per sheet |
| Classify sheet index | `sheet_index` | LLM |
| Jurisdiction profile | `jurisdiction` | After cover meta |
| Normalize | `normalizer` | LLM batches |
| Project intelligence | `normalizer.build_project_intelligence` | GOIDs + relationships |
| Cluster | `llm_clusterer` or `clusterer` | Default `CLUSTERER=llm` |
| Conflicts | `conflict_checker` | Per-cluster vision reason |
| QAQC / code / constructability | `qaqc_review`, `code_review`, `constructability` | Full-set / batched |
| Validate & dedup | `validator` | Merges conflict + QAQC + code + construct issues |
| Risk / RFIs | `risk`, `rfi` | Text-only |
| Report | `report` | `conflicts.json` + `report.md` (+ stage JSON dumps when `out_dir` set) |
Design notes for Stage 2/3 engines also live under `Changes/*.docx`.
## Where to change what
| Concern | File |
|---------|------|
| Prompts, vocab, conflict taxonomy | [backend/prompts.py](backend/prompts.py) |
| Env knobs | [backend/config.py](backend/config.py), [backend/.env.example](backend/.env.example) |
| HTTP API | [backend/main.py](backend/main.py) — `/health`, `/models`, `/check`, `/jobs/{id}`, `/jobs/{id}/log`, `/jobs/{id}/sheet-image/{page}` |
| CLI tuning loop | [cli/run_check.py](cli/run_check.py) |
| LLM client, cache, cost, per-run model overrides | [backend/llm.py](backend/llm.py) |
| OpenRouter vision/text model lists | [backend/models_catalog.py](backend/models_catalog.py) |
| Job registry + stdout tee log | [backend/jobs.py](backend/jobs.py), [backend/job_log.py](backend/job_log.py) |
| Stage helpers (prompt render, issue validate) | [backend/pipeline/_stage.py](backend/pipeline/_stage.py) |
| Code text corpus (Stage 7) | [backend/code_corpus/](backend/code_corpus/) |
| Hybrid local LLM helper | [scripts/setup_vllm.sh](scripts/setup_vllm.sh) |
Older prompt snapshot: `backend/prompts.py.v1`.
## Gotchas
1. **Prompt placeholders** — Use `str.replace` via `_stage.render`, never `str.format`. Prompts contain literal `{` JSON braces.
2. **Clustering** — Default is LLM (`CLUSTERER=llm`); empty LLM result falls back to deterministic. Deterministic clusters need ≥2 disciplines (or schedule-vs-plan); single-discipline “missing” gaps are a known limit.
3. **Jobs are in-memory** — Process restart clears job status; reports on disk under `backend/outputs/<job_id>/` can still be reloaded via `get_job` disk fallback. Run logs persist as `job.log` in that same folder and via `GET /jobs/{id}/log`.
4. **Dependency pin**`httpx==0.27.2` with `openai==1.51.0`. httpx ≥0.28 breaks openais `proxies=` kwarg.
5. **Code corpus licensing** — Only `ada_2010.txt` is shipped. Do not paste IBC/IFC/IECC without a license (see `backend/code_corpus/README.md`).
6. **Dual assertion schema** — Newer `{sheet, objects[]}` is mapped to legacy `{assertions[]}` with `attribute`/`value` for older stages.
7. **Grounding guard** — Extractor drops objects whose numeric claims are not in `source_text` (graphical-only objects allowed).
8. **Cost counters** — Module-global LLM cost accounting; overlapping jobs share counters. Same for stdout tee logging and per-run model overrides.
9. **Samples**`samples/*.pdf` are gitignored; drop PDFs locally for CLI runs.
10. **README drift** — Treat README for setup/CI; treat this file + `runner.py` for pipeline truth. `prompts.py` header may still say some prompts are unwired — they are wired through the runner.
11. **Two models** — Vision (`MODEL`, image stages) and text (`TEXT_MODEL`, non-image). UI exposes separate dropdowns from OpenRouters `/models` (cached ~1h). Hybrid still runs vision on OpenRouter; text dropdown also covers local name override + cloud fallback.
12. **Job log** — Pipeline `print()` output is teed into memory + `outputs/<job_id>/job.log`. Status polls include `log_tail`; completed/error jobs include full `log`.
## Quick start pointers
- Full setup: [README.md](README.md) (`docker compose up -d --build` → http://localhost:8099).
- Local CLI: `python cli/run_check.py samples/your_set.pdf --out out/your_set`.
- Prompt iteration: set `LLM_CACHE=true` in `backend/.env` so unchanged stages replay for free; clear with `rm -rf backend/.llm_cache`.
- Artifacts: `assertions.json`, `clusters.json`, per-stage JSON, `conflicts.json`, `report.md` under the chosen `out_dir` or `backend/outputs/`.
- No automated test suite; validate via CLI dumps and golden-set diffs (described in README).
## Conflict categories (taxonomy)
Defined in `backend/prompts.py`: `dimensional_disagreement`, `elevation_disagreement`, `location_mismatch`, `missing_element`, `schedule_vs_plan_mismatch`, `detail_vs_plan_mismatch`, `tag_or_reference_inconsistency`, `spatial_clash`, `note_or_spec_contradiction`.