Cross-discipline design-contradiction checker for construction drawing sets. Standalone tool broken out from Iron_Bid; a pipeline stage may later fold back into Iron_Bid. Pipeline: PDF->images -> per-sheet assertion extraction -> deterministic clustering by location -> per-cluster reasoning -> report. Includes CLI (cli/run_check.py) and web UI (backend/main.py). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3.3 KiB
Conflict Checker
Cross-discipline design contradiction detector for construction drawing sets. Built for architects to back-check a set (Arch / Struct / Mech / Elec / Plumb / FP / …) before it goes out to a GC for bid. It flags information that disagrees between disciplines — e.g. the RCP ceiling height vs the mechanical duct elevation, a door schedule count vs the floor plan, a column that lands in a corridor.
This is not the IronBid scope-ownership conflict checker (who-owns-what for bidding). That stays in IronBid; this tool is a separate, design-QA pipeline.
How it works (hybrid extract-then-compare)
PDF -> page images -> per-sheet grounded facts -> cluster by location -> reason -> report
Stage 0 Stage 1 (vision) Stage 2 (no LLM) Stage 3 Stage 4
- Stage 0
pdf_processor— PDF pages to base64 JPEGs (100 DPI, 2400px cap). - Stage 1
extractor— one vision call per sheet extracts discrete, grounded assertions (each carries verbatimsource_textand alocation_key). A grounding guard drops any assertion whose number isn't in its own source text. - Stage 2
clusterer— deterministic: groups assertions that refer to the same grid / room / tag across ≥2 disciplines (or a schedule-vs-plan within one). This keeps Stage 3 calls small and few. - Stage 3
conflict_checker— one reasoning call per cluster (with the relevant sheet images) decides whether the disciplines genuinely contradict, and classifies it. - Stage 4
report—conflicts.json+ a readablereport.md.
The model is google/gemini-2.5-pro via OpenRouter (configurable). All prompt
tuning lives in backend/prompts.py — the system prompts, the attribute vocabulary,
and the conflict taxonomy.
Setup
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt # needs system poppler-utils for pdf2image
cp backend/.env.example backend/.env # then set AI_API_KEY to your OpenRouter key
Run
CLI (the fast tuning loop — also dumps assertions.json / clusters.json for inspection):
python cli/run_check.py samples/your_set.pdf --out out/your_set
# -> out/your_set/report.md + conflicts.json
Web UI (upload + view):
uvicorn backend.main:app --reload # open http://127.0.0.1:8000
Conflict categories
dimensional_disagreement, elevation_disagreement, location_mismatch,
missing_element, schedule_vs_plan_mismatch, tag_or_reference_inconsistency,
spatial_clash, note_or_spec_contradiction.
Tuning
- Edit prompts/vocab/taxonomy in
backend/prompts.py. - Inspect
out/<set>/assertions.jsonto see what Stage 1 extracted, andout/<set>/clusters.jsonto see what got compared. Most false negatives are a clustering/extraction miss; most false positives are a Stage-3 prompt issue. - Build a golden set: hand-verify
conflicts.jsonfor a known set and diff future runs.
Known limitations (v1)
- A location appearing in only one discipline never forms a cluster, so pure "missing element" gaps aren't caught deterministically (Stage 3 still catches missing counterparts when the location is co-located).
- Stage 3 currently sends full pages, not crops. If accuracy/cost needs it, add crop-by-grid later.